如何对 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>();