WPF: the relation of commands and ViewModels in MVVM

I am trying to call the same command from two different presentation models, but I got stuck during their design (both for command models and for viewing).

First I created the ViewModel1 view model class:

 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... ... } 

And the class of the ProcessMyString command:

 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(); } } 

Then I created the second class of the ViewModel2 view model, but when I realized that this view model would also need to use the same command , the command constructor

 public ProcessMyString(ViewModel1 viewModel) 

will not work because it accepts the ViewModel1 parameter, and I need to be able to pass both view models. Then I decided to create a ViewModelBase class and make both view models from it. Of course, I also modified the command constructor:

 // Constructor parameter is now ViewModelBase public ProcessMyString(ViewModelBase viewModel) 

But this meant that the Execute(object parameter) command method is now called the method from ViewModelBase . This is a good application, because ViewModel calls ProcessMyString() , should only be reserved for the ViewModel1 and ViewModel2 classes. If I had a ViewModel3 class, I would not want it to call ProcessMyString() , and if I do not extend it from ViewModelBase , that would be fine.

But what happens if I need a command that is split between ViewModel2 and ViewModel3 ?

The question of summation: how do I organize my teams and view models so that presentation motives can use the same commands?

+4
source share
2 answers

I will post this answer on the assumption that the ProcessMyString class is not needed and should be replaced by a common command.

First of all, download the MVVM Light library. After that, unzip it somewhere and add a link to this library:

(library folder) \ Mvvm Light Toolkit \ Binaries \ WPF4 \ GalaSoft.MvvmLight.WPF4.dll

It contains the RelayCommand class, which is what you need.

First create a base class that contains your command:

 public abstract class ProcessStringViewModel : DependencyObject { // The command property public RelayCommand ProcessMyStringCommand { get; set; } } 

I would remove the inheritance from the DependencyObject class, but maybe you are using it somehow, so let it be.

The ViewModel1 class can be rewritten as follows:

 public class ViewModel1 : ProcessStringViewModel { public ViewModel1() { // Command gets instantiated this.ProcessMyStringCommand = new RelayCommand(() => this.ProcessMyString()); } internal void ProcessMyString() { } } 

The ViewModel2 class may call another function, but the command is the same:

 public class ViewModel2 : ProcessStringViewModel { public ViewModel2() { this.ProcessMyStringCommand = new RelayCommand(SomeOtherFunction); } private void SomeOtherFunction() { MessageBox.Show("Call of some function"); } } 

If you decide not to use the base class and inheritance, you can delete the base class, copy it to each derived class and work.

+1
source

First of all, as a personal preference, I try to minimize the amount of inheritance that I use with the ViewModel. Sophisticated user interface code in non-trivial applications can be complicated enough to follow anyone other than the original author, the last thing you want to do is complicate it by including a complex object model.

The beauty of WPF using the ICommand interface is that you should be able to use a more compositional approach rather than an inheritance model, and use the interface to share common properties.

Here is just a quick example of how I can approach this scenario:

 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. } 
+6
source

Source: https://habr.com/ru/post/1347353/


All Articles