Tim Van Wassenhove

Passionate geek, interested in Technology. Proud father of two

10 Sep 2006

Implementing Master/Detail for Custom Objects with DataGridViewComboBoxColumns

Imagine you have the following two classes

public class Parent 
{
	private int id;
	private string name;

	public Parent( int id, string name ) 
	{
		this.id = id;
		this.name = name;
	}

	public int Id 
	{
		get { return this.id; }
	}

	public string Name 
	{
		get { return this.name; }
	}
}

public class Child : Parent 
{
	private int parentId;

	public Child( int id, int parentId, string name ) : base( id, name ) 
	{
		this.parentId = parentId;
	}

	public int ParentId 
	{
		get { return this.parentId; }
	}
}

In the first ComboBoxColumn you display a list of possible Parents. In the second ComboBoxColumn you display Children, but only those that belong to the Chosen Parent. Here is how it goes

public partial class Form1 : Form 
{
	private Object selectedValue;

	public Form1() 
	{
		InitializeComponent();

		// Add a couple of Parents
		for ( int i = 0; i < 3; ++i ) 
		{ 
			Parent parent = new Parent( i, String.Format( "Parent{0:00}", i ) ); 
			this.Column1.Items.Add( parent ); 
			// Add a couple of Children to each parent 
			for ( int j = 0; j < 5; ++j ) 
			{ 
				Child child = new Child( j, i, String.Format( "Child{0:00}", i * 10 + j ) ); 
				this.Column2.Items.Add( child ); 
			} 
		} 
		this.Column1.DisplayMember = "Name"; 
		this.Column2.DisplayMember = "Name"; 
	} 
	
	private void dataGridView1_CellParsing( object sender, DataGridViewCellParsingEventArgs e ) 
	{ 
		e.Value = this.selectedValue; 
		e.ParsingApplied = true; 
	} 
	
	private void dataGridView1_EditingControlShowing( object sender, DataGridViewEditingControlShowingEventArgs e ) 
	{ 
		ComboBox cb = e.Control as ComboBox; 
		if ( cb != null ) 
		{ 
			// remove all the children that do not belong to the choosen parent 
			int currentColumnIndex = this.dataGridView1.CurrentCell.ColumnIndex; 
			if ( currentColumnIndex == 1 ) 
			{ 
				cb.Items.Clear(); 
				int currentRowIndex = this.dataGridView1.CurrentCell.RowIndex; 
				Object currentCellValue = this.dataGridView1.Rows[currentRowIndex].Cells[0].Value; 
				if ( currentCellValue != null ) 
				{ 
					int parentId = ( (Parent)currentCellValue ).Id; 
					foreach ( Child child in this.Column2.Items ) 
					{ 
						if ( child.ParentId == parentId ) 
						{ 
							cb.Items.Add( child ); 
						} 
					} 
				} 
			} 
			cb.SelectedIndexChanged -= cb_SelectedIndexChanged; 
			cb.SelectedIndexChanged += cb_SelectedIndexChanged; 
		} 
		
		void cb_SelectedIndexChanged(object sender, EventArgs e) 
		{ 
			ComboBox comboBox = sender as ComboBox; 
			this.selectedValue = comboBox.SelectedItem; 
		} 
	}
}