我试图从两个不同的视图模型调用相同的命令,但我在设计它们时遇到困难(命令和视图模型)。
首先,我创建了一个ViewModel1
视图模型类:
public class ViewModel1 : DependencyObject
{
...
// The command property
public ProcessMyString ProcessMyStringCommand { get; set; }
public ViewModel1()
{
// Command gets instantiated
this.ProcessMyStringCommand = new ProcessMyString(this);
}
internal void ProcessMyString()
{
// This is where the actual processing method is called
// somewhere from the business logic...
...
}
ProcessMyString
命令类:
public class ProcessMyString : ICommand
{
private ViewModel1 viewModel;
public ProcessMyString(ViewModel1 viewModel)
{
this.viewModel = viewModel;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
viewModel.ProcessMyString();
}
}
然后,我创建了第二个视图模型类ViewModel2
,但是当我意识到这个视图模型也需要使用相同的命令时,命令的构造函数
public ProcessMyString(ViewModel1 viewModel)
不起作用,因为它需要ViewModel1
参数,我需要能够传递两个视图模型。然后,我决定创建ViewModelBase
类,并使两个视图模型从中扩展。我当然修改了命令的构造函数:
// Constructor's parameter is now ViewModelBase
public ProcessMyString(ViewModelBase viewModel)
但这意味着命令的方法Execute(object parameter)
现在从ViewModelBase
调用了一个方法。这不是一个好的appproach,因为ViewModel对ProcessMyString()
的调用只应为ViewModel1
和ViewModel2
类保留。如果我上课ViewModel3
我就不希望它调用ProcessMyString()
,如果我不从ViewModelBase
扩展它就可以了。
但如果我需要在ViewModel2
和ViewModel3
之间共享的命令会怎样?
总结问题是:我应该如何组织命令和查看模型,以便能够使视图模型共享相同的命令?
答案 0 :(得分:7)
首先,作为个人偏好,我倾向于最小化我使用ViewModel的继承量。除了原始作者之外,非平凡应用程序中的复杂UI代码可能非常棘手,除了原作者之外,最后一件事就是通过包含复杂的对象模型来使其变得更难。
使用ICommand接口的WPF的美妙之处在于,您应该能够使用更多的组合方法,而不是继承模型,并使用接口来共享公共属性。
这里只是我可以快速了解这种情况:
public class ProcessStringCommand : ICommand
{
private readonly IProcessStringViewModel m_viewModel;
public ProcessStringCommand(IProcessStringViewModel vm)
{
m_viewModel = vm;
}
public void Execute(object param)
{
ProcessString(m_viewModel.ProcessString);
}
public bool CanExecute(object param)
{
return true;
}
private void ProcessString(string processString)
{
// Put logic here
}
}
public interface IProcessStringViewModel
{
public string ProcessString { get; }
}
public class ViewModel1 : ViewModelBase, IProcessStringViewModel
{
private readonly ICommand m_command;
private readonly string m_processString;
public ViewModel1()
{
m_command = new ProcessStringCommand(this);
}
public string ProcessString
{
get { return m_processString; }
}
public ICommand ProcessStringCommand
{
get { return m_command; }
}
}
public class ViewModel2 : ViewModelBase, IProcessStringViewModel
{
private readonly ICommand m_command;
private readonly string m_processString;
public ViewModel2()
{
m_command = new ProcessStringCommand(this);
}
public string ProcessString
{
get { return m_processString; }
}
public ICommand ProcessStringCommand
{
get { return m_command; }
}
}
public class ViewModel3 : ViewModelBase
{
// Whatever you need here.
}
答案 1 :(得分:1)
我将发布这个答案,假设ProcessMyString
类是不必要的,应该用通用命令替换。
首先,下载库MVVM Light。 之后将其解压缩到某处并添加对此库的引用:
(带库的文件夹)\ Mvvm Light 工具包\二进制\ WPF4 \ GalaSoft.MvvmLight.WPF4.dll
它包含RelayCommand
类,这就是你需要的。
首先创建一个包含命令的基类:
public abstract class ProcessStringViewModel : DependencyObject
{
// The command property
public RelayCommand ProcessMyStringCommand { get; set; }
}
我会从DependencyObject
类中删除继承,但也许你会以某种方式使用它,所以就这样吧。
可以用这种方式重写ViewModel1
类:
public class ViewModel1 : ProcessStringViewModel
{
public ViewModel1()
{
// Command gets instantiated
this.ProcessMyStringCommand = new RelayCommand(() => this.ProcessMyString());
}
internal void ProcessMyString()
{
}
}
ViewModel2
类可以调用不同的函数,但命令是相同的:
public class ViewModel2 : ProcessStringViewModel
{
public ViewModel2()
{
this.ProcessMyStringCommand = new RelayCommand(SomeOtherFunction);
}
private void SomeOtherFunction()
{
MessageBox.Show("Call of some function");
}
}
如果您决定不使用基类和继承 - 您可以删除基类,将属性复制到每个派生类,它将起作用。