mpen
mpen

Reputation: 283213

Need a dict with my own custom Pair type?

KeyValuePair doesn't implement INotifyPropertyChanged, so I've implemented my own Pair type, but I want to use it in a dictionary.

What's the easiest way to do that?


So here's the deal. In my code I need a dictionary with key/value pairs. This doesn't really need to be observable.

I have an edit window though, that displays this dict in a datagrid. That needs to be observable so that the datagrid can work its magic.

So what I've done is make make the edit window accept any enumerable of pairs:

    public ObservableCollection<Pair<string,object>> Variables { get; private set; }

    public VariablesWindow(IEnumerable<Pair<string, object>> vars)
    {
        Variables = new ObservableCollection<Pair<string, object>>(vars.DeepCopy());

So that it can do its thing. And then in the main code I use a dict like normal, but when I open the edit window I have to convert the dict into something the edit window can use:

var window = new VariablesWindow(Dict2Enum(_dict));

So I've added these 2 helper methods:

    private static IEnumerable<Pair<TKey, TValue>> Dict2Enum<TKey, TValue>(Dictionary<TKey, TValue> dict)
    {
        return dict.Select(i => new Pair<TKey, TValue>(i.Key, i.Value));
    }

    private static Dictionary<TKey, TValue> Enum2Dict<TKey, TValue>(IEnumerable<Pair<TKey, TValue>> collection)
    {
        return collection.ToDictionary(p => p.Key, p => p.Value);
    }

Seems a bit expensive though. I'm looping over the collection twice now. Once to convert the dictionary to an enumerable, then again to deep copy it so that the variables don't get changed until the user hits save, and then I convert that enumerable into an observable collection.

Upvotes: 1

Views: 344

Answers (2)

Jon Skeet
Jon Skeet

Reputation: 1503040

Are you trying to notify of a value changing? If so, I'd consider writing a Wrapper<T> class which supported INotifyPropertyChanged, and then using (say) Dictionary<string, Wrapper<int>> (for a "string/int" dictionary which supports notification of changes).

Note that this will mean that anyone who keeps a reference to the wrapper will see the changes made to the value - it's something you'd have to be quite careful about.

EDIT: To expand on my comments somewhat...

If you want to be able to edit the key as well, I suspect you'll that for a mutable TKey/TValue pair you'll want a Dictionary<TKey, MutablePair<TKey, TValue>>. You'll need to support INotifyPropertyChanging as well as INotifyPropertyChanged, and it would get somewhere hairy... you may need to remove it by key on INotifyPropertyChanging, and then re-add it on INotifyPropertyChanged. No doubt things would get messy if the change was abandoned half way through. You'd also need to work out what you'd want to happen if one key overwrote another... and then the original object was changed:

// Rough code - imagine we'd got a wrapper around Dictionary<TKey, TValue>
// to create the pairs automatically.
oddDictionary["key1"] = "value1";
oddDictionary["key2"] = "value2";

var pair1 = oddDictictionary.GetMutablePair("key1");
var pair2 = oddDictictionary.GetMutablePair("key2");
pair1.Key = "key2"; // Overwrite pair2, presumably...
// Does the "changing" remove pair1? Or check for consistency? As it's
// not part of the dictionary before the operation, does this not affect
// the dictionary at all?
pair2.Key = "key3"; 

Basically there's a lot of semantics you need to think through really carefully before going much further.

I suggest you write lots of unit tests for the behaviour you want to implement, and then see what you can do.

Upvotes: 2

ShahidAzim
ShahidAzim

Reputation: 1494

Here is a sample which can be used as a reference:

http://drwpf.com/blog/2007/09/16/can-i-bind-my-itemscontrol-to-a-dictionary/

Upvotes: 1

Related Questions