RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Generic Dictionaries: Hidden Treasure of System.Collections.Generic : Page 2

Generic dictionaries simplify common tasks, such as coordinating selection between a TreeView and a ListView—but their capabilities extend far beyond that, once you realize you can use DynamicInvoke() to execute delegates stored in the dictionary.

Using Two Dictionaries for Bidirectional Lookup
"But wait!" (I hope you're already saying) "Okay, you've got the ability to look up a ListViewItem using a key that's a TreeNode, but what about when you get a hit on the ListViewItem, and you want to know which corresponding TreeNode should be selected?"

Well, one answer would be to have two generic dictionaries. For example, you could add a second one of the form:

   private Dictionary<ListViewItem, TreeNode> LVIDictionary = 
      new Dictionary<ListViewItem, TreeNode>();
Now you have a way to get the corresponding TreeNode from a selected ListViewItem using the LVIDictionary instance.

Loading the Generic Dictionaries
Now the question becomes: How can you get these dictionaries properly loaded with the TreeNode and ListViewItem key/value pairs, and link them to selection events at run-time?

You might immediately think of creating custom classes that inherit from TreeView and ListView with overridden methods, but because you can't inherit from important items such as TreeNodeCollection, you'd have to begin casting to use custom Nodes or ListViewItems in the methods you didn't override.

I strongly encourage you to forget that route unless you are a rodeo champion of such fancy overriding—with a library of already-well-tested code to draw from. Alternatively, you could load the dictionaries from DataSets or XML files, from which you would construct the TreeView Nodes and ListView ListViewItems dynamically. Or perhaps with some applications, you might want to give your users the ability to create/edit/delete entries on the fly.

This article has sufficient time and space to examine only a simple example of the mechanics of creating new entries. Look at the code for the Click event-handler of the makeNewItemBtn below:

   private int nodeCount = 0;
   private void makeNewItemBtn_Click(object sender, EventArgs e)
      currentNode = new TreeNode();
      currentNode.Text = "Item " + nodeCount.ToString();
      currentLVI = new ListViewItem();
      currentLVI.Text = currentNode.Text;
      nodeDictionary.Add(currentNode, currentLVI);
      LVIDictionary.Add(currentLVI, currentNode);
      // foreach (TreeNode theNode in nodeDictionary.Keys)
      // {
      //    Console.WriteLine(theNode.Text);
      // }
The commented-out code in the preceding example shows foreach iteration over the current Keys collection in the nodeDictionary, writing the Text property value of each key to the console. Using such code, you can easily synchronize the current selection in ListView and TreeView by defining an AfterSelect event-handler for the TreeView, and an ItemActivate handler for the ListView:

   private void tv1_AfterSelect(object sender, TreeViewEventArgs e)
      nodeDictionary[tv1.SelectedNode].Selected = true;
   // note : if you use SelectedIndexChanged instead
   // you'll have to handle the case of SelectedItems being 
   // set to null when the ListView loses focus ...
   // note : ItemActivate seems a little "sluggish" compared to 
   // SelectedIndexChanged at run-time !
   private void lv1_ItemActivate(object sender, EventArgs e)
      tv1.SelectedNode = LVIDictionary[lv1.SelectedItems[0]];
While this example is very simple, because it adds only one pair of TreeNode/ListViewItem at a time, you can easily envision more complex versions that, might, for example, synchronize ListViewItems with TreeNodes at different levels of the TreeView structure, or that base synchronization on some ordering principle other than linear sequence.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date