如何注入动作进入使用Ninject的命令?
其实探索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截取扩展是否可以成为这项工作的正确工具,以及如何有效地使用它?
我创建了一个与注入服务交互的命令的简单示例。可能因为我从记忆中而不能编译。也许这可以帮助你。
public class TestViewModel
{
private readonly IAuthenticationService _authenticationService;
public DelegateCommand SignInCommand { get; private set; }
public TestViewModel(IAuthenticationService authenticationService) //Inject auth service
{
_authenticationService = authenticationService
SignInCommand = new DelegateCommand(OnSignInRequest)
}
private void OnSignInRequest(Action<bool> isSuccessCallback)
{
var isSuccess = _authenticationService.SignIn();
isSuccessCallback(isSuccess);
}
}
}
我认为注射动作是错误的做法。虚拟机中的命令应该在命令方法内使用注入服务。 – 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