动态设置 DataGridViewComboBoxCell 的数据源为基于其他单元格选择筛选的 DataView



我一直在寻找执行以下操作的方法,但无济于事。我想出了一个有效的解决方案,但我想知道是否有更好的处理方法。

问题:

我正在使用具有两个DataGridViewComboBoxColumn,col1和col2的DataGridView。

col1 已将其数据源设置为数据表。根据从 col1 中的给定单元格中选择的内容,我希望将同一行中相应的 col2 单元格的数据源设置为col2 数据源的过滤数据视图。

我当前实现的缩写代码可能更好地帮助描述我正在尝试做的事情:

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;
}
}

最后一部分是我关心的问题。 动态切换 cell2 的数据源时,如果 cell2 的当前选择未出现在新的数据视图中,则会引发异常:

System.ArgumentException: DataGridViewComboBoxCell 值无效。

为了避免这种情况,我将数据源设置为宏数据表(包含可以根据单元格 1 的选择显示的所有值),将单元格 2 的选定值更改为 DataView 中的第一个结果,然后将单元格 2 的数据源设置为表示 DataView。这一切都确保单元格永远不会有无效的选择,并且它按预期工作。

我的问题是,有没有更好/更简单的方法?供我使用,此代码仅在创建新行时激活,因此在给定形式中不会多次执行。但是,如果有更好的方法或一些改进它的建议,我将不胜感激!

(这里的第一个问题,所以我也愿意接受发布的建议......对任何失误表示歉意)

编辑(提供表格结构 - 还将"BoundID"更改为"ID1"以避免混淆):

DataGrid 的表结构为:

MainTableID int

ID1 int --这是 col1 的外键

ID2 int --这是 col2 的外键

第 1 列的表结构:

ID1 整数

显示1 瓦尔查尔(50)

第 2 列的表结构:

ID2 整型

显示2 瓦尔查尔(50)

ID1 int --这是 col1 的外键

更新:我根据Mohsen的建议重新定义了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);
}
}

这似乎很完美。

您的代码可以简化为这样,没有异常抛出:

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;
cell.DataSource = ((DataTable)((DataGridViewComboBoxColumn)dgv.Columns[e.ColumnIndex + 1]).DataSource).Select("BoundID = " + dgv.CurrentCell.Value);                
}

更新

当您更改第一个组合框中已设置的项目时,因为第二个组合框中过滤的数据视图具有不同的ID1,将引发异常并显示">DataGridViewComboBoxCell 值无效"。为了捕获此异常,请在注册的方法中注册 datagridviewDataError没有代码的事件。然后,当您更改已设置的梳状框时,相应的组合框将填充正确的项目。

这是对我有用的解决方案的快速停止商店,但我仍然想把功劳归功于 Mohsen。在原始问题中重复了这一点。

我已经根据Mohsen的建议重新定义了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);
}
}

这似乎很完美。

相关内容

  • 没有找到相关文章

最新更新