Search code examples
c#wpfmvvmmvvm-lightmodern-ui

WPF MvvM communication between view models in a single View


This title might be inappropriate for question itself but stay with me  I’ll change it if you have better suggestion. This is my first wpf application so I might missed some key concept… I did google, but I failed to find correct approach.

I am building wpf application using MvvM Light and MUI and I got into trouble with item bindings, ie communication between view models. Now, I am sure that I wouldn't have this problem if I used single View model for the Page and all user controls in it, but I think I overdid it on my first try.

I have one Main Window in application and pages as the user controls. In each page I have several other user controls and each one of them have its own view model and its own logic for doing stuff but in the end they all depend on the corresponding VM with data grid. We could think of them as poor man angular directives. Each user control have its data context defined like so:

DataContext="{Binding ViewModelName, Source={StaticResource Locator}}

Layout looks like this: Wpf Layout Look at this way, DG1 in VM1 is Master (customer) and UC3 and UC4 are Details (orders). If I add new order to the customer, I would like it to be updated in the DG1 without refreshing entire grid.

In VM1 Data Grid 1 selection changed I am firing commands to set property values of depending user controls.

<i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectionChanged">
                <mvvm:EventToCommand Command="{Binding ErrorWorkflow.GetErrorWorkflowCommand, Mode=OneWay, Source={StaticResource Locator}}" CommandParameter="{Binding SelectedError.WF_REF}" />
                <mvvm:EventToCommand Command="{Binding ErrorDetails.GetErrorCaseDetailsCommand, Mode=OneWay, Source={StaticResource Locator}}" CommandParameter="{Binding SelectedError}" />
             </i:EventTrigger>
        </i:Interaction.Triggers>

That part works ok, but when I change the value of in the depending VM3 for both VM3 and VM1, VM1 property values are not changed even though I call RaisePropertyChanged or setting property explicitly by hand like SelectedError.Status = “somethingnew”.

On the other hand, if I clear selection form the data grid, depending view models stay bound (text boxes on them preserve the value because they are referencing properties on their own VM3).

All View Models derive from ViewModelBase from mvvmLight and all models from ObservableObjects (I know that I should use Poco, but apparently I have to create each property on VM too). Example:

        public const string SelectedErrorPropertyName = "SelectedError";

    private ErrorLog _selectedError;

    public ErrorLog SelectedError
    {
        get
        {
            return _selectedError;
        }
        set
        {
            Set(() => SelectedError, ref _selectedError, value);

        }
    }

I think that Messenger would be an overkill considering the size of the application (only few pages like this one).

Should I change the Page to use only one View Model and share them for each user control or am I missing something obvious here? If you think that I am missing some key information in this example please tell me and I’ll update.

Thank you in advance for any advice, cheers!


Solution

  • You should never change the Page to only one View Model and Messenger is not an overkill. The MVVM Light Messenger is built to solve exact the problem (communication between VMs) you are having at the moment. You should use it.

    For further information about the messaging within MVVM Light, Jesse Liberty of Microsoft has a great tutorial on how to make use of it.