tags:

views:

179

answers:

1

Greetings, creating my first MVVM based WPF app and trying to figure out why I'm unable to hook into the PropertyChanged event of a dependency property.

Code in the parent view model:

void createClients()
{
    var clients = from client in Repository.GetClients()
                  select new ClientViewModel(Repository, client);
    foreach (var client in clients)
    {
        client.PropertyChanged += onClientPropertyChanged;
    }
    Clients = new ViewableCollection<ClientViewModel>(clients);
    Clients.CollectionChanged += onClientsCollectionChanged;
}

// Never gets called
void onClientPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == "Name")
    {
         //...
    }
}

ViewableCollection is a simple extension of ObservableCollection to encapsulate a View.

In the ClientViewModel the setters are being called but RaisePropertyChanged isn't working as I would expect, because onClientPropertyChanged isn't being invoked. Both view models inherit from ViewModelBase.

public string Name
{
    get { return client.Name; }
    set
    {
        if (value == client.Name) return;
        client.Name = value;
        RaisePropertyChanged("Name");
    }
}

If I wire up PropertyChanged to a method inside the ClientViewModel then it is being fired, so I'm stumped as to why this isn't working in the parent view model. Where am I going wrong?

A: 

This SO question explains the problem; ObservableCollection protects the PropertyChanged event.

One solution is to use MVVM-Light Messenger:

void createClients()
{
    var clients = from client in Repository.GetClients()
                  select new ClientViewModel(Repository, client);
    Clients = new ViewableCollection<ClientViewModel>(clients);
    Clients.CollectionChanged += onClientsCollectionChanged;
    Messenger.Default.Register<PropertyChangedMessage<string>>(this, (pcm) =>
    {
        var clientVM = pcm.Sender as ClientViewModel;
        if (clientVM != null && pcm.PropertyName == "Name")
        {
            // ...
        }
    });
}

createClients() should be refactored, but for consistency with the question code I'll leave it in there. Then a slight change to the property setter:

public string Name
{
    get { return client.Name; }
    set
    {
        if (value == client.Name) return;
        string oldValue = client.Name;
        client.Name = value;
        RaisePropertyChanged<string>("Name", oldValue, value, true);
    }
}
Si
-1 because he's not handling PropertyChanged on the ObservableCollection. He's iterating through the collection and handling PropertyChanged on each item.
Matt Casto
Hi Matt, I don't follow you? there is no iteration, only a registration to receive property changed event, and a message broadcast along with the event handling in the property setter. How do you handle this inside the ObservableCollection if it protects the PropertyChanged event?
Si
Okay, I didn't realize that you were answering your own question. I must have completely misunderstood the problem you were having because I don't understand how its related to your answer. SO won't let me un-vote your answer unless it is edited (sorry)
Matt Casto
No problem Matt, I was answering because it would've been too confusing to answer in the question, if you get what I mean :)
Si
If you edit your answer then I can up-vote it.
Matt Casto