1

I have used this blog and this SO question to setup MVVM in my WPF app. My issue is that my viewmodels are being instantiated twice. And I have code in their constructors that needs to only run once.

I have a content control on my MainWindow.xaml:

<ContentControl Content="{Binding CurrentViewModel, UpdateSourceTrigger=PropertyChanged}" />

On my MainWindow ViewModel I load other viewmodels using MVVM Light messenger service:

Messenger.Default.Register<BaseViewModel>(this, ChangeViewModel);
private void ChangeViewModel(BaseViewModel viewModel)
{
    CurrentViewModel = viewModel;
}

Then on other views I use the messenger service to tell the MainWindow ViewModel to load another ViewModel:

Messenger.Default.Send((BaseViewModel)new AuthViewModel());

The problem is that when this new View is loaded I set the DataContext in the code behind:

    public AuthView()
    {
        InitializeComponent();
        DataContext = new AuthViewModel();
    }

This results in the constructor for AuthViewModel being run twice. What is the proper way to do this?

Dbloom
  • 1,302
  • 3
  • 18
  • 45
  • 2
    "*The problem is that when this new View is loaded I set the DataContext in the code behind.*" - exactly. Don't do that. – Clemens Jul 01 '20 at 16:07
  • @Clemens - I took your advice and it seems to work. But now how is the DataContext being set? What is linking the view to the viewModel? – Dbloom Jul 01 '20 at 17:58
  • 1
    DataContext is a property that supports *value inheritance*. If it is not set explicitly, its value is inherited from the parent element. See the Remarks: https://learn.microsoft.com/en-us/dotnet/api/system.windows.frameworkelement.datacontext?view=netcore-3.1#remarks – Clemens Jul 01 '20 at 18:07
  • @Clemens - The only place I can find in my code that would link my views and viewModels in the app.xaml file where I have defined DataTemplates: auth:AuthView/ – Dbloom Jul 01 '20 at 18:25
  • The Messenger is sending a viewmodel object to anyone listening. The MainWindow viewModel is the only thing listening. When it gets those messages it changes the CurrentViewModel to the viewModel that was passed in. I got the idea from here: https://rachel53461.wordpress.com/2011/06/05/communication-between-viewmodels-with-mvvm/ – Dbloom Jul 01 '20 at 18:30
  • 1
    When that DataTemplate is automatically applied at a ContentControl (or something similar), the Content property of that control already holds an instance of the view model. That instance is then passed to the DataContext of the element in the DataTemplate. Applying the DataTemplate is performed automatically due to its DataType property. – Clemens Jul 01 '20 at 18:33
  • 1
    @Dbloom: Do you expect the constructor to be invoked once when you explicitly call `new AuthViewModel()` twice...? Try to remove `DataContext = new AuthViewModel();`. This should solve your issue. – mm8 Jul 02 '20 at 16:06

1 Answers1

1

Change this:

private void ChangeViewModel(BaseViewModel viewModel)
{
    CurrentViewModel = viewModel;
}

TO

private void ChangeViewModel(BaseViewModel viewModel)
    {
var issame = this.CurrentViewModel == null ? false : viewModel.GetType().Equals(this.CurrentViewModel.GetType());
                if (issame)
                    return;
else
CurrentViewModel = viewModel;
}
rufw91
  • 157
  • 2
  • 8