I have a tree of model object which I am displaying in a TreeView using a hierarchical data template. Each model object is converted on the fly to a ViewModel object using a ValueConverter, but the Model's properties are still bound to for the child items in the hierarchical data template.
The problem I have is that the Model objects store their children in dictionaries, and it's specifically the values, rather than the keys that I'm interested in client side. The Dictionary is not Observable, so what I am looking for is - in an ideal world - a way to wrap the Dictionary (or perhaps more specifically the internal ValueCollection that the Dictionary uses on the "Values" property, in order to make it observable.
I've delved into the source of the Dictionary to see if there are any hidden hooks I could reflect, but I can't see anything.
Anyone have a suggestion?
Edit:
The behaviour I want is effectively this:
var nonObservable = new Dictionary<Guid, object>();
var observableDictionary = new ObservableDictionary<Guid, object>(nonObservable);
observableDictionary.CollectionChanged += //Some event handler
nonObservable.Add(Guid.NewGuid, new object());
When I add objects to the non-observable Dictionary, I want a collection changed event on the wrapper to fire. This will probably require some deep reflecting. It's a hacky approach that I would rather avoid, but I don't really like the alternatives either.
You could implement the IDictionary<TKey, TValue> interface. Internally, you'd use a Dictionary, so your class would act as a proxy between the client and the real dictionary. However, you'd also be raising events, like this:
public class ObservableDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
private IDictionary<TKey, TValue> _dictionary = //...
public event EventHandler<DictionaryChangedArgs> OnAdded;
public ObservableDictionary()
{
_dictionary = new Dictionary<TKey, TValue>();
}
//wrap an existing dictionary
public ObservableDictionary(IDictionary<Tkey, TValue> dictionary)
{
_dictionary = dictionary;
}
public void Add(TKey key, TValue val) {
_dictionary.Add(key, value);
if(OnAdded != null)
OnAdded(new DictionaryChangedArgs(key, value));
}
}
Edit
Updated the code to reflect your requirement: "wrap an existing dictionary".
The idea seems to be similar to the one presented on dav_i's link.
Related
If I instantiate a new Dictionary I can pass in many values:
Dictionary<string, string> data = new Dictionary<string, string>(){
{ "Key1", "Value1" },
{ "Key2", "Value2" },
{ "Key3", "Value3" },
{ "Key4", "Value4" },
{ "Key5", "Value5" },
}
However, if I already have a Dictionary, such as when it is passed in a parameter, I'm required to call Add for each key-value pair:
data.Add("Key1", "Value1");
data.Add("Key2", "Value2");
data.Add("Key3", "Value3");
data.Add("Key4", "Value4");
data.Add("Key5", "Value5");
I'm wondering if there's a "shorthand" method for adding in a large number of values to an existing Dictionary at one time - preferably natively? An authoritative "no" is welcome if that be the case.
Not as clean as I'm looking for, but these are the two alternatives I know.
This one allows passing many values at once, but requires creating a new Dictionary rather than updating the existing one:
Dictionary<string, string> newData = new Dictionary<string, string>(data)
{
{ "Key6", "Value6"},
{ "Key7", "Value7"},
{ "Key8", "Value8"},
};
It's also possible to create an extension method, but this still calls Add for each row:
public static void AddMany<Tkey, TValue>(this Dictionary<Tkey, TValue> dict, Dictionary<Tkey, TValue> toAdd)
{
foreach(KeyValuePair<Tkey, TValue> row in toAdd)
{
dict.Add(row.Key, row.Value);
}
}
An authoritative "no" is welcome if that be the case.
That be the case.
No, there is not an AddRange or equivalent because there is no practical way to add multiple items to a dictionary at one time. It makes sense for a List to add multiple items at once because they can get copied into the internal array in one command.
For a Dictionary, the hash code of each item must be computed to determine what "bucket" the value will get stored in, so there is by necessity a need to iterate over each item. Thus an AddRange method or its equivalent would at best be syntactic sugar. At worst, one would need to define what would happen if any item in the list already existed. Would it throw an exception? If so, would items that were added before the duplicate stay in the dictionary? If not, would it silently skip the item or replace the duplicate?
These are questions that have no intuitively correct answer and thus have not been pre-defined.
If you frequently need to add multiple items to your dictionary you could make an extension method
public static class DictionaryExtensions
{
public static void AddRange<TKey, TValue>(this Dictionary<TKey, TValue> dic, List<KeyValuePair<TKey, TValue>> itemsToAdd)
{
itemsToAdd.ForEach(x => dic.Add(x.Key, x.Value));
}
}
The above would be fine for bulk adding known-unique items. If you need to be concerned about dupes then you'd want to add sanity checks and perhaps return a list of bools to let you know which succeeded .. but at that point you might as well forego the extension method since much of the convenience would be lost.
You can make an extension to achieve this task.
public static class DictionaryHelper
{
public static Dictionary<TKey, TValue> AddRange<TKey, TValue>(this Dictionary<TKey, TValue> destination, Dictionary<TKey, TValue> source)
{
if (destination == null) destination = new Dictionary<TKey, TValue>();
foreach (var e in source)
{
if (!destination.ContainsKey(e.Key))
destination.Add(e.Key, e.Value);
destination[e.Key] = e.Value;
}
return destination;
}
}
This is a generic function that will accept another dictionary.
I have a complex data container with multiple levels of nested Dictionaries.
But having Key and Value properties make it non-intuitive and hard to use.
Please suggest the simplest way to rename Key and Value properties in Dictionary<,> subclasses.
Update:
Patryk Ćwiek: If you implement IDictionary<TKey, TValue>, you also can't rename properties, because they're part of the contract.
You're right. My question was not correct. Usage of KeyValuePair in IDictionary restrict the pair properties to Key and Value. So if we want non Key/Value pair we had to implement IDictionary with custom KeyValuePair struct. Or may be there is some other tricky way?
PS. Maybe someone suggest an IDictionary code generation template?
Make your own interface with the property name(s) you want. Then, have your concrete class implement your custom interface.
To keep your code DRY, create a private Dictionary that you delegate all of your work to. You can even have your custom interface be Enumerable (or anything else that IDictionary implements) by delegating the required methods to your private variable.
Here is an example. You would just need change your code from using IDictionary to IComplexDataContainer.
interface IComplexDataContainer<TKey, TValue>
: IEnumerable<KeyValuePair<TKey,TValue>>
{
TValue this[TKey index] { get; set; }
}
class MyComplexDataContainer<TKey, TValue>
: IComplexDataContainer<TKey, TValue>
{
IDictionary<TKey, TValue> hiddenHelper { get; set; }
public MyComplexDataContainer()
{
hiddenHelper = new Dictionary<TKey, TValue>();
}
// delegate all of the work to the hidden dictionary
public TValue this[TKey index]
{
get
{
return hiddenHelper[index];
}
set
{
hiddenHelper[index] = value;
}
}
// Just delegate the IEnumerable interface to your hidden dictionary
// or any other interface you want your class to implement
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return hiddenHelper.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Then you would just use like this:
IComplexDataContainer<string, int> myData = new MyComplexDataContainer<string,int>();
myData["tom"] = 18;
myData["dick"] = 22;
myData["harry"] = myData["tom"];
I was looking for a method in ConcurrentDictionary that allows me to remove an entry by key, if and only if the value is equal to one that I specify, something like the equivalent of TryUpdate, but for removals.
The only method that does this seems to be this method:
ICollection<KeyValuePair<K, V>>.Remove(KeyValuePair<K, V> keyValuePair)
It is the explicit implementation of the ICollection interface, in other words, I have to cast my ConcurrentDictionary to an ICollection first so that I can call Remove.
Remove does exactly what I want, and that cast is no big deal either, also the source code shows it calls the private method TryRemovalInternal with bool matchValue = true, so it all looks nice and clean.
What worries me a bit however is the fact that it is not documented as the optimistically concurrent Remove method of ConcurrentDictionary, so http://msdn.microsoft.com/en-us/library/dd287153.aspx just duplicates the ICollection boilerplate, and the How to: Add and Remove Items from a ConcurrentDictionary does not mention that method either.
Does anyone know if that's the way to go, or is there some other method that I'm missing?
Though it is not an official document, this MSDN blog post can be helpful. The gist of that article: casting to ICollection and calling its Remove method, just as described in the question, is the way to go.
Here's a snippet from the above blog post, which wraps it into a TryRemove extension methods:
public static bool TryRemove<TKey, TValue>(
this ConcurrentDictionary<TKey, TValue> dictionary, TKey key, TValue value)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
return ((ICollection<KeyValuePair<TKey, TValue>>)dictionary).Remove(
new KeyValuePair<TKey, TValue>(key, value));
}
If you don't need all the bells & whistles of ConcurrentDictionary, you can just declare your type as an IDictionary.
public class ClassThatNeedsDictionary
{
private readonly IDictionary<string, string> storage;
public ClassThatNeedsDictionary()
{
storage = new ConcurrentDictionary<string, string>();
}
public void TheMethod()
{
//still thread-safe
this.storage.Add("key", "value");
this.storage.Remove("key");
}
}
I find this useful in situation in which you only need to add and remove, but still want a thread-safe iteration.
How can we retrieve Dictionary<A,B> elements in the order in which they were inserted? If dictionary doesn't support this then which object should i use which gives the behavior of dictionary but also allows me to get the elements in the order in which they were inserted.
Thanks in advance :)
There is no guarantee that you can retrieve the elements from a Dictionary<TKey, TValue> in order. If this is the behavior that you desire, just encapsulate it into a class:
class DictionaryWithKeysOrderedByInsertion<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>> {
private readonly List<TKey> keys = new List<TKey>();
private readonly Dictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue>();
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
foreach(var key in keys) {
yield return new KeyValuePair(key, dictionary[key]));
}
}
// etc.
}
Dictionary is unordered, if you want them back in the order they were inserted, you might want to consider the generic Queue
No, dictionary does not have such functionality.
You can
use 2 structures and insert into both at the same time - List/LinkedList to store sequence and dictionary to provide fast lookup.
you can add information about insertion time to entries stored in the dictionary.
I am using a ResourceDictionary, but I would like to be able to look up the value or the key with the other item. Each is always unique, so that is not a problem. Is there a type that has this double sided lookup feature?
Not built in, but this is pretty easy to write. I would probably implement IDictionary for this though... You would then dump the ResourceDictionary into your custom type.
public class DoubleLookup<TKey, TValue>
{
private IDictionary<TKey, TValue> keys;
private IDictionary<TValue, TKey> values;
//stuff...
public void Add(TKey key, TValue value)
{
this.keys.Add(key, value);
this.values.Add(value, key);
}
public TKey GetKeyFromValue(TValue value)
{
return this.values[value];
}
public TValue GetValueFromKey(TKey key)
{
return this.keys[key];
}
}
Be very careful when reversing the key/value relationship in a dictionary.
The contract of the dictionary guarantees that, for every value in the collection, there is exactly one key which maps to that value. The keys are unique. But the reverse is not true; for every distinct value, there can be many different keys mapping to that value.
In my own personal code library (written in Java, which is close enough), I have MultiMap class for just this kind of thing. Although the keys are unique, each key can be associated with multiple values. It's exactly identical to a Map>.
When I need to perform value-to-key lookups in a collection, I do something like this:
Map<K, V> lookupTable = ...;
MultiMap<V, K> reverseLookupTable = MapUtil.invert(lookupTable);
V value = ...;
if (reverseLookupTable.containsKey(value)) {
Set<K> keys = reverseLookupTable.get(value);
}
If you use something other than a MultiMap (like a HashMap or Dictionary) as your reverse-lookup table, you run the risk of losing some of your V->K mappings, unless you can guarantee that all keys AND all values in your collection are unique.
EDIT:
Oops. I just noticed that you said that all keys and values in your collection are unique. But I'll leave my answer here anyhow, as a warning for others reading this, who might not be able to provide the same guarantee.