Click here to Skip to main content
15,881,812 members
Articles / Programming Languages / C#
Article

Using CollectionBase and DictionaryBase

Rate me:
Please Sign up or sign in to vote.
4.48/5 (33 votes)
20 Jun 20034 min read 172K   2.2K   86   17
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

C#
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

C#
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.

C#
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.

C#
//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.

C#
//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.

C#
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).

C#
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.

C#
//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.

C#
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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
I am currently a .NET (C# and ASP) programmer. I've been working professionaly with .NET since Beta 2. In my past, I have worked with Clipper, Delphi, VB, C and mostly, C++ (both Borland and MS).

Comments and Discussions

 
QuestionUpdates on Collection don't show up in DataGrid Pin
violiance30-Sep-10 3:59
violiance30-Sep-10 3:59 
AnswerRe: Updates on Collection don't show up in DataGrid Pin
Helen.Yu29-Jun-11 22:12
Helen.Yu29-Jun-11 22:12 
JokeThanks Pin
violiance17-Sep-10 20:23
violiance17-Sep-10 20:23 
General[Message Deleted] Pin
it.ragester28-Mar-09 5:47
it.ragester28-Mar-09 5:47 
QuestionI have a small doubt on CollectionBase Pin
asmysee19-Apr-06 18:52
asmysee19-Apr-06 18:52 
AnswerRe: I have a small doubt on CollectionBase Pin
Bahadir Cambel26-Apr-06 12:02
Bahadir Cambel26-Apr-06 12:02 
QuestionRe: I have a small doubt on CollectionBase Pin
auxcom28-Apr-07 18:21
auxcom28-Apr-07 18:21 
GeneralVery Nice Article Pin
dl4gbe20-Mar-06 0:39
dl4gbe20-Mar-06 0:39 
GeneralAbout headertext!!! Pin
Anonymous29-Dec-03 14:30
Anonymous29-Dec-03 14:30 
GeneralRe: About headertext!!! Pin
jeff_martin30-Dec-03 3:37
jeff_martin30-Dec-03 3:37 
GeneralGrid does not display all items Pin
TurnSomePages17-Jul-03 0:26
TurnSomePages17-Jul-03 0:26 
GeneralRe: Grid does not display all items Pin
jeff_martin17-Jul-03 8:50
jeff_martin17-Jul-03 8:50 
GeneralTypedCollectionGenerator Pin
leppie21-Jun-03 23:42
leppie21-Jun-03 23:42 
GeneralRe: TypedCollectionGenerator Pin
Jeff Martin22-Jun-03 4:59
Jeff Martin22-Jun-03 4:59 
GeneralRe: TypedCollectionGenerator Pin
leppie22-Jun-03 5:41
leppie22-Jun-03 5:41 
GeneralRe: TypedCollectionGenerator Pin
mikasa23-Jun-03 2:49
mikasa23-Jun-03 2:49 
GeneralRe: TypedCollectionGenerator Pin
leppie23-Jun-03 7:04
leppie23-Jun-03 7:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.