Search code examples
c#wpfmvvmprism-5

propertychanged in region from other region


I am using WPF + MVVM with prism and unity. I have three regions "menu", "main" and "footer". Now I would like to set a property in the footerViewModel (region "footer") from MainViewModel in region "main". This property should be displayed in the footerView. The change event works but it does not update the textbox in the view.

I hope someone can help me?

Thanks in advance.

This is my MainViewModel:

private CodingGuidline _selectedGuidline;
public CodingGuidline SelectedGuidline {
  get { return _selectedGuidline; }
  set
  {
    _selectedGuidline = value;
    OnPropertyChanged(() => SelectedGuidline);
    OnUpdateAppCodingSpecification(this, EventArgs.Empty);
  }
}


private async void OnUpdateAppCodingSpecification(object sender, EventArgs args)
{
  try
  {
    Task<CodingGuidline> result = CodingRepository.GetCodingSpecification(SelectedGuidline.Guid);
    _application.CurrentGuidline = await result;
    _container.Resolve<FooterViewModel>().OnUpdateCodingGuidline(this, EventArgs.Empty);
  }
  catch (Exception exception)
  {
    MessageBox.Show(exception.ToString());
  }

}

Notice: _application is a static object which provides shared information

FooterViewModel:

    public FooterViewModel(IUnityContainer container)
{
  _container = container;
  _application = _container.Resolve<IApplication>();
  AssemblyVersion = "Version: " + Assembly.GetExecutingAssembly().GetName().Version;
  WebserviceUrl = "Host: " + _application.WebserviceUrl;

  UpdateCodingGuidline += OnUpdateCodingGuidline;
}

public event EventHandler UpdateCodingGuidline;

public void OnUpdateCodingGuidline(object sender, EventArgs args) {
  if (_application.CurrentGuidline != null)
  {
    CurrentCodingSpecification = _application.CurrentGuidline.SequenceNumber + " " + _application.CurrentGuidline.Name;
  }
  else
  {
    CurrentCodingSpecification = " - ";
  }
}

private string _currentCodingSpecification;
public string CurrentCodingSpecification {
  get {
    return _currentCodingSpecification;
  }
  set {
    if (value != _currentCodingSpecification) {
      _currentCodingSpecification = value;
      OnPropertyChanged(() => CurrentCodingSpecification);
      MessageBox.Show(CurrentCodingSpecification.ToString());
    }
  }
}

The Messagebox appears but the view doesnt show the change.

Binding in FooterView:

  <StatusBarItem Content="{Binding CurrentCodingSpecification, Mode=TwoWay}" HorizontalAlignment="Left" VerticalAlignment="Center" Width="200"/>

Solution

  • Services are the way to solve this issue. Create a shared service that you can inject into all your view models (and thus mock!). This manages the state and has events that can notify the vm's when a value has changed.

    During the initialization of your vm's, you can subscribe to the service. When the vm's are closed, you can unsubscribe again to prevent memory leaks.

    And a bit off-topic, but here are a few tips to improve your MVVM coding:

    1. Instead of injecting a container, inject services (don't hide what you really need), that makes testing and other development much easier
    2. Using MessageBox.Show is not smart inside vm's. How should it behave during a test? Use a service for this instead (for example, IMessageService). Then if you need to change something to the way message boxes are shown, there is 1 location for you to look at). And you can mock the messages (and even result codes).