其實探索Command Pattern,並發現它非常有趣。我正在編寫MVVM Architectural Pattern之後的WPF Windows應用程序。如何注入動作進入使用Ninject的命令?
我已經開始與這些帖子裏面講解的基礎知識。
- Basic MVVM and ICommand usuage example
- Simplify Distributed System Design Using the Command Pattern, MSMQ, and .NET
現在,我能打破用戶操作爲命令,我想這可能是巨大的,注入我想要的命令。我注意到,該命令被發現到視圖模型第一引用的文章中,所以我想這將是巨大的,如果我能沿着Ninject使用它們,實際使用的綁定看起來像下面注入我的命令到我的視圖模型:
kernel
.Bind<ICommand>()
.To<RelayCommand>()
.WithConstructorArgument("execute", new Action<object>(???));
但是,那麼,在這裏放什麼???。預期的答案是一種方法。大!我只需要一種方法放在那裏。
因爲第一篇文章只是初始化視圖模型構造函數中的命令,很容易地說應在命令執行調用執行什麼方法。
但是從CompositionRoot內?這不是放置一種方法的地方,它會做任何事情,而不是通過你使用的任何DI容器將類型綁定在一起!
所以現在我已經遇到了使用Ninject擴展的攔截器模式。這看起來可以滿足我的要求,如果我可以這樣說,這裏有點混亂。不是說文章混亂,他們不是。我很困惑!
此外,還有來自BatteryBackupUnit這個答案誰總是把偉大的答案。
但現在,我不能看到如何把它粘所有在一起!謙虛,我迷路了。
所以這裏是我的代碼到目前爲止。
RelayCommand
public class RelayCommand : ICommand {
public RelayCommand(Action<object> methodToExecute, Predicate<object> canExecute) {
if(methodToExecute == null)
throw new ArgumentNullException("methodToExecute");
if(canExecute == null)
throw new ArgumentNullException("canExecute");
this.canExecute = canExecute;
this.methodToExecute = methodToExecute;
}
public bool CanExecute(object parameter) {
return canExecute != null && canExecute(parameter);
}
public event EventHandler CanExecuteChanged {
add {
CommandManager.RequerySuggested += value;
canExecuteChanged += value;
}
remove {
CommandManager.RequerySuggested -= value;
canExecuteChanged -= value;
}
}
public static bool DefaultCanExecute(object parameter) { return true; }
public void Execute(object parameter) { methodToExecute(parameter); }
public void OnCanExecuteChanged() {
var handler = canExecuteChanged;
if(handler != null) handler(this, EventArgs.Empty);
}
public void Destroy() {
canExecute = _ => false;
methodToExecute = _ => { return; };
}
private Predicate<object> canExecute;
private Action<object> methodToExecute;
private event EventHandler canExecuteChanged;
}
CategoriesManagementViewModel
public class CategoriesManagementViewModel : ViewModel<IList<Category>> {
public CategoriesManagementViewModel(IList<Category> categories
, ICommand changeCommand
, ICommand createCommand
, ICommand deleteCommand) : base(categories) {
if(changeCommand == null)
throw new ArgumentNullException("changeCommand");
if(createCommand == null)
throw new ArgumentNullException("createCommand");
if(deleteCommand == null)
throw new ArgumentNullException("deleteCommand");
this.changeCommand = changeCommand;
this.createCommand = createCommand;
this.deleteCommand = deleteCommand;
}
public ICommand ChangeCommand { get { return changeCommand; } }
public ICommand CreateCommand { get { return createCommand; } }
public ICommand DeleteCommand { get { return deleteCommand; } }
private readonly ICommand changeCommand;
private readonly ICommand createCommand;
private readonly ICommand deleteCommand;
}
我不知道,會使用Property Injection,雖然我傾向於不使用它它會更好?
比方說,我有CategoriesManagementView
調用另一個窗口,比如說CreateCategoryView.Show()
,然後CreateCategoryView接管直到用戶回到管理窗口。
創建命令然後需要調用CreateCategoryView.Show(),這是我從CompositionRoot內部嘗試。
CompositionRoot
public class CompositionRoot {
public CompositionRoot(IKernel kernel) {
if(kernel == null) throw new ArgumentNullException("kernel");
this.kernel = kernel;
}
//
// Unrelated code suppressed for simplicity sake.
//
public IKernel ComposeObjectGraph() {
BindCommandsByConvention();
return kernel;
}
private void BindCommandsByConvention() {
//
// This is where I'm lost. I can't see any way to tell Ninject
// what I want it to inject into my RelayCommand class constructor.
//
kernel
.Bind<ICommand>()
.To<RelayCommand>()
.WithConstructorArgument("methodToExecute", new Action<object>());
//
// I have also tried:
//
kernel
.Bind<ICommand>()
.ToConstructor(ctx =>
new RelayCommand(new Action<object>(
ctx.Context.Kernel
.Get<ICreateCategoryView>().ShowSelf()), true);
//
// And this would complain that there is no implicit conversion
// between void and Action and so forth.
//
}
private readonly IKernel kernel;
}
也許我是過於複雜的東西,通常是當一個迷糊什麼happends。 =)
我只是想知道Ninject截取擴展是否可以成爲這項工作的正確工具,以及如何有效地使用它?
我認爲注射動作是錯誤的做法。虛擬機中的命令應該在命令方法內使用注入服務。 – vidalsasoon 2015-03-13 14:55:41
這是否意味着,例如,我的'createCommand'參數是一個類,而該類又取決於我的'CreateCategoryView',然後ICommand.Execute會簡單地調用依賴的'Show()'方法? – 2015-03-13 15:07:48
你只需要在虛擬機中聲明命令並綁定到它。例如:public DelegateCommand SignInCommand {get;私人設置; }。在你的實現中,引用你的注入服務(你的API,AuthenticationService等) – vidalsasoon 2015-03-13 15:42:12