Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Notify that certain value has changed in Dictionary

At the moment I'm writing my own dictionary that implements INotifyPropertyChanged. See below:

public event PropertyChangedEventHandler PropertyChanged;

protected void OnPropertyChanged(string propertyName)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

new public Item this[TKey key]
{
    get { return base.Item[key]; }
    set(TValue value)
    {
        if (base.Item[key] != value)
        {
            base.Item[key] = value;
            OnPropertyChanged("XXX"); // what string should I use?
        }
    }
}

My goal is simple: when a certain value in the Dictionary has changed, notify that it has changed. All WPF elements that have a binding with the corresponding key name should then update themselves.

Now my question is: what string should I use as propertyName in order to notify?

I have tried "[" + key.ToString() + "]", "Item[" + key.ToString() + "]" and simply key.ToString(). They all did not seem to work, because the WPF elements did not update.

Using String.Empty ("") does update the WPF elements, but I'm not using this, because this will update all WPF elements that are bound the same dictionary, even though they have different keys.


This is how my binding looks like in XAML:

<TextBlock DataContext="{Binding Dictionary}" Text="{Binding [Index]}" />

Index is of course the name of the key in my dictionary.


In stead of using INotifyPropertyChanged, some have suggested to use INotifyCollectionChanged. I tried this:

Dim index As Integer = MyBase.Keys.ToList().IndexOf(key)
Dim changedItem As Object = MyBase.ToList().ElementAt(index)

RaiseEvent CollectionChanged(Me, New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, changedItem, index))

But that does not update the bound WPF elements either.

like image 850
Rudey Avatar asked Jan 30 '13 13:01

Rudey


2 Answers

Perhaps you need to consider the INotifyCollectionChanged interface rather than INotifyPropertyChanged. If that's the case, have a look at this question and the blog post that it links to.

Also, check this answer to a previous question that was similar to yours. It suggests that you use the value of Binding.IndexerName as the property name for the change notification.

Edit:

If you want to avoid using INotifyCollectionChanged, you might try an alternative approach. Change your dictionary so that the type of its values is a proxy object that implements INotifyPropertyChanged.

public class MyProxy<T> : INotifyPropertyChanged
{
    public T Value
    {
        // Getter and setter with change notification code here.
    }
}

Then insert instances of this type into your dictionary just once. Replace the code that updates a value in the dictionary with code that retrieves the proxy, then updates its Value property.

You would need to change your XAML binding to something like ([Item]).Value.

After reviewing some of your other comments, it does look as though this approach might work for you. It's similar to something I had to do recently. Create a custom KeyedCollection and a corresponding proxy. Add a ItemName property to the proxy; it can be read only, and does not need to support change notifications. Make your KeyedCollection implementation index on the ItemName property. Works a treat! I'll add sample code if you would like it.

like image 199
Olly Avatar answered Sep 24 '22 03:09

Olly


if (base.Item[key] != value)
{
     base.Item[key] = value;
     if (key == "notifykey") OnPropertyChanged("[Item]");
}

String.empty will notify all properties not just Item

Per op this as the problem of all the bindings to Dictionary still update.
So I would make a new property

Let just assume you value is string Bind to KeyedValue

public String KeyedValue
{
    get { return base.Item[Index]; }
}

if (key == "Index") OnPropertyChanged("KeyedValue");
like image 28
paparazzo Avatar answered Sep 20 '22 03:09

paparazzo