![](/img/trans.png)
[英]WPF - Model method as Execute event for a command (NO RelayCommand or DelegateCommand)
[英]Simplifying RelayCommand/DelegateCommand in WPF MVVM ViewModels
如果您正在使用MVVM並使用命令,您通常會在ViewModel上看到由私有RelayCommand或DelegateCommand字段支持的ICommand屬性,例如MSDN上原始MVVM文章中的此示例:
RelayCommand _saveCommand;
public ICommand SaveCommand
{
get
{
if (_saveCommand == null)
{
_saveCommand = new RelayCommand(param => this.Save(),
param => this.CanSave );
}
return _saveCommand;
}
}
然而,這很混亂,並且使得設置新命令相當繁瑣(我與一些資深WinForms開發人員一起工作,他們對所有這些打字都不滿意)。 所以我想簡化它並挖掘一下。 我在get {}塊的第一行設置了一個斷點,看到它只是在我的應用程序第一次加載時才被擊中 - 我可以隨后發出盡可能多的命令,這個斷點永遠不會被擊中 - 所以我想要簡化這個以從我的ViewModel中刪除一些混亂,並注意到以下代碼的工作方式相同:
public ICommand SaveCommand
{
get
{
return new RelayCommand(param => this.Save(), param => this.CanSave );
}
}
但是,我不太了解C#或垃圾收集器,知道這是否會導致問題,例如在某些情況下產生過多的垃圾。 這會造成任何問題嗎?
這與您提供計算某個常量值的 - - 整數 - 屬性完全相同。 您可以為get-method上的每個調用計算它,也可以在第一次調用時創建它,然后對其進行緩存,以便為以后的調用返回緩存的值。 因此,如果最多只調用一次getter,它確實沒有任何區別,如果經常調用它,你將失去一些(不多)性能,但你不會遇到真正的麻煩。
我個人喜歡縮寫MSDN這樣的方式:
RelayCommand _saveCommand;
public ICommand SaveCommand
{
get
{
return _saveCommand ?? (_saveCommand = new RelayCommand(param => this.Save(),
param => this.CanSave ));
}
}
我發現如果你有多個控件調用相同的命令,你需要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類延遲實例化,因此沒有任何命令的ViewModel將避免額外的分配。
我做的一件事是讓Visual Studio為我打字。 我剛剛創建了一個代碼片段,允許我通過輸入創建一個RelayCommand
rc 選項卡保存回車
rc是代碼片段快捷方式選項卡,可以加載您鍵入的文本,並創建所有其他措辭。
一旦你看到一個代碼片段並創建自己的代碼片段,你將永遠不會回去:)
有關創建代碼段的詳細信息,請訪問: http : //msdn.microsoft.com/en-us/library/ms165394.aspx
當您在viewmodel上公開ICommand屬性並且它沒有支持字段時,這是可以的,只要您只綁定一次該字段即可。
CommandWrapper的GetCommand方法將返回命令(如果已創建)。
你為什么不寫作:
private readonly RelayCommand _saveCommand = new RelayCommand(param => this.Save(),
param => this.CanSave );;
public ICommand SaveCommand { get { return _saveCommand; } }
當您在viewmodel上公開ICommand屬性並且它沒有支持字段時,這是可以的,只要您只綁定一次該字段即可。 基本上,當表單加載並執行初始綁定時,這是它唯一一次訪問命令的get屬性。
很多時候你只會一次綁定一個命令。
如果將同一命令綁定到多個控件,則需要支持字段。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.