use generic collection as datasource?

I have a generic dictionary of my custom class and want to use it as a listbox datasource. Is this possible?
Actually, I don't really have to use it as a datasource if this is not possible. My custom class is an item in a listbox and combobox. If I change the description property in my class, how do I get the listbox and combobox to update (the tostring method returns the description)?
[393 byte] By [Zaph0d] at [2008-2-8]
# 1

Sort of - you'll need to bind it through a BindingSource. You can then set the ComboBox DisplayMember to "Value" and the ComboBox ValueMember to "Key".

Joe


Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("Foo", "Bar");
dict.Add("Bar", "Foo");

BindingSource bs = new BindingSource();
bs.DataSource = dict;

this.comboBox1.DataSource = bs;
this.comboBox1.DisplayMember = "Value";
this.comboBox1.ValueMember = "Key";

JoeStegman at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...
# 2
I wrote the following but get an exception in the selectedIndexValue changed event where I try to cast the SelectedItem/SelectedValue to MyClass and it fails. Shouldn't SelectedValue be of type MyClass?


BindingSource
bs = new BindingSource();

bs.DataSource = myclasses; //Dictionary<int, MyClass>

lstDataviews.DataSource = bs;

lstDataviews.DisplayMember = "Value"; //want to use the MyClass.ToString()

lstDataviews.ValueMember = "Value"; //want to access the whole MyClass object

Zaph0d at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...
# 3
SelectedItem will be a KeyValuePair<int, MyClass>. The KeyValuePair is not bindable in Beta 2, so you won't be able to get this to work (it is bindable post Beta 2).

In Beta 2, you can do what you're the above in an untyped way using a DictionaryEntry and a List<DictionaryEntry>.

Joe

JoeStegman at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...
# 4
Ok, I think I have got a bit off track and have been asking the wrong questions. Here is an example of what I want to do:


using System;

using System.Collections.Generic;

using System.Windows.Forms;

namespace WindowsApplication1

{

public class MyClass

{

private int id;

private string forename;

private string surname;

public MyClass(int id, string forename, string surname)

{

this.id = id;

this.forename = forename;

this.surname = surname;

}

public int ID

{

get

{

return id;

}

set

{

id = value;

}

}

public string Forename

{

get

{

return forename;

}

set

{

forename = value;

}

}

public string Surname

{

get

{

return surname;

}

set

{

surname = value;

}

}

public override string ToString()

{

return surname + ", " + forename;

}

}

public class Form1 : Form

{

private Dictionary<int, MyClass> myClasses = new Dictionary<int, MyClass>();

private MyClass myclass = new MyClass(2, "dick", "jones");

public Form1()

{

myClasses.Add(myclass.ID, myclass);

ListBox li = new ListBox();

BindingSource bs = new BindingSource();

bs.DataSource = myClasses.Values;

li.DataSource = bs;

li.Dock = DockStyle.Fill;

this.Controls.Add(li);

Button btn = new Button();

btn.Text = "change dick to richard";

btn.Click += new EventHandler(btn_Click);

btn.Dock = DockStyle.Top;

this.Controls.Add(btn);

}

void btn_Click(object sender, EventArgs e)

{

myclass.Forename = "richard";

MessageBox.Show("Changed, but how do I reflect change in listbox?");

}

}

}




(If I add or remove an item from the dictionary, I would also like the items to be removed from the listbox)

Zaph0d at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...
# 5

OK, you need change notification on both your list and your business object - the code below should work. I sense there's more to it though...

Joe


private BindingList<MyClass> myClasses = new BindingList<MyClass>();

public Form1()
{
MyClass myclass = new MyClass(2, "dick", "jones");
ListBox li = new ListBox();
BindingSource bs = new BindingSource();
Button btn = new Button();

myClasses.Add(myclass);

bs.DataSource = myClasses;
li.DataSource = bs;
li.Dock = DockStyle.Fill;
this.Controls.Add(li);

btn.Text = "change dick to richard";
btn.Click += delegate
{
myclass.Forename = "richard";
Debug.WriteLine("Changed, but do I reflect change in listbox?");
};

btn.Dock = DockStyle.Top;
this.Controls.Add(btn);
}
}

public class MyClass : INotifyPropertyChanged
{
private int id;
private string forename;
private string surname;

public MyClass(int id, string forename, string surname)
{
this.id = id;
this.forename = forename;
this.surname = surname;
}

public int ID
{
get { return id; }
set { id = value; }
}

public string Forename
{
get { return forename; }
set
{
if (forename != value)
{
forename = value;
OnPropertyChanged("Forename");
}
}
}

public string Surname
{
get { return surname; }
set { surname = value; }
}

public override string ToString()
{
return surname + ", " + forename;
}

#region INotifyPropertyChanged Members
protected virtual void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}

protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
{
if (null != this.PropertyChanged)
{
this.PropertyChanged(this, args);
}
}

public event PropertyChangedEventHandler PropertyChanged;

#endregion
}

JoeStegman at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...
# 6
>> I sense there's more to it though...

You are right :-)

I tried the example and it works as required (thanks). Unfortunately, I think that I really did need to use the dictionary collection to efficiently find a MyClass object in the collection by id (the key). Any ideas on this?

Zaph0d at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...
# 7
Would I be better off extending BindingList<> and maybe adding FindByKey capabilities or extending Dictionary<> to allow modifications to the collection to be updated in the listbox (ie what I was talking about in my 24 May 2005, 1:09 PM post)?

Any help would be greatly appreciated.

Zaph0d at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...
# 8

The only way I know to make this work is to add a FindByKey to BindingList<T>.
I don't know how to do this with Dictionary<> given you'd need to add list change notification to Dictionary<> and property change notifcation to KeyValuePair<>.

Joe

JoeStegman at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...