2

First off I am very new to WPF MVVM and a bit confused. People say that generally in MVVM the best practice is not to have any code behind. I have found that some methods are way easier to achieve in code behind than in viewmodel (e.g MouseMove) and that led me thinking between the differences of these 2 following examples:

1) Using RelayCommand:

View

<Button Command="{Binding AlertCommand}"></Button>

ViewModel

public RelayCommand AlertCommand { get; set; }

public void Alert()
{
   MessageBox.Show("message");
}

2) calling ViewModel methods from code behind:

View

<Button PreviewMouseLeftButtonUp="OnMouseLeftButtonUp"></Button>

View code behind

private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
     var ctx = (MainViewModel) this.DataContext;
     ctx.Alert();
}

Is using code behind here wrong? What are my benefits of not using code behind?

Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
Lacir1971
  • 23
  • 1
  • 3
  • 1
    try this: https://stackoverflow.com/questions/16314828/bind-command-in-wpf-using-mvvm – sujith karivelil Jan 18 '18 at 07:34
  • One of the purposes of MVVM is to keep the UI separate from business logic. In other words, the view, in general, should not be aware of viewmodel functionality. The first example is the correct way to do it. – sparky68967 Jan 18 '18 at 07:41
  • 2
    While there are ways to bind a Command to a view event (Behaviors, ...) I think it's not all that bad to use this code behind relaying in cases where the actual viewmodel type for some XAML is well known. It is the views job to transfer some concrete events to more abstract viewmodel activity and as long as the code behind is only concerned with the views job and not starting to implement any model logic, everything should be fine. ... and I *think* this is pretty opinion based – grek40 Jan 18 '18 at 07:41
  • 2
    @sparky68967 typically it's the other way around. The viewmodel should not be aware of the view, but the view will build upon a specific viewmodel. So the really questionable part of the example code would be the `MessageBox.Show`, which is a UI thing and doesn't belong to the viewmodel ;) – grek40 Jan 18 '18 at 07:43
  • Because, the ViewModel should not be aware of the View so we expose command via ICommand to minimize the coupling between them. – Jimbot Jan 18 '18 at 07:46

2 Answers2

4

The MVVM pattern is a best practice when building UWP, WPF, and Xamarin.Forms apps. The main advantage is that you are able to decouple the logic from the presentation and potentially could present a single view model by multiple different views and could switch views without having to modify the view model significantly. This is a great advantage when building cross-platform apps with native UI, which MvvmCross framework uses to a great extent for example.

Having an empty code-behind is however definitely just an ideal, which is usually not easy and not always necessary to achieve. Sometimes you need to use code-behind for purely view-related manipulation like changing layout for different window sizes, controlling animations, etc. For such actions, code-behind is a much better fit than trying to force this somehow into the VM.

Comparing your two approaches, using the RelayCommand-based one over the direct method call is preferable, because it has less direct tie to the method itself. If you wanted, you could switch the RelayCommand instance in the VM for a different implementation (calling different method) at runtime, and thanks to binding the button could now perform a different action. This can be used in editor-like apps where some tools may have different functionality based on current context the app is in.

Also, for controls which do not offer a Command you can use EventTrigger hand in hand with InvokeCommandAction (both defined withing Expression Blend SDK) which will allow you to "convert" an event to a command call, even with your defined transformation of EventArgs.

Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
1

Both are valid methods. The first is preferable if possible. I generally use the second method on events where no command binding is available. The notion of "absolutely no code-behind in MVVM" is debatable. Any code that belongs directly to the view (and is not business logic) and is not reusable in a VM can be put in the code-behind, such as wiring up events in the second example.

Lennart
  • 9,657
  • 16
  • 68
  • 84