Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 具有ViewModel依赖项的ICommand_C#_Wpf_Mvvm_Icommand - Fatal编程技术网

C# 具有ViewModel依赖项的ICommand

C# 具有ViewModel依赖项的ICommand,c#,wpf,mvvm,icommand,C#,Wpf,Mvvm,Icommand,当我使用ICommand时,我正在寻找一种模式,以在我的应用程序中保持坚实的原则。基本上,我的问题是命令执行与视图模型有依赖关系,但同时视图模型与命令有依赖关系(我通过构造函数注入它们)。我希望仅保留带有属性的viewmodel,因此这是我当前实现的一个示例: public class MyViewModel : INotifyPropertyChanged { public ICommand MyCommand { get; private set; } public strin

当我使用ICommand时,我正在寻找一种模式,以在我的应用程序中保持坚实的原则。基本上,我的问题是命令执行与视图模型有依赖关系,但同时视图模型与命令有依赖关系(我通过构造函数注入它们)。我希望仅保留带有属性的viewmodel,因此这是我当前实现的一个示例:

public class MyViewModel : INotifyPropertyChanged
{
   public ICommand MyCommand { get; private set; }

   public string Message { get; set; } // PropertyChanged ommited

   public MyViewModel()
   {            
   }

   public void SetCommand(ICommand myCommand)
   {
       this.MyCommand = myCommand;
   }

   ....
}

internal interface IMyViewModelCommandManager
{
    void ExectueMyCommand();
}

internal class MyViewModelCommandManager : IMyViewModelCommandManager
{
   private readOnly MyViewModel myViewModel;

   public MyViewModelCommandManager(MyViewModel myViewModel)
   {
       this.myViewModel = myViewModel;
   }

   public ExectueMyCommand()
   {
        MessageBox.Show(this.myViewModel.Message);
   }
}

internal class MyViewModelFactory: IMyViewModelFactory
{
   private readonly IContainerWrapper container;

   public MyViewModelFactory(IContainerWrapper container)
   {
      this.container = container;
   }

   public MyViewModel Create()
   {
       MyViewModel viewModel = new MyViewModel();

       IMyViewmodelCommandManager manager = this.container.Resolve<IMyViewmodelCommandManager>(new ResolverOverride[] { new ParameterOverride("viewModel", viewModel) });

       ICommand myCommand = new DelegateCommand(manager.ExecuteMyCommand);

       viewModel.SetCommand(myCommand);

       return viewModel;
   }
}
公共类MyViewModel:INotifyPropertyChanged
{
public ICommand MyCommand{get;private set;}
公共字符串消息{get;set;}//PropertyChanged-ommited
公共MyViewModel()
{            
}
public void SetCommand(ICommand myCommand)
{
this.MyCommand=MyCommand;
}
....
}
内部接口IMyViewModelCommandManager
{
void ExectueMyCommand();
}
内部类MyViewModelCommandManager:IMyViewModelCommandManager
{
私有只读MyViewModel MyViewModel;
公共MyViewModelCommandManager(MyViewModel MyViewModel)
{
this.myViewModel=myViewModel;
}
公共行政命令()
{
Show(this.myViewModel.Message);
}
}
内部类MyViewModelFactory:IMyViewModelFactory
{
专用只读IContainerWrapper容器;
公共MyViewModelFactory(IContainerWrapper容器)
{
this.container=容器;
}
公共MyViewModel创建()
{
MyViewModel viewModel=新的MyViewModel();
IMyViewmodelCommandManager=this.container.Resolve(new ResolverOverride[]{new ParameterOverride(“viewModel”,viewModel)});
ICommand myCommand=新的DelegateCommand(manager.ExecuteMyCommand);
viewModel.SetCommand(myCommand);
返回视图模型;
}
}
因此,为了避免使用SetCommand方法。我已经想到了两种解决方案,但我不知道它们是否优雅

第一种方法是将viewmodel依赖项从构造函数移动到方法,以这种方式更新代码:

public class MyViewModel : INotifyPropertyChanged
{
   public ICommand MyCommand { get; private set; }

   public string Message { get; set; } // PropertyChanged ommited

   public MyViewModel(ICommand myCommand)
   {
       this.MyCommand = myCommand;            
   }

   ....
}

internal interface IMyViewModelCommandManager
{
    void ExectueMyCommand(MyViewModel viewModel);
}

internal class MyViewModelCommandManager : IMyViewModelCommandManager
{
   public MyViewModelCommandManager()
   {
       ....
   }

   public ExectueMyCommand(MyViewModel viewModel)
   {
        MessageBox.Show(myViewModel.Message);
   }
}

internal class MyViewModelFactory: IMyViewModelFactory
{
   private readonly IContainerWrapper container;

   public MyViewModelFactory(IContainerWrapper container)
   {
      this.container = container;
   }

   public MyViewModel Create()
   {
       IMyViewmodelCommandManager manager = this.container.Resolve<IMyViewmodelCommandManager>(..);

       ICommand myCommand = new DelegateCommand<MyViewModel>(manager.ExecuteMyCommand);

       MyViewModel viewModel = new MyViewModel(myCommand);
       return viewModel;
   }
}
公共类MyViewModel:INotifyPropertyChanged
{
public ICommand MyCommand{get;private set;}
公共字符串消息{get;set;}//PropertyChanged-ommited
公共MyViewModel(ICommand和myCommand)
{
this.MyCommand=MyCommand;
}
....
}
内部接口IMyViewModelCommandManager
{
void ExectueMyCommand(MyViewModel-viewModel);
}
内部类MyViewModelCommandManager:IMyViewModelCommandManager
{
公共MyViewModelCommandManager()
{
....
}
公共执行命令(MyViewModel viewModel)
{
MessageBox.Show(myViewModel.Message);
}
}
内部类MyViewModelFactory:IMyViewModelFactory
{
专用只读IContainerWrapper容器;
公共MyViewModelFactory(IContainerWrapper容器)
{
this.container=容器;
}
公共MyViewModel创建()
{
IMyViewmodelCommandManager=this.container.Resolve(..);
ICommand myCommand=新的DelegateCommand(manager.ExecuteMyCommand);
MyViewModel viewModel=新的MyViewModel(myCommand);
返回视图模型;
}
}
当然,xaml代码将使用CommandParameter:

<Button Content="Show Message" Command="{Binding MyCommand}" CommandParameter="{Binding .}" />

我认为的另一个解决方案是使用一个技巧创建viewModel的包装器,commandManager与包装器而不是viewModel具有依赖关系:

internal class MyViewModelCommandContext
   {
      public MyViewModel ViewModel { get; set; }
   }

   public class MyViewModel : INotifyPropertyChanged
    {
       public ICommand MyCommand { get; private set; }

       public string Message { get; set; } // PropertyChanged ommited

       public MyViewModel(ICommand myCommand)
       {
           this.MyCommand = myCommand;            
       }

       ....
    }

    internal interface IMyViewModelCommandManager
    {
        void ExectueMyCommand();
    }

    internal class MyViewModelCommandManager : IMyViewModelCommandManager
    {
       private readonly MyViewModelCommandContext context;

       public MyViewModelCommandManager(MyViewModelCommandContext context)
       {
           this.context = context;
           ....
       }

       public ExectueMyCommand()
       {
            MessageBox.Show(this.context.myViewModel.Message);
       }
    }

    internal class MyViewModelFactory: IMyViewModelFactory
    {
       private readonly IContainerWrapper container;

       public MyViewModelFactory(IContainerWrapper container)
       {
          this.container = container;
       }

       public MyViewModel Create()
       {
           MyViewModelCommandContext context = new MyViewModelCommandContext();

           IMyViewmodelCommandManager manager = this.container.Resolve<IMyViewmodelCommandManager>(new ResolverOverride[] { new ParameterOverride("context", context) });

           ICommand myCommand = new DelegateCommand(manager.ExecuteMyCommand);

           MyViewModel viewModel = new MyViewModel(myCommand);
           context.ViewModel = viewModel;
           return viewModel;
       }
    }
内部类MyViewModelCommandContext
{
公共MyViewModel视图模型{get;set;}
}
公共类MyViewModel:INotifyPropertyChanged
{
public ICommand MyCommand{get;private set;}
公共字符串消息{get;set;}//PropertyChanged-ommited
公共MyViewModel(ICommand和myCommand)
{
this.MyCommand=MyCommand;
}
....
}
内部接口IMyViewModelCommandManager
{
void ExectueMyCommand();
}
内部类MyViewModelCommandManager:IMyViewModelCommandManager
{
私有只读MyViewModelCommandContext上下文;
公共MyViewModelCommandManager(MyViewModelCommandContext上下文)
{
this.context=上下文;
....
}
公共行政命令()
{
Show(this.context.myViewModel.Message);
}
}
内部类MyViewModelFactory:IMyViewModelFactory
{
专用只读IContainerWrapper容器;
公共MyViewModelFactory(IContainerWrapper容器)
{
this.container=容器;
}
公共MyViewModel创建()
{
MyViewModelCommandContext=新建MyViewModelCommandContext();
IMyViewmodelCommandManager=this.container.Resolve(new ResolverOverride[]{new ParameterOverride(“context”,context)});
ICommand myCommand=新的DelegateCommand(manager.ExecuteMyCommand);
MyViewModel viewModel=新的MyViewModel(myCommand);
context.ViewModel=ViewModel;
返回视图模型;
}
}

我认为第一个是解决这个问题的最好办法,你认为什么是最好的办法。你会应用另一种解决方案吗?

两种解决方案都过于复杂。固体是伟大的,亲吻是更好的

您的
MyViewModelCommandManager
当前直接耦合到
MyViewModel
,因为它需要后者的
消息,所以将它们分开有什么好处?为什么不直接在
MyViewModel
中实现该命令呢

如果这需要在
MyViewModel
中注入太多依赖项,那么请考虑实际需要该命令做什么,并抽象掉不需要的所有其他内容

  • 该命令将显示一条消息
  • 该消息由MyViewModel保存
  • 您希望在MyViewModel之外显示消息(可能其他ViewModel也需要显示消息,您希望重用代码?)
  • 所以你真正需要的
    internal class MyCommandContext
    {
        public string Message { get; set; }
    }
    
    public class MyViewModel : INotifyPropertyChanged
    {
        public ICommand MyCommand { get; private set; }
    
        public string Message { get; set; } // PropertyChanged ommited
    
        public string OtherProperty { get; set; }
    
        public ObservableCollection<MyChildViewModel> Childs { get; set; }
    
        public MyViewModel(ICommand myCommand)
        {
            this.MyCommand = myCommand;            
        }
    
           ....
    }
    
    internal interface IMyViewModelCommandManager
    {
        void ExectueMyCommand();
    }
    
    internal class MyViewModelCommandManager : IMyViewModelCommandManager
    {
       private readonly MyCommandContext context;
    
       public MyViewModelCommandManager(MyViewModelCommandContext context)
       {
           this.context = context;
           ....
       }
    
       public ExectueMyCommand()
       {
            MessageBox.Show(this.context.Message);
       }
    }
    
    internal interface IMyViewModelCommandSynchronizer
    {
        void Initialize();
    }
    
    internal class MyViewModelCommandSynchronizer : IMyViewModelCommandSynchronizer, IDisposable
    {
         private readOnly MyViewModel viewModel;
         private readOnly MyCommandContext context;
    
         MyViewModelCommandSynchronizer(MyViewModel viewModel, MyCommandContext context)
         {
             this.viewModel = viewModel;
             this.context = context;
         }
    
         public void Initialize()
         {
             this.viewModel.PropertyChanged += this.ViewModelOnPropertyChanged;
         }
    
        private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Message")
            {
                 this.context.Message = this.viewModel.Message;
            }
        }
    
        // Dispose code to deattach the events.
    }
    
    internal class MyViewModelFactory: IMyViewModelFactory
    {
       private readonly IContainerWrapper container;
    
       public MyViewModelFactory(IContainerWrapper container)
       {
           this.container = container;
       }
    
       public MyViewModel Create()
       {
           MyCommandContext context = new MyCommandContext();
    
           IMyViewmodelCommandManager manager = this.container.Resolve<IMyViewmodelCommandManager>(new ResolverOverride[] { new ParameterOverride("context", context) });
    
           ICommand myCommand = new DelegateCommand(manager.ExecuteMyCommand);
    
           MyViewModel viewModel = new MyViewModel(myCommand);
    
           IMyViewModelCommandSynchronizer synchronizer = this.container.Resolve<IMyViewmodelCommandManager>(new ResolverOverride[] { new ParameterOverride("context", context), new ParameterOverride("viewModel", viewModel) });
    
           synchronizer.Initialize();
    
           return viewModel;
       }
    }