如果您正在执行MVVM并使用命令,您将经常看到ViewModel上的ICommand属性由私有RelayCommand或DelegateCommand字段支持,就像MSDN上最初的MVVM文章中的这个示例
RelayCommand _saveCommand;
public ICommand SaveCommand
{
get
{
if (_saveCommand == null)
{
_saveCommand = new RelayCommand(param => this.Save(),
param => this.CanSave );
}
return _saveCommand;
}
}
但是,这非常混乱,并且使设置新命令变得相当单调乏味(我与一些经验丰富的WinForms开发人员一起工作,他们不喜欢输入这些内容)。所以我想把它简化一下,深入研究一下。我在get{}代码块的第一行设置了一个断点,发现它只在我的应用程序第一次加载时被命中--以后我可以发出任意多个命令,而这个断点永远不会被命中--所以我想简化这一点,以便从我的ViewModels中去除一些杂乱的东西,并注意到以下代码的工作方式是相同的:
public ICommand SaveCommand
{
get
{
return new RelayCommand(param => this.Save(), param => this.CanSave );
}
}
但是,我对C#或垃圾收集器的了解还不够,不知道这是否会导致问题,比如在某些情况下会生成过多的垃圾。这会不会有问题呢?
发布于 2010-06-25 01:24:38
我发现,如果您有多个调用相同命令的控件,则需要使用MSDN中的原始方法,否则每个控件都将更新其自己的RelayCommand。我没有意识到这一点,因为我的应用程序每个命令只有一个控件。
因此,为了简化ViewModels中的代码,我将创建一个命令包装类来存储(并延迟实例化)所有的RelayCommands,并将其抛出到我的ViewModelBase类中。这样,用户就不需要直接实例化RelayCommand或DelegateCommand对象,也不需要了解它们的任何信息:
/// <summary>
/// Wrapper for command objects, created for convenience to simplify ViewModel code
/// </summary>
/// <author>Ben Schoepke</author>
public class CommandWrapper
{
private readonly List<DelegateCommand<object>> _commands; // cache all commands as needed
/// <summary>
/// </summary>
public CommandWrapper()
{
_commands = new List<DelegateCommand<object>>();
}
/// <summary>
/// Returns the ICommand object that contains the given delegates
/// </summary>
/// <param name="executeMethod">Defines the method to be called when the command is invoked</param>
/// <param name="canExecuteMethod">Defines the method that determines whether the command can execute in its current state.
/// Pass null if the command should always be executed.</param>
/// <returns>The ICommand object that contains the given delegates</returns>
/// <author>Ben Schoepke</author>
public ICommand GetCommand(Action<object> executeMethod, Predicate<object> canExecuteMethod)
{
// Search for command in list of commands
var command = (_commands.Where(
cachedCommand => cachedCommand.ExecuteMethod.Equals(executeMethod) &&
cachedCommand.CanExecuteMethod.Equals(canExecuteMethod)))
.FirstOrDefault();
// If command is found, return it
if (command != null)
{
return command;
}
// If command is not found, add it to the list
command = new DelegateCommand<object>(executeMethod, canExecuteMethod);
_commands.Add(command);
return command;
}
}
这个类也是由ViewModelBase类延迟实例化的,所以没有任何命令的ViewModels将避免额外的分配。
发布于 2010-06-25 17:31:55
这完全等同于您提供了一个计算某个常量值的属性。您可以为get-method的每次调用计算它,也可以在第一次调用时创建它,然后缓存它,以便为以后的调用返回缓存的值。因此,如果getter最多被调用一次,它就没有任何区别,如果经常调用它,您将损失一些(不是很多)性能,但您不会遇到真正的麻烦。
我个人喜欢这样缩写MSDN-way:
RelayCommand _saveCommand;
public ICommand SaveCommand
{
get
{
return _saveCommand ?? (_saveCommand = new RelayCommand(param => this.Save(),
param => this.CanSave ));
}
}
发布于 2010-06-26 19:14:40
你为什么不直接写:
private readonly RelayCommand _saveCommand = new RelayCommand(param => this.Save(),
param => this.CanSave );;
public ICommand SaveCommand { get { return _saveCommand; } }
https://stackoverflow.com/questions/3112203
复制相似问题