如何对 CompositeCommand 进行控制反转?
How to do inversion of control on CompositeCommand?
我有以下 ViewModel,我在构造函数中实例化了 CompositeCommand:
public class ViewImportPreviewViewModel:BindableBase
{
private IEventAggregator eventAggregator; //event aggregator to enable Studio button in different ViewModel
private readonly IRegionManager regionManager; //region manager for navigation to the main menu
public CompositeCommand FinalizeImportClick{get;set;}//composite command to register multiple command for finalize import button click
public ViewImportPreviewViewModel(IRegionManager regionManager, IEventAggregator eventAggregator) //constructor
{
this.eventAggregator = eventAggregator;
this.regionManager = regionManager;
FinalizeImportClick = new CompositeCommand();
FinalizeImportClick.RegisterCommand(new DelegateCommand<string>(NavigateToMain)); //register a delegate command for finalize import button click
}
//subscriber method to the firs delegate command registered with finalize button click
private void NavigateToMain(string argument)
{
//it enables the studio button after import and sends it to the main menu view XAML
eventAggregator.GetEvent<ButtonEnableEvent>().Publish("ImportDone");
//it navigates to the main menu after import
regionManager.RequestNavigate("ScreenNavigationRegion", argument);
//publish an event for the main buttons viewmodel and then over there try to fade in main buttons
eventAggregator.GetEvent<FadeinButtonsEvent>().Publish("ImportDone");
}
}
现在想做控制反转,在class外实例化CompositeCommand,然后通过Unity Container注入,像这样:
public class ViewImportPreviewViewModel:BindableBase
{
private IEventAggregator eventAggregator; //event aggregator to enable Studio button in different ViewModel
private readonly IRegionManager regionManager; //region manager for navigation to the main menu
public CompositeCommand finalizeImportClick;//composite command to register multiple command for finalize import button click
public ViewImportPreviewViewModel(IRegionManager regionManager, IEventAggregator eventAggregator, CompositeCommand finalizeImportClick) //constructor
{
this.eventAggregator = eventAggregator;
this.regionManager = regionManager;
this.finalizeImportClick = finalizeImportClick;
finalizeImportClick.RegisterCommand(new DelegateCommand<string>(NavigateToMain)); //register a delegate command for finalize import button click
}
//subscriber method to the firs delegate command registered with finalize button click
private void NavigateToMain(string argument)
{
//it enables the studio button after import and sends it to the main menu view XAML
eventAggregator.GetEvent<ButtonEnableEvent>().Publish("ImportDone");
//it navigates to the main menu after import
regionManager.RequestNavigate("ScreenNavigationRegion", argument);
//publish an event for the main buttons viewmodel and then over there try to fade in main buttons
eventAggregator.GetEvent<FadeinButtonsEvent>().Publish("ImportDone");
}
}
然后在模块初始化时,我这样做:
CompositeCommand myCommand = new CompositeCommand();
container.RegisterInstance<CompositeCommand>(myCommand);
我没有收到任何错误,但是 NavigateToMain(string argument)
没有被调用,尽管命令已注册。
我尝试改为注册类型,但 CompositeCommand 继承了 ICommand 接口,该接口不包含 RegisterCommand
方法的定义。
实际上,CompositeCommands 是 singletons/static 是很常见的,因为多个松散耦合的模块将注册同一个 CompositeCommand。这是标准的,也是预期的。
当然,您希望这样做是为了让您的 ViewModel 可测试。您希望通过构造函数知道您的依赖项。您不想在 VM 中调用静态方法。
您要做的是创建一个像 IApplicationCommands 这样的自定义接口,并为您想要公开的每个 CompositeCommand 提供属性,然后确保将该接口注册到您的容器中。我还建议提供一个静态版本,这样您就可以将按钮数据绑定到 compositeCommands 而无需引用绑定,这非常好。
所以也许是这样的:
//Create an interface to abstract away the implementation of the static GlobalCommands class
public interface IGlobalCommands
{
CompositeCommand SaveAllCommand { get; }
}
public static class GlobalCommands
{
public static CompositeCommand SaveAllCommand = new CompositeCommand();
}
//Create a facade around the static GlobalCommands class
public class GloablCommandsFacade : IGlobalCommands
{
public CompositeCommand SaveAllCommand
{
get { return GlobalCommands.SaveAllCommand; }
}
}
并像这样注册:
//register our global commands facade with the container as the IGlobalCommands interface so that we can ask for this service in our VM constructors
// and remove the call to a static class in our VM. This keeps us testable.
Container.RegisterType<IGlobalCommands, GloablCommandsFacade>();
我有以下 ViewModel,我在构造函数中实例化了 CompositeCommand:
public class ViewImportPreviewViewModel:BindableBase
{
private IEventAggregator eventAggregator; //event aggregator to enable Studio button in different ViewModel
private readonly IRegionManager regionManager; //region manager for navigation to the main menu
public CompositeCommand FinalizeImportClick{get;set;}//composite command to register multiple command for finalize import button click
public ViewImportPreviewViewModel(IRegionManager regionManager, IEventAggregator eventAggregator) //constructor
{
this.eventAggregator = eventAggregator;
this.regionManager = regionManager;
FinalizeImportClick = new CompositeCommand();
FinalizeImportClick.RegisterCommand(new DelegateCommand<string>(NavigateToMain)); //register a delegate command for finalize import button click
}
//subscriber method to the firs delegate command registered with finalize button click
private void NavigateToMain(string argument)
{
//it enables the studio button after import and sends it to the main menu view XAML
eventAggregator.GetEvent<ButtonEnableEvent>().Publish("ImportDone");
//it navigates to the main menu after import
regionManager.RequestNavigate("ScreenNavigationRegion", argument);
//publish an event for the main buttons viewmodel and then over there try to fade in main buttons
eventAggregator.GetEvent<FadeinButtonsEvent>().Publish("ImportDone");
}
}
现在想做控制反转,在class外实例化CompositeCommand,然后通过Unity Container注入,像这样:
public class ViewImportPreviewViewModel:BindableBase
{
private IEventAggregator eventAggregator; //event aggregator to enable Studio button in different ViewModel
private readonly IRegionManager regionManager; //region manager for navigation to the main menu
public CompositeCommand finalizeImportClick;//composite command to register multiple command for finalize import button click
public ViewImportPreviewViewModel(IRegionManager regionManager, IEventAggregator eventAggregator, CompositeCommand finalizeImportClick) //constructor
{
this.eventAggregator = eventAggregator;
this.regionManager = regionManager;
this.finalizeImportClick = finalizeImportClick;
finalizeImportClick.RegisterCommand(new DelegateCommand<string>(NavigateToMain)); //register a delegate command for finalize import button click
}
//subscriber method to the firs delegate command registered with finalize button click
private void NavigateToMain(string argument)
{
//it enables the studio button after import and sends it to the main menu view XAML
eventAggregator.GetEvent<ButtonEnableEvent>().Publish("ImportDone");
//it navigates to the main menu after import
regionManager.RequestNavigate("ScreenNavigationRegion", argument);
//publish an event for the main buttons viewmodel and then over there try to fade in main buttons
eventAggregator.GetEvent<FadeinButtonsEvent>().Publish("ImportDone");
}
}
然后在模块初始化时,我这样做:
CompositeCommand myCommand = new CompositeCommand();
container.RegisterInstance<CompositeCommand>(myCommand);
我没有收到任何错误,但是 NavigateToMain(string argument)
没有被调用,尽管命令已注册。
我尝试改为注册类型,但 CompositeCommand 继承了 ICommand 接口,该接口不包含 RegisterCommand
方法的定义。
实际上,CompositeCommands 是 singletons/static 是很常见的,因为多个松散耦合的模块将注册同一个 CompositeCommand。这是标准的,也是预期的。
当然,您希望这样做是为了让您的 ViewModel 可测试。您希望通过构造函数知道您的依赖项。您不想在 VM 中调用静态方法。
您要做的是创建一个像 IApplicationCommands 这样的自定义接口,并为您想要公开的每个 CompositeCommand 提供属性,然后确保将该接口注册到您的容器中。我还建议提供一个静态版本,这样您就可以将按钮数据绑定到 compositeCommands 而无需引用绑定,这非常好。
所以也许是这样的:
//Create an interface to abstract away the implementation of the static GlobalCommands class
public interface IGlobalCommands
{
CompositeCommand SaveAllCommand { get; }
}
public static class GlobalCommands
{
public static CompositeCommand SaveAllCommand = new CompositeCommand();
}
//Create a facade around the static GlobalCommands class
public class GloablCommandsFacade : IGlobalCommands
{
public CompositeCommand SaveAllCommand
{
get { return GlobalCommands.SaveAllCommand; }
}
}
并像这样注册:
//register our global commands facade with the container as the IGlobalCommands interface so that we can ask for this service in our VM constructors
// and remove the call to a static class in our VM. This keeps us testable.
Container.RegisterType<IGlobalCommands, GloablCommandsFacade>();