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