Notifying that all properties have changed on a ViewModel
Asked Answered
A

3

7

I am working on a Silverlight application using V3 SP1 of MVVM Light Toolkit.

My application is fully French/English. All UI elements (buttons, labels, etc.) and all the data (models). I need dynamic language switching and this is fully implemented and works with anything coming from a resource file. What I am struggling with is the ViewModels.

The Models have language specific prperties (DescriptionEn, DescriptionFr) and an additional property call LocalizedDescription which uses the current culture to return call the language specific property.

When the language changes (via a button click) I raise and broadcast (via the Messenger) a property changed event.

In each of my ViewModels, I register to receive the property changed message for the language swap.

I want to notify all the properties of the ViewModel that something has changed.

From: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.propertychanged.aspx

The PropertyChanged event can indicate all properties on the object have changed by using either null or String.Empty as the property name in the PropertyChangedEventArgs.

However, since the toolkit abstracts the raising of the changed event with RaisePropertyChanged(...) I cannot get this to work. I have also examined the source of the tookit and discovered that RaisePropertyChanged calls VerifyPropertyName(..) which in turn returns an error is the property does not belong to the ViewModel. I also noticed that the VerifyPropertyName method is attributed with Conditional("DEBUG"), but even if I choose the Release configuration, the ArgumentException("Property not found") is still raised.

Does anyone know of a way to get this to work using the toolkit aside from manually calling RaisePropertyChanged for every property of the ViewModel?

Follow-up:

Based on the comment from Simon, I attempted to create my own class that extends ViewModelBase. I looked at the source on CodePlex and decided to create a single method called RaiseAllPropertyChanged(). It would simply be a copy of the RaisePropertyChanged(string propertyName) but without the parameter and without the call to VerifyPropertyName(...). I cannot get it to work. Here is what I have.

public class ViewModelBaseExtended : ViewModelBase
{
    protected void RaiseAllPropertyChanged()
    {
        var handler = this.PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(String.Empty));
        }
    }
}

But I get a compiler error: The event 'GalaSoft.MvvmLight.ViewModelBase.PropertyChanged' can only appear on the left hand side of += or -=. This is a copy of the code that is used in the ViewModelBase.

Can someone offer some advice as to how to get this to work?

Solution:

I copied all the code from ViewModelBase into a new class. I then added the method RaisePropertyChanged() mentioned above which instantiates the PropertyChangedEventArgs class with String.Empty. This is now the new subclass for my ViewModels.

Thanks again to Simon for leading the way!

Arte answered 20/5, 2011 at 15:30 Comment(2)
Why are you notifying for all anyway?Rexanne
I am notifying all properties because I need them to re-read their data because of a language change. For example, I have a ViewModel that has 10 properties. Those properties are collections of data that have both French and English descriptions and are rendered at runtime in the current language. When the current language is changed, I need to notify all the properties so that their data now renders in the new current language. Although, upon implementing the solution above, I am still struggling to get the data to switch languages. But the issue of notifying all is resolved.Arte
R
3

Unfortunately this is not possible with the current code-base of MVVMLight

In the short term your have 2 options:

  1. User your own custom base class. And by custom base class I mean "Do not inherit from the MVVMLight class".

  2. Download and compile MVVMLight in Release mode. This will force the "VerifyPropertyName" method to be excluded. Of course then you don't get the value of property name checks.

I am sure Laurent Bugnion will have this fixed soon.

Rexanne answered 22/5, 2011 at 3:56 Comment(4)
I have added a follow-up to my original question taking your suggestion of a new base class. Any suggestions?Arte
@Vincenzo update my answer. you cant access an event in a base class in that manner. you need to create your own custom base class from scratch.Rexanne
@Vincenzo are you on twitter ? if so ping me at twitter.com/SimonCropp and we can discuss thisRexanne
Thanks @Rexanne for the info. I have updated the original post with my solution.Arte
D
5

In case you're reading this in 2016, you can use ObservableObject and notify that all of the properties have changed by doing:

RaisePropertyChanged(string.Empty);
Diazomethane answered 25/3, 2016 at 14:45 Comment(0)
R
3

Unfortunately this is not possible with the current code-base of MVVMLight

In the short term your have 2 options:

  1. User your own custom base class. And by custom base class I mean "Do not inherit from the MVVMLight class".

  2. Download and compile MVVMLight in Release mode. This will force the "VerifyPropertyName" method to be excluded. Of course then you don't get the value of property name checks.

I am sure Laurent Bugnion will have this fixed soon.

Rexanne answered 22/5, 2011 at 3:56 Comment(4)
I have added a follow-up to my original question taking your suggestion of a new base class. Any suggestions?Arte
@Vincenzo update my answer. you cant access an event in a base class in that manner. you need to create your own custom base class from scratch.Rexanne
@Vincenzo are you on twitter ? if so ping me at twitter.com/SimonCropp and we can discuss thisRexanne
Thanks @Rexanne for the info. I have updated the original post with my solution.Arte
O
1

A lighter solution to this problem would have been to override RaisePropertyChanged(string propertyName) in your class :

protected override void RaisePropertyChanged(string propertyName)
    {
        if (propertyName != null)
        {
            base.RaisePropertyChanged(propertyName);
        }
        else
        {
            var handler = PropertyChangedHandler;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(null));
            }

        }
    }
Osmose answered 14/1, 2014 at 18:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.