0

I think it is mostly architecture question. I have a View and my ViewModel class set as DataContext. Now, I have a click event binded to View by ICommand.

So what we have, user click button in View I get this event in ViewModel and I would like to open Dialog.

As for me Dialog it is associated with a View and View should open this dialog, so it is means that this method

public void OpenDialog(){...}

should reside in View and I should someway to call this method from my ViewModel where I got click event.

Questions is:

  • If I understand this MVVM WPF approach in a right way
  • How to make this connection (best practices)
Sirop4ik
  • 4,543
  • 2
  • 54
  • 121
  • Ask yourself the question: If a user clicks a button in a *view*, why do you get the event in the *viewmodel*? Why not process that button click in the view where it belongs? (it looks like you've already followed this thought pattern) [Here is an older answer](https://stackoverflow.com/a/40777396/109702) with some helpful reference links. – slugster Feb 13 '20 at 11:35
  • @slugster as far as I understood this is WPF binding implementation, you need to create a view + viewModel and bind all properties and click events from viewModel to View, not right? Do you mean that I need to bind only properties, but buttons clicks should be in View, right? – Sirop4ik Feb 13 '20 at 11:58
  • Correct - you absolutely should handle view related events in the view, even if that means writing code behind (you can still bind the event handlers if you want, but they belong in the view). Putting the handlers in the viewmodel is a mistake made by so many people it's almost become normal, but even when using abstraction it's still incurring a dependency from the VM(s) back to the view(s). – slugster Feb 13 '20 at 12:03
  • @slugster ok, so it is means also that `View` know about `ViewModel`, right? Like user make a click `View` handle this event and if I need to execute some logic, now I call my `ViewModel` for logic execution and if at the end of process I need to open (for example) dialog I call `Func` like in @Rob answer, if I understood correctly the flow? – Sirop4ik Feb 13 '20 at 12:15
  • The view does know that it has a viewmodel, it just doesn't need to know a lot about it (my views always accessed the VMs via an interface). Your view can trigger an action in the viewmodel in response to a UI related event, for example if you open a dialog so that the user can edit some details then when they hit the OK button the main view gets control back, at this point it can call a `Save()` type of method on the VM (which will then invoke any business or storage logic in a service). – slugster Feb 13 '20 at 22:26
  • When the main view spawns the dialog it can pass in the current VM or part of it, so the dialog can also use binding. While this might sound complex it isn't - you're just being super careful about separation of concerns between the View and the VM. Your aim should be to have the view totally replaceable; the view can access the VM but the VM knows nothing about the view. Aim to reduce tight coupling by only exposing the viewmodel as an interface. I hope that all helps :) – slugster Feb 13 '20 at 22:29

1 Answers1

1

You can create a property on the view model with following signature:

public Func<string, string, bool> ReportMessage { get; set; }

Then when constructing your view model you can pass it an implementation:

var OKCancelMessage = new Func<string, string, bool>((m, c) => MessageBox.Show(m, c) == MessageBoxResult.OK ? true : false);

new ViewModel() 
{ 
    ReportMessage = OKCancelMessage 
}

This way your view model will not know about the implementation of the message and separation of view from model has been achieved.

EDIT

Calling the function is simple:

if(ReportMessage("Do you really want to delete this record?", "Question"))
    Delete(record);
Robert
  • 2,407
  • 1
  • 24
  • 35
  • Really nice approach, thanks! But could you please add how I can call this `Func` from `ViewModel`? As far as I understand after I set this `Func` from `View` to `ViewModel` I have to someway to call it when I need, right? – Sirop4ik Feb 13 '20 at 11:56
  • I have edited the answer to include usage of Func object. – Robert Feb 13 '20 at 12:00
  • This approach *can* work and was one of the better approaches when using Silverlight, but it does lead to a mess of Funcs once you project starts getting bigger. – slugster Feb 13 '20 at 12:05
  • As far as it goes this is a pretty nice solution for small to mid sized projects. For bigger projects I would consider using some sort of Dependency Injection like Ninject. – Robert Feb 13 '20 at 12:09