Hi Ginny!
You are lucky, I have found out that most of the trouble started when I
began to delete objects in the list. Especially when deleting the last
object. But finally I got it all working as well.
The declarations of the controls databinding is done in the following way:
m_lst = new ArrayList(); // List of all objects of type MyClass
this.cmbBoxItems.DisplayMember = "ID"; // Main combobox - ID is a property
of MyClass
this.cmbBoxItems.DataSource = m_lst; // Uses m_lst as datasource
// Child controls only displaying the data for each object selected in the
combobox
this.txtId.DataBindings.Add(new Binding("Text", m_lst, "ID"));
this.txtDesc.DataBindings.Add(new Binding("Text", m_lst, "Description"));
Description is a property of MyClass
this.comboBox1.DataBindings.Add(new Binding("Text", m_lst, "ID"));
this.comboBox2.DataBindings.Add(new Binding("Text", m_lst,
"Description"));
Is this the correct way of binding your datasource and child-controls??
I find it somewhat "magical" how the child-controls "know" which object in
m_lst is the one selected in the main combobox as the databindings doesn't
connect anything to the main combobox... do you have an answer for this?
The extra textboxes and comboboxes could of course contain data of other
fields than ID and Description.
There are also a few things I have noticed:
1. Must create object in list before adding databindings
Before I can add databindings to the controls, and bind the cmbbox to the
ArrayList I need atleast 1 object in the list. I solve this by adding the
databinding after the first object is added to the list. This may not be
so strange, the binding need to know the object it binds to in the list,
but still annoying
2. If all objects are removed from the list, databindings must be removed
before the list is cleared.
If I remove the last object in the list I need to call
DataBindings.Clear() on the controls bound to the list before I clear it.
I can't call the DataBindings.Clear() method after the list is emptied,
which I need to do in order to re-enable databinding when objects are
added again. It also seems like the last object in the Main combobox isn't
removed (see 3.)
3. Removing the last objects imposes a slight delay.
When the main ComboBox's DataSource property is set to a empty list there
seem to be a slight (but annoying) delay. I reset the DataSource by
setting it to null, and then pointing it back to the updated list
(removed/added/changed object in it). However it seems
like setting the DataSource to null doesn't clear the ComboBox's item
list. I solved this by manually clearing the combobox instead of setting
the datasource to the empty ArrayList to circumvent the annoying delay.
Since you never delete objects I suppose you never really noticed these
things. But could be good to know for future projects!
regards,
Peter
Here's the source for my test application if anyone would be interested:
using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Data;
namespace ComboBoxArrayListBindingTest
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
#region Members
private System.Windows.Forms.Button btnAdd;
private System.Windows.Forms.Button btnDelete;
private System.Windows.Forms.ComboBox cmbBoxItems;
private System.Windows.Forms.TextBox txtId;
private System.Windows.Forms.TextBox txtDesc;
private System.Windows.Forms.Button btnChange;
private System.Windows.Forms.MainMenu mainMenu1;
private System.Windows.Forms.ComboBox comboBox1;
private System.Windows.Forms.ComboBox comboBox2;
ArrayList m_lst;
string strDisplayMember = "ID";
#endregion
#region Constructor & Disposer
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
m_lst = new ArrayList();
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
base.Dispose( disposing );
}
#endregion
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.mainMenu1 = new System.Windows.Forms.MainMenu();
this.btnAdd = new System.Windows.Forms.Button();
this.cmbBoxItems = new System.Windows.Forms.ComboBox();
this.btnDelete = new System.Windows.Forms.Button();
this.txtId = new System.Windows.Forms.TextBox();
this.txtDesc = new System.Windows.Forms.TextBox();
this.btnChange = new System.Windows.Forms.Button();
this.comboBox1 = new System.Windows.Forms.ComboBox();
this.comboBox2 = new System.Windows.Forms.ComboBox();
//
// btnAdd
//
this.btnAdd.Location = new System.Drawing.Point(20, 176);
this.btnAdd.Size = new System.Drawing.Size(64, 20);
this.btnAdd.Text = "Add";
this.btnAdd.Click += new System.EventHandler(this.btnAdd_Click);
//
// cmbBoxItems
//
this.cmbBoxItems.Location = new System.Drawing.Point(40, 32);
this.cmbBoxItems.Size = new System.Drawing.Size(140, 21);
//
// btnDelete
//
this.btnDelete.Location = new System.Drawing.Point(164, 176);
this.btnDelete.Size = new System.Drawing.Size(64, 20);
this.btnDelete.Text = "Delete";
this.btnDelete.Click += new System.EventHandler(this.btnDelete_Click);
//
// txtId
//
this.txtId.Location = new System.Drawing.Point(40, 72);
this.txtId.Text = "ID";
//
// txtDesc
//
this.txtDesc.Location = new System.Drawing.Point(40, 96);
this.txtDesc.Size = new System.Drawing.Size(184, 20);
this.txtDesc.Text = "Description";
//
// btnChange
//
this.btnChange.Location = new System.Drawing.Point(92, 176);
this.btnChange.Size = new System.Drawing.Size(64, 20);
this.btnChange.Text = "Change";
this.btnChange.Click += new System.EventHandler(this.btnChange_Click);
//
// comboBox1
//
this.comboBox1.Items.Add("001");
this.comboBox1.Items.Add("002");
this.comboBox1.Items.Add("003");
this.comboBox1.Items.Add("004");
this.comboBox1.Items.Add("005");
this.comboBox1.Items.Add("006");
this.comboBox1.Items.Add("007");
this.comboBox1.Items.Add("008");
this.comboBox1.Location = new System.Drawing.Point(40, 124);
this.comboBox1.Size = new System.Drawing.Size(188, 21);
//
// comboBox2
//
this.comboBox2.Items.Add("Detta är objekt 1");
this.comboBox2.Items.Add("Detta är objekt 2");
this.comboBox2.Items.Add("Detta är objekt 3");
this.comboBox2.Items.Add("Detta är objekt 4");
this.comboBox2.Items.Add("Detta är objekt 5");
this.comboBox2.Items.Add("Detta är objekt 6");
this.comboBox2.Items.Add("Detta är objekt 7");
this.comboBox2.Items.Add("Detta är objekt 8");
this.comboBox2.Location = new System.Drawing.Point(40, 148);
this.comboBox2.Size = new System.Drawing.Size(188, 21);
//
// Form1
//
this.Controls.Add(this.comboBox2);
this.Controls.Add(this.comboBox1);
this.Controls.Add(this.btnChange);
this.Controls.Add(this.txtDesc);
this.Controls.Add(this.txtId);
this.Controls.Add(this.btnDelete);
this.Controls.Add(this.cmbBoxItems);
this.Controls.Add(this.btnAdd);
this.Menu = this.mainMenu1;
this.Text = "Form1";
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
Application.Run(new Form1());
}
#region Main Methods
private void AddObject()
{
int iNewId;
string strNewId;
if( m_lst.Count == 0 )
{
iNewId = 1;
strNewId = "001";
}
else
{
iNewId = int.Parse(((MyClass)m_lst[m_lst.Count-1]).ID) + 1;
strNewId = iNewId.ToString().PadLeft(3, '0');
}
MyClass mc = new MyClass();
mc.ID = strNewId;
mc.Description = "Detta är objekt " + iNewId.ToString();
m_lst.Add(mc);
if( m_lst.Count == 1 ) // First object added
{
// We need to add databindings
AddBindings();
}
ResetDataSource( this.cmbBoxItems, this.m_lst, strDisplayMember);
// Select the last(new) object
this.cmbBoxItems.SelectedIndex = this.cmbBoxItems.Items.Count - 1;
}
private void DeleteObject()
{
DisableButtons();
int indx = cmbBoxItems.SelectedIndex;
if( indx != -1 ) // List not empty
{
MyClass mc = (MyClass)cmbBoxItems.SelectedItem;
if( cmbBoxItems.Items.Count == 1 ) //Last object
{
// Must remove bindings before we remove last item
RemoveBindings();
m_lst.Remove( mc );
ResetDataSource( this.cmbBoxItems, this.m_lst, strDisplayMember);
this.txtId.Text = string.Empty;
this.txtDesc.Text = string.Empty;
this.comboBox1.SelectedIndex = -1;
this.comboBox2.SelectedIndex = -1;
}
else if( indx == 0 ) //First obj
{
m_lst.Remove( mc );
ResetDataSource( this.cmbBoxItems, this.m_lst, strDisplayMember);
mc = (MyClass)cmbBoxItems.SelectedItem;
this.txtId.Text = mc.ID;
this.txtDesc.Text = mc.Description;
}
else
{
cmbBoxItems.SelectedIndex--;
m_lst.Remove( mc );
ResetDataSource( this.cmbBoxItems, this.m_lst, strDisplayMember);
}
}
EnableButtons();
}
private void SaveObject()
{
if( this.cmbBoxItems.SelectedIndex != -1 )
{
DisableButtons();
MyClass mc = (MyClass)cmbBoxItems.SelectedItem;
mc.ID = this.txtId.Text;
mc.Description = this.txtDesc.Text;
ResetDataSource( this.cmbBoxItems, this.m_lst, strDisplayMember);
EnableButtons();
}
}
private void ResetDataSource( ComboBox cbx, IList lst, string strDispMem )
{
// As ArrayList doesn't implement IBindingList it doesn't propagate
// changes to the controls that is bound to it. We need to reset the
// combobox DataSource property for each change to the list.
cbx.Visible = false; // No flickering please
cbx.DataSource = null;
if( lst.Count != 0 )
{
cbx.DisplayMember = strDispMem;
cbx.DataSource = lst;
}
else
cbx.Items.Clear(); // Force manual clearing of list
cbx.Visible = true;
}
private void AddBindings()
{
this.txtId.DataBindings.Add(new Binding("Text", m_lst, "ID"));
this.txtDesc.DataBindings.Add(new Binding("Text", m_lst, "Description"));
this.comboBox1.DataBindings.Add(new Binding("Text", m_lst, "ID"));
this.comboBox2.DataBindings.Add(new Binding("Text", m_lst,
"Description"));
}
private void RemoveBindings()
{
this.txtId.DataBindings.Clear();
this.txtDesc.DataBindings.Clear();
this.comboBox1.DataBindings.Clear();
this.comboBox2.DataBindings.Clear();
}
private void DisableButtons()
{
this.btnAdd.Enabled = false;
this.btnChange.Enabled = false;
this.btnDelete.Enabled = false;
}
private void EnableButtons()
{
this.btnAdd.Enabled = true;
this.btnChange.Enabled = true;
this.btnDelete.Enabled = true;
}
#endregion
#region EventHandlers
private void btnAdd_Click(object sender, System.EventArgs e)
{
DisableButtons();
AddObject();
EnableButtons();
}
private void btnDelete_Click(object sender, System.EventArgs e)
{
DeleteObject();
}
private void btnChange_Click(object sender, System.EventArgs e)
{
SaveObject();
}
#endregion
}
public class MyClass
{
string m_id;
string m_desc;
public string ID
{
get{ return m_id; }
set{ m_id = value; }
}
public string Description
{
get{ return m_desc; }
set{ m_desc = value; }
}
}
}