Using CollectionBase and DictionaryBase






4.47/5 (32 votes)
Jun 21, 2003
4 min read

173357

2159
An article on deriving from CollectionBase and DictionaryBase in order to data bind to controls and access data in an easier manner.
Introduction
I'm sure we've all used .NET's collections and dictionaries before in our code. Anyone who has used ADO.NET definitely has. Isn't it nice to write something like
dataSet.Tables[0].Rows[0]["FieldName"];
and access the fieldname of your choice? Recently, while designing a new system for work, my team decided to implement this type of functionality in our class design. We wanted to be able to use code like
phoneNumbers["Fax"] = userInput.Text;
and be able to databind to our own classes. This article will show you how easy it is to implement this type of functionality.
Background
This article assumes an intermediate grasp of C#. I am not going to explain the get and set of properties, or the theory of OOP. If anyone needs further clarification of something I do not explain, feel free to email me or post a question below the article.
In order to data bind to a control, you must implement ICollection
and IEnumerable
. While it is not difficult to do this, it does involve the need to write several more functions than we do in this demonstration. By deriving your class from CollectionBase
, you are automatically implementing ICollection
and IEnumerable
.
Using the code
This is not code to really use, it is an example of how to create your own code to take advantage of .NET's Collections.
What are we trying to do?
We want to be able to have a class (in this example, PhoneNumber
) and create multiple instances of that class in a collection. We would like to be able to bind this collection of objects to a bind-able control and also iterate through the collection. It would also be nice if we could access certain items by a textual name, rather than number. Let's start by creating our class.
public class PhoneNumber
{
private string m_PhoneNumber = "";
private string m_Type = "";
public PhoneNumber(string phoneType, string phoneNumber)
{
m_PhoneNumber = phoneNumber;
m_Type = phoneType;
}
public string Number
{
get {return m_PhoneNumber;}
set {m_PhoneNumber = value;}
}
public string Type
{
get {return m_Type;}
set {m_Type = value;}
}
}
Pretty basic class. We have a PhoneNumber
class which contains internal variables to track the phone number (in string format) and the type. The constructor accepts two strings, Type
and PhoneNumber
. There are two properties which return these variables.
How do we DataBind
In order to bind a collection of our PhoneNumber
class, we must implement ICollection
and IEnumerable
interfaces. This is not hard to do, but there is an easier way. We create a class that derives from CollectionBase
, which does the implementation for us.
//derive from CollectionBase in order to implement
//ICollection and IEnumerable
public class PhoneNumberCollection : CollectionBase
{
//strongly typed accessor
public PhoneNumber this[int index]
{
get
{
//we must cast our return object as PhoneNumber
return (PhoneNumber) this.List[index];
}
set
{
//warning, this is not for adding, but for reassigning
//this will throw an exception if the index does not already
//exist. Use Add(phoneNumber) to add to collection
this.List[index] = value;
}
}
//add a phone number to the collection
public void Add(PhoneNumber phoneNumber)
{
this.List.Add(phoneNumber);
}
}
The above two classes are in PhoneNumber.cs. What does this class provide us? The ability to bind a collection to any .NET control that supports data binding. Here is an example...
I just typed "Home" in Phone Type and the number in Phone Number, clicked Add, then added another number called "Work". The button Bind Collection and my list appears in the DataGrid
. How much code did this take? 4 lines! Well, 5 counting the variable declaration. Here is the code from Form1.cs.
//this is declared as a class level variable
PhoneNumberCollection m_PhoneCollection = null;
public Form1()
{
InitializeComponent();
//create our Phone Number Collection
m_PhoneCollection = new PhoneNumberCollection();
//this will be used later
m_PhoneDict = new PhoneNumberDictionary();
}
private void btnAdd_Click(object sender, System.EventArgs e)
{
//create a PhoneNumber object w/ entered information
PhoneNumber phone = new PhoneNumber(txtType.Text, txtNumber.Text);
//add it to the collection
m_PhoneCollection.Add(phone);
}
private void btnList_Click(object sender, System.EventArgs e)
{
//bind the collection to datasource
gridPhoneList.DataSource = m_PhoneCollection;
}
I have not implemented it with this example, but you can also foreach
over the collection.
foreach (PhoneNumber phone in m_PhoneCollection)
{
//do something w/ phone
Console.Write(phone.Type);
}
The really fun stuff
DictionaryBase
is a very powerful base class. By deriving from it, we are able to access items in the collection by a string, rather than an integer. Would your users prefer to see Phone Number 1 or Fax Number? In order to use a dictionary, we must derive from DictionaryBase
.(This also appears in PhoneNumber.cs).
public class PhoneNumberDictionary : DictionaryBase
{
//strongly typed access by string key
public PhoneNumber this[string key]
{
get {return (PhoneNumber) this.Dictionary[key]; }
set { this.Dictionary[key] = value; }
}
//add a phone number based on key
public void Add(string key, PhoneNumber phoneNumber)
{
this.Dictionary.Add(key, phoneNumber);
}
//see if collection contains an entry corresponding to key
public bool Contains(string key)
{
return this.Dictionary.Contains(key);
}
//we will get to this later
public ICollection Keys
{
get {return this.Dictionary.Keys;}
}
}
How do we use this class? We create an instance of the class, then use the Add
function to add the entries. We are going to build on our btnAdd_Click
and btnList_Click
events above.
//declare an instance of dictionary class
PhoneNumberDictionary m_PhoneDict = null;
private void btnAdd_Click(object sender, System.EventArgs e)
{
PhoneNumber phone = new PhoneNumber(txtType.Text, txtNumber.Text);
m_PhoneCollection.Add(phone);
//add the number to our dictionary and use the type as the key
m_PhoneDict.Add(phone.Type, phone);
}
private void btnList_Click(object sender, System.EventArgs e)
{
gridPhoneList.DataSource = m_PhoneCollection;
//there appears to be a bug w/ WinForms data binding. In Web forms, you
//can simple call
//cbTypes.DataSource = m_PhoneDict.Keys;
//cbTypes.DataBind();
//so we'll work around by iterating through the DictionaryEntries
//in our Phone Dictionary
foreach (DictionaryEntry de in m_PhoneDict)
{
cbTypes.Items.Add(de.Key);
}
}
As mentioned in the comments, the Keys
property does not bind with the ComboBox
in WinForms. If you are using Web forms (as I do 99% of the time), this will work flawlessly. We overcome this problem by iterating (using foreach
) over the Keys
collection and adding them manually to the combo box. Note that the Keys
collection returns a DictionaryEntry
type. DictionaryEntry
contains two properties that we are concerned about, Key
and Value
. If we accessed the Value
above, we would have the phone number. In our sample application, we have done nothing more than we did before (adding 2 numbers) and we can drop down the Type combo box and we see our 2 types listed there.
By selecting "Home", we see our home number appear in the Phone Number text box.
Here is the code to implement our drop down change event.
private void cbTypes_SelectedIndexChanged(object sender, System.EventArgs e)
{
//get the phone number object stored in collection based on
//text in ComboBox selected item
PhoneNumber phone = m_PhoneDict[cbTypes.SelectedItem.ToString()];
//show it to user
txtResult.Text = phone.Number;
}
That's pretty much it. Collections
and Dictionaries
are very powerful programming tools. One thing to consider, this may be overkill for a one-off application, but my team is using them because we are developing classes that will be used in multiple applications for some time to come.
Points of interest
This was an interesting exploration of the .NET framework. I knew what I wanted to do, based on seeing similar ways of accessing information in the framework. I saw quite a few examples of implementing IEnumerable
and ICollection
, and was going that route when a friend of mine told me about the CollectionBase
class (Thank, Chris!). I used it, and upon further inspection, found the DictionaryBase
class.
History
This is the first version of the article.