我一直在尋找一種方式來做到以下幾點,但無濟於事。我提出了一個可行的解決方案,但我想知道是否有更好的方法來處理它。動態設置DataGridViewComboBoxCell的DataSource過濾DataView基於其他單元格選擇
問題:
我使用的是有兩個DataGridViewComboBoxColumn,col1和COL2一個DataGridView。
col1已將其DataSource設置爲DataTable。根據col1中給定單元格的選擇,我想讓同一行中的相應col2單元格將其DataSource設置爲col2的DataSource的過濾DataView。
從我目前執行的縮寫代碼可以更好地幫助說明什麼,我試圖做的:
DataGridView dg = new DataGridView();
dg.DataSource = new BindingSource() { DataSource = _myDataTable }; //DataTable with Foreign Keys for ID1 and ID2
dg.CellValueChanged += new DataGridViewCellEventHandler(dg_CellValueChanged);
DataGridViewComboBoxColumn col1 = new DataGridViewComboBoxColumn();
col1.DataPropertyName = "ID1";
col1.DisplayMember = "Display1";
col1.ValueMember = "ID1";
col1.DataSource = dataTable1;
col1.ValueType = typeof(Int32);
DataGridViewComboBoxColumn col2 = new DataGridViewComboBoxColumn();
col2.DataPropertyName = "ID2";
col2.DisplayMember = "Display2";
col2.ValueMember = "ID2";
col2.DataSource = dataTable2;
col2.ValueType = typeof(Int32);
dg.Columns.Add(col1);
dg.Columns.Add(col2);
然後我定義事件處理程序爲:
private void dg_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 0 && e.RowIndex > -1)
{
var dgv = sender as DataGridView;
if (dgv == null)
return;
int selectedID;
if (!int.TryParse(dgv[e.ColumnIndex, e.RowIndex].Value.ToString(), out selectedID))
return;
var cell = dgv[e.ColumnIndex + 1, e.RowIndex] as DataGridViewComboBoxCell;
if (cell == null)
return;
var col = dgv.Columns[e.ColumnIndex + 1] as DataGridViewComboBoxColumn;
if(col == null)
return;
var dt = col.DataSource as DataTable; // The macro-DataTable containing all possible values
if(dt == null)
return;
DataView dv = new DataView(dt, "ID1 = " + selectedID, "DisplayOrder", DataViewRowState.CurrentRows);
if(dv.Count == 0)
return;
//This is the part that I am wondering if there is a better way of handling
cell.DataSource = dt; //Set the data source to the macro-DataTable so that when we set the Value to something in the new DataView it will not throw an exception
cell.DisplayMember = "Display2"; // Have to redefine the Display/Value members
cell.ValueMember = "ID2";
cell.Value = dv[0]["ID2"]; // Set the value to the first option in the new DataView to avoid an exception being thrown when setting the dv as the DataSource
cell.DataSource = dv;
}
}
最後一部分是我所關注。 當動態切換小區2的數據源,如果小區2的當前選擇不會在新的數據視圖出現,那麼將引發異常:
System.ArgumentException:值的DataGridViewComboBoxCell無效。
爲了避免這種情況,我將數據源設置爲宏DataTable(包含可以基於cell1的選擇顯示的所有值),將cell2的選定值更改爲DataView中的第一個結果然後將cell2的DataSource設置爲DataView。這一切都可以確保單元格永遠不會有無效的選擇,並且按預期工作。
我的問題是,有沒有更好/更簡單的方法呢?就我的使用而言,只有在創建新行時纔會激活此代碼,因此在給定表單中這些代碼的執行時間不會超過幾次。但是,如果有更好的方法來實現它,或者提出更好的建議,我將不勝感激!
(這裏第一個問題,所以我也開放的建議張貼...對於任何失誤道歉)
EDIT(提供表結構 - 也改變了 「BoundID」 是 「ID1」,以避免混淆):
DataGrid的表結構將是:
MainTableID INT
ID1 INT - 這是一個外鍵COL1
ID2 INT - 這是一個外鍵COL2
色譜柱1的表結構:
ID1 INT
Display1 VARCHAR(50)
第2列的表結構:
ID2 INT
顯示2 VARCHAR(50)
ID1 INT - 這是一個外鍵COL1
更新時間: 我重新定義了每穆赫辛的建議的CellValueChanged事件處理程序:
private void dg_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 0 && e.RowIndex > -1)
{
var dgv = sender as DataGridView;
var cell = dgv[e.ColumnIndex + 1, e.RowIndex] as DataGridViewComboBoxCell;
if (cell == null)
return;
DataView dv = new DataView(((DataTable)((DataGridViewComboBoxColumn)dgv.Columns[e.ColumnIndex + 1]).DataSource), "ID1 = " + dgv.CurrentCell.Value, "DisplayOrder", DataViewRowState.CurrentRows);
if(dv.Count == 0)
return;
cell.DisplayMember = "Display2"; // Have to redefine the Display/Value members
cell.ValueMember = "ID2";
cell.DataSource = dv;
}
}
我已經添加了DataError的事件處理程序,就像他建議的那樣:
void dg_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
if(e.ColumnIndex != 1)
{
//Alert the user for any other DataError's outside of the column I care about
MessageBox.Show("The following exception was encountered: " + e.Exception);
}
}
這似乎很好地工作。
感謝您的回覆。 當我使用上面的代碼,它似乎清除displaymember和valuemember作爲下拉結束,只是顯示** System.Data.DataRow **它返回的所有項目。 此外,如果我嘗試再次設置displaymember和valuemember,則會發生異常:**名爲Display2的字段不存在** – Smitty
您能提供數據庫表的圖嗎?此外,請不要爲列設置DataPropertyName –
道歉,我以前沒有指出DataGridView使用BindingSource作爲DataSource(這就是爲什麼使用DataPropertyName)的原因。 我已經根據您的要求添加了表格結構。 – Smitty