0

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?

Peter Ajtai
  • 56,972
  • 13
  • 121
  • 140
si618
  • 16,580
  • 12
  • 67
  • 84
  • How are you trigger the Name property change? If its through data binding, are you using the TwoWay mode? Check the output window for data binding errors. Also, have you tried putting a breakpoint in your Name property setter and is it being hit? – Matt Casto Aug 19 '10 at 12:56
  • Hi Matt, yes on both counts, but I just found another SO question which explains this behaviour. – si618 Aug 20 '10 at 00:27

1 Answers1

1

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);
    }
}
Community
  • 1
  • 1
si618
  • 16,580
  • 12
  • 67
  • 84
  • 1
    -1 because he's not handling PropertyChanged on the ObservableCollection. He's iterating through the collection and handling PropertyChanged on each item. – Matt Casto Aug 20 '10 at 12:13
  • 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? – si618 Aug 20 '10 at 12:45
  • 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 Aug 20 '10 at 13:25
  • No problem Matt, I was answering because it would've been too confusing to answer in the question, if you get what I mean :) – si618 Aug 20 '10 at 15:40