根据其他 dgv 组合框选择填充 datagridview 组合框
Populate datagridview combo box based on other dgv combobox selection
我目前正在使用数据库查询中的列表填充组合框,如下所示:
private List<ExerciseAndVideo> GetExerciseVideoComboBoxListFromDB()
{
List<ExerciseAndVideo> exerciseList = new List<ExerciseAndVideo>();
con = new SqlConnection("my db path etc");
cmd = new SqlCommand();
con.Open();
cmd.Connection = con;
cmd.CommandText = "SELECT nome, link_video, gruppo_muscolare FROM Esercizi ORDER BY nome ASC";
dr = cmd.ExecuteReader();
while (dr.Read())
{
ExerciseAndVideo item = new ExerciseAndVideo();
item.Esercizio = dr.GetString(0);
item.Video = dr.GetString(1);
item.Gruppo = dr.GetString(2);
exerciseList.Add(item);
}
con.Close();
return exerciseList;
}
public class ExerciseAndVideo
{
public string Esercizio { get; set; }
public string Video { get; set; }
public string Gruppo { get; set; }
}
我现在要做的是在 dgv 中添加另一个组合框以过滤练习列表的结果。
我添加了这样的组合:
dataGridView1.Columns.Add(GetGroupComboBoxColumn(GrList));
private List<GroupList> GetGroupComboBoxListFromDB()
{
List<GroupList> GrList = new List<GroupList>();
GrList.Add(new GroupList { Gruppo = "quads" });
GrList.Add(new GroupList { Gruppo = "hamstring" });
GrList.Add(new GroupList { Gruppo = "gluteus" });
return GrList;
}
我该怎么做?
我希望在组合 1 中 select 编辑“股四头肌”时,在组合 2 中我只看到股四头肌的练习。
编辑
以下是 dgv 连击中的火爆事件:
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name == "Esercizio")
{
curCombo = e.Control as ComboBox;
if (curCombo != null)
{
curCombo.SelectedIndexChanged -= new EventHandler(curCombo_SelectedIndexChanged);
curCombo.SelectedIndexChanged += new EventHandler(curCombo_SelectedIndexChanged);
}
}
}
private void curCombo_SelectedIndexChanged(object sender, EventArgs e)
{
if (curCombo != null && curCombo.SelectedValue != null)
{
ExerciseAndVideo selectedExercise = (ExerciseAndVideo)curCombo.SelectedItem;
dataGridView1.CurrentRow.Cells["Video"].Value = selectedExercise.Video;
dataGridView1.CurrentRow.Cells["Gruppo"].Value = selectedExercise.Gruppo;
}
}
private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].Name == "Esercizio")
{
if (curCombo != null)
{
curCombo.SelectedIndexChanged -= new EventHandler(curCombo_SelectedIndexChanged);
}
}
}
这里是组合如何获取数据源:
private DataGridViewComboBoxColumn GetGroupComboBoxColumn(List<GroupList> GrList)
{
DataGridViewComboBoxColumn cbCol = new DataGridViewComboBoxColumn();
cbCol.HeaderText = "Zona";
cbCol.Name = "Zona";
cbCol.DisplayMember = "Zona";
cbCol.DataSource = GrList;
cbCol.Width = 100;
return cbCol;
}
private DataGridViewComboBoxColumn GetExcerciseComboBoxColumn(List<ExerciseAndVideo> exerciseList)
{
DataGridViewComboBoxColumn cbCol = new DataGridViewComboBoxColumn();
cbCol.HeaderText = "Esercizio";
cbCol.Name = "Esercizio";
cbCol.DisplayMember = "Esercizio";
// if I use this string works fine
string selectedGroup = "quadricipiti";
var filteredList = exerciseList.Where(x => x.Gruppo == selectedGroup).ToList();
cbCol.DataSource = filteredList;
cbCol.Width = 140;
return cbCol;
}
编辑 2
我按照建议编辑了 curCombo_SelectedIndexChanged 事件,但我在 exerciseList 上收到错误,因为函数中不存在:
private void curCombo_SelectedIndexChanged(object sender, EventArgs e)
{
if (curCombo != null && curCombo.SelectedValue != null)
{
ExerciseAndVideo selectedExercise = (ExerciseAndVideo)curCombo.SelectedItem;
dataGridView1.CurrentRow.Cells["Video"].Value = selectedExercise.Video;
dataGridView1.CurrentRow.Cells["Gruppo"].Value = selectedExercise.Gruppo;
string selectedGroup = Convert.ToString((GroupList)SelectedCombo.SelectedItem);
DataGridViewComboBoxCell Esercizi = (DataGridViewComboBoxCell)(dataGridView1.CurrentRow.Cells["Esercizi"]);
var filteredList = exerciseList.Where(x => x.Gruppo == selectedGroup).ToList();
Esercizi.DataSource = filteredList;
}
}
编辑 3
更正列表代码以使其作为全局工作后,我没有收到任何错误,但我无法从组合 1 中选择 selected 值作为 selected 组。
如果我使用像“quads”这样的字符串或其他一切正常,否则如果我尝试从组合 1 中选取值,我会在组合 2 上得到一个空白列表。
这是我尝试从组合 1 中获取值的一些代码:
string selectedGroup = Convert.ToString(dataGridView1.CurrentRow.Cells["Zona"]);
string selectedGroup = SelectedCombo.SelectedItem.ToString();
string selectedGroup = Convert.ToString((GroupList)SelectedCombo.SelectedItem);
上次编辑
这里我发现正在努力从组合 1 中获取值:
string selectedGroup = Convert.ToString(dataGridView1.CurrentRow.Cells[0].FormattedValue.ToString());
现在的问题是要使过滤器正常工作,我必须 select 组合 1 中的值的 2 倍。
因此,例如,我在组合 1 中 select“四边形”,在组合 2 中得到一个空白列表。我再次 select“四边形”,我得到过滤后的结果。
我认为问题可能出在事件中,但我没有看到错误:
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name == "Esercizio")
{
curCombo = e.Control as ComboBox;
if (curCombo != null)
{
curCombo.SelectedIndexChanged -= new EventHandler(curCombo_SelectedIndexChanged);
curCombo.SelectedIndexChanged += new EventHandler(curCombo_SelectedIndexChanged);
}
}
if (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name == "Zona")
{
curCombo = e.Control as ComboBox;
if (curCombo != null)
{
curCombo.SelectedIndexChanged -= new EventHandler(ComboBox_SelectedIndexChanged);
curCombo.SelectedIndexChanged += new EventHandler(ComboBox_SelectedIndexChanged);
}
}
}
private void curCombo_SelectedIndexChanged(object sender, EventArgs e)
{
if (curCombo != null && curCombo.SelectedValue != null)
{
ExerciseAndVideo selectedExercise = (ExerciseAndVideo)curCombo.SelectedItem;
dataGridView1.CurrentRow.Cells["Video"].Value = selectedExercise.Video;
dataGridView1.CurrentRow.Cells["Gruppo"].Value = selectedExercise.Gruppo;
}
}
private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (curCombo.SelectedValue != null)
{
string selectedGroup = Convert.ToString(dataGridView1.CurrentRow.Cells[0].FormattedValue.ToString());
DataGridViewComboBoxCell Esercizi = (DataGridViewComboBoxCell)(dataGridView1.CurrentRow.Cells["Esercizio"]);
// string selectedGroup = "femorali";
var filteredList = exerciseList.Where(x => x.Gruppo == selectedGroup).ToList();
Esercizi.DataSource = filteredList;
}
}
private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].Name == "Esercizio")
{
if (curCombo != null)
{
curCombo.SelectedIndexChanged -= new EventHandler(curCombo_SelectedIndexChanged);
}
}
if (dataGridView1.Columns[e.ColumnIndex].Name == "Zona")
{
if (curCombo != null)
{
curCombo.SelectedIndexChanged -= new EventHandler(ComboBox_SelectedIndexChanged);
}
}
}
来自长长的来回评论。我在下面有一个解决方案,应该可以像您描述的那样工作。在我开始之前,我想建议您在 post 提问时更加小心。最初当您 post 编辑这个问题时,遗漏了很多细节,可以避免您看到不必要的扩展评论。您遗漏的细节越多,其他人为理解您的问题而提出的问题越多,您的问题得到解答的机会就越小。
以后,我建议您提供所有需要的信息,当然如果需要的话,一定要编辑您的问题以添加任何相关信息。其他人为帮助您所做的工作越多,您获得任何帮助的机会就越少,更不用说得到答案了。帮自己一个忙,采取额外的步骤来确保你的问题是完全可以理解的,并且更好但可以重现……我保证你不会后悔的。
继续,鉴于下面的图片,我认为这与您 post编辑的相似。
用户可以select更改“区域”组合框项目。发生这种情况时,我们要做的是“过滤”“练习”列组合框单元格,使其仅包含 selected 区域中的练习。那么,如果用户 select 从练习组合框单元格中进行练习,那么,该练习的匹配“视频” link 将显示在该行的“视频”单元格中。希望这是正确的。
观察会导致其他一些假定的行为。
如果一行有一个 selected 区域和一个 selected 练习,并且视频单元格显示练习的视频 link……那么……如果用户更改该行的“区域”值,然后代码将清除练习和视频单元格,因为这些值不一定属于新的 selected 区域。
假设 Zone 组合框单元格为“空”……如果用户尝试 select 在为该行设置 Zone 值之前从 Exercise 组合框进行练习……那么...我们希望练习组合框不包含任何值,因为区域尚未 selected。换句话说,在用户 select 区域之前,练习组合框不会填充值。
下面的代码使用上述假设并在区域更改时清除练习和视频值,并防止用户在区域被 selected 之前 select 进行练习。
如果您创建一个新的 winform 解决方案并将 DataGridView
拖放到窗体上,您应该能够按照以下步骤逐步完成此示例。下面是一些代码和 类 以帮助测试数据和构建网格。
首先,我们将用于组合框列的两个 类。两者都简单明了。
public class ExerciseAndVideo {
public string Exercise { get; set; }
public string Video { get; set; }
public string ZoneName { get; set; }
}
public class Zone {
public string ZoneName { get; set; }
}
一些额外的代码来填充全局变量 ExerciseList
和 ZoneList
以及组合框的一些测试数据…
private void SetExerciseListFromDB() {
ExerciseList = new List<ExerciseAndVideo>();
ExerciseList.Add(new ExerciseAndVideo { Exercise = "-", ZoneName = "-", Video = "" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 1", ZoneName = "quads", Video = "Video 1" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 2", ZoneName = "gluteus", Video = "Video 2" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 3", ZoneName = "quads", Video = "Video 3" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 4", ZoneName = "hamstring", Video = "Video 4" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 5", ZoneName = "quads", Video = "Video 5" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 6", ZoneName = "hamstring", Video = "Video 6" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 7", ZoneName = "quads", Video = "Video 7" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 8", ZoneName = "gluteus", Video = "Video 8" });
}
private void SetZoneListFromDB() {
ZoneList = new List<Zone>();
ZoneList.Add(new Zone { ZoneName = "-" });
ZoneList.Add(new Zone { ZoneName = "quads" });
ZoneList.Add(new Zone { ZoneName = "hamstring" });
ZoneList.Add(new Zone { ZoneName = "gluteus" });
}
注意:在上面的代码中,您可能会注意到每个练习和区域列表都添加了一个额外的项目,用于表示用户没有选择......
ExerciseList.Add(new ExerciseAndVideo { Exercise = "-", ZoneName = "-", Video = "" });
和
ZoneList.Add(new Zone { ZoneName = "-" });
我们可以不用这些“空白”(无选择)值;但是,当 selected 不同的区域时,我们需要一种方法将练习组合框设置为某个“空白”值。您可以像列表中的第一个练习一样设置一个默认值,这样就可以了。这里的要点是,如果我们不将练习值设置为属于“过滤”练习的“过滤”版本的值……您将得到网格的 DataError
抱怨单元格中的值是在项目的组合框列表中不是有效值。
当用户“更改”区域组合框值并且练习单元格已包含先前设置的区域值中的值时,这适用。如果我们不将练习值更改为新过滤版本中的“某物”,而只是将练习值保留为旧值……那么我们将得到网格的 DataError
.
这是向练习列表添加“空白”无选择值的逻辑。当我们过滤列表时,我们会将此“空白”值添加到列表中,然后在区域更改时将练习值设置为该“空白”值。这样我们几乎可以保证我们将避免网格的 DataError
因为练习单元格中的无效值。还有其他解决方法,但是,我发现在处理彼此相关的组合框时,这种“空白”非选择值使事情变得容易得多。我希望这是有道理的。
接下来是手动设置网格列的代码,包括区域和练习组合框列。您可能需要考虑给网格一个 DataSource
…更多关于这个的最后。
private void AddColumnsToGrid() {
DataGridViewComboBoxColumn cbCol = GetComboBoxColumn("Zone", "Zone", "ZoneName", 100);
cbCol.DataSource = ZoneList;
dataGridView1.Columns.Add(cbCol);
cbCol = GetComboBoxColumn("Exercise", "Exercise", "Exercise", 140);
cbCol.DataSource = ExerciseList;
dataGridView1.Columns.Add(cbCol);
dataGridView1.Columns.Add(GetTextBoxColumn("Serie", "serie"));
dataGridView1.Columns.Add(GetTextBoxColumn("Ripetizioni", "ripetizioni"));
dataGridView1.Columns.Add(GetTextBoxColumn("Recupero", "recupero"));
dataGridView1.Columns.Add(GetTextBoxColumn("Time under tension", "tut"));
dataGridView1.Columns.Add(GetLinkColumn("Video", "Video"));
dataGridView1.Columns.Add(GetTextBoxColumn("Note", "note"));
}
private DataGridViewComboBoxColumn GetComboBoxColumn(string headertext, string name, string displayMember, int width) {
DataGridViewComboBoxColumn cbCol = new DataGridViewComboBoxColumn();
cbCol.HeaderText = headertext;
cbCol.Name = name;
cbCol.DisplayMember = displayMember;
cbCol.Width = width;
return cbCol;
}
private DataGridViewTextBoxColumn GetTextBoxColumn(string headerText, string name) {
DataGridViewTextBoxColumn col = new DataGridViewTextBoxColumn();
col.HeaderText = headerText;
col.Name = name;
return col;
}
private DataGridViewLinkColumn GetLinkColumn(string headerText, string name) {
DataGridViewLinkColumn col = new DataGridViewLinkColumn();
col.HeaderText = headerText;
col.Name = name;
return col;
}
如果我们现在 运行 代码,它会像上图一样。用户可以 select 任何区域和任何练习。 Exercise 组合框的过滤尚未实现,Video 单元格的设置也未实现。因此,无论哪个区域 selected.
,您都应该在组合框中看到所有区域和所有练习
接下来我们将在用户更改 Zone 组合框值时将“过滤”应用于 Exercise 组合框。总体方法是这样的……首先我们要创建一个全局常规 ComboBox
变量,我们将调用 CurCombo
。然后我们将连接网格的 EditingControlShowing
事件。当用户单击网格单元格并开始编辑该单元格时,将触发此事件。请记住……此事件在用户实际对单元格进行任何更改之前触发。在这种情况下,我们将查看编辑的单元格是否是区域单元格。如果编辑的单元格是区域单元格,那么……我们要做的就是将网格的组合框单元格转换为我们的全局 CurCombo
变量。这看起来像……
CurCombo = e.Control as ComboBox;
其中 e
是传入的 DataGridViewEditingControlShowingEventArgs
变量。它将允许我们将单元格转换为常规组合框。然后,我们将连接 CurCombo
的 SelectedIndexChanged
事件,然后退出并等待用户更改组合框的索引。
当用户确实更改了 Zone 组合框索引,并且组合框 SelectedIndexChanged
事件触发......那么我们就会知道我们需要根据 select编辑区。
让事情变得更复杂……如果用户更改了其中一个练习组合框,那么我们想要更新视频单元格以将 link 显示为 selected 视频。我们可以创建另一个 ComboBox
并执行与区域组合框相同的操作,但是,我们知道用户不能同时 select 两个组合框。所以我们可以对两个组合框使用相同的 CurCombo
变量。但是……我们需要确保在用户离开单元格时取消连接 CurCombo
的 SelectedIndexChanged
事件。否则,当任一组合框更改时,两个事件都将开始触发。
考虑到两个组合框都将触发网格的 EditingControlShowingEvent
事件,如果组合框是练习组合框,我们需要采取额外的步骤。在我们连接 CurCombo
的 SelectedIndexChanged
事件之前,我们要检查 Zone 组合框是否有值。如果 Zone 组合框没有值,那么我们不希望 Exercise 组合框包含除空白无选择值以外的任何值。我们希望用户先 select 一个区域。
因此,如果编辑了练习组合框并且区域组合框单元格不为空,那么我们只需连接 CurCombo
的 SelectedIndexChanged
事件以指向一个不同的事件方法,该方法将更新视频单元格,然后退出并等待用户更改锻炼值。如果区域单元格为空,那么我们将过滤练习组合框以仅包含我们的空白非选择值并且我们不会连接 CurCombo
事件,因为用户无论如何都不能 select 练习。
看起来代码很多;然而,我在代码中添加了一些调试语句,这样我们就可以在输出 window 中看到事件何时进入和何时退出,同时显示哪个事件被连接起来。这可能有助于调试,一旦你让它完全工作,我会删除调试语句。
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) {
Debug.WriteLine("DGV_EditingControlShowing <- Enter");
if (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name == "Exercise") {
if (dataGridView1.CurrentRow.Cells["Zone"].Value != null && // <- Zone is not null
!string.IsNullOrEmpty(dataGridView1.CurrentRow.Cells["Zone"].Value.ToString()) && // <- Zone is not an empty string
dataGridView1.CurrentRow.Cells["Zone"].Value.ToString() != "-") { // <= Zone is not "-" blank value
CurCombo = e.Control as ComboBox;
if (CurCombo != null) {
Debug.WriteLine("----------Wiring up Exercise combo box");
CurCombo.SelectedIndexChanged -= new EventHandler(ExerciseComboBox_SelectedIndexChanged);
CurCombo.SelectedIndexChanged += new EventHandler(ExerciseComboBox_SelectedIndexChanged);
}
}
else {
// NO Zone is selected - set the Exercise combo box item list to our single blank value
DataGridViewComboBoxCell ExerciseCell = (DataGridViewComboBoxCell)(dataGridView1.CurrentRow.Cells["Exercise"]);
var filteredList = ExerciseList.Where(x => x.ZoneName == "-").ToList();
Debug.WriteLine("----------Zone is empty filtering Exercise combo box to single blank value");
ExerciseCell.DataSource = filteredList;
}
}
else {
if (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name == "Zone") {
CurCombo = e.Control as ComboBox;
if (CurCombo != null) {
Debug.WriteLine("----------Wiring up Zone combo box");
CurCombo.SelectedIndexChanged -= new EventHandler(ZoneComboBox_SelectedIndexChanged);
CurCombo.SelectedIndexChanged += new EventHandler(ZoneComboBox_SelectedIndexChanged);
}
}
}
Debug.WriteLine("DGV_EditingControlShowing -> Leave");
}
接下来我们需要实现ExerciseComboBox_SelectedIndexChanged
和ZoneComboBox_SelectedIndexChanged
事件方法……再次添加调试语句以帮助调试。应该注意的是,如果我们使用 List<ExerciseAndVideo>
作为组合框列的 DataSource
,那么不要试图直接从网格单元格中获取组合框值......我建议你获取 ExerciseAndVideo
对象直接来自组合框 SelectedItem
属性。我们应该能够像...
ExerciseAndVideo EandV = (ExerciseAndVideo)CurCombo.SelectedItem;
和
Zone selectedZone = (Zone)CurCombo.SelectedItem;
这样可以更轻松地在网格单元格中获取新 selected 值。
private void ExerciseComboBox_SelectedIndexChanged(object sender, EventArgs e) {
Debug.WriteLine("ExerciseComboBox_SelectedIndexChanged <- Enter");
if (CurCombo != null) {
ExerciseAndVideo EandV = (ExerciseAndVideo)CurCombo.SelectedItem;
dataGridView1.CurrentRow.Cells["Video"].Value = EandV.Video;
}
Debug.WriteLine("ExerciseComboBox_SelectedIndexChanged -> Leave");
}
private void ZoneComboBox_SelectedIndexChanged(object sender, EventArgs e) {
Debug.WriteLine("ZoneComboBox_SelectedIndexChanged <- Enter");
if (CurCombo.SelectedValue != null) {
Zone selectedZone = (Zone)CurCombo.SelectedItem;
DataGridViewComboBoxCell ExerciseCell = (DataGridViewComboBoxCell)(dataGridView1.CurrentRow.Cells["Exercise"]);
var filteredList = ExerciseList.Where(x => x.ZoneName == selectedZone.ZoneName || x.ZoneName == "-").ToList();
Debug.WriteLine("----------Exercises combo filtered");
ExerciseCell.DataSource = filteredList;
dataGridView1.CurrentRow.Cells["Exercise"].Value = "-";
dataGridView1.CurrentRow.Cells["Video"].Value = "";
}
Debug.WriteLine("ZoneComboBox_SelectedIndexChanged -> Leave");
}
几乎完成...如果我们现在 运行 代码,您将能够更改区域组合框,但是,如果我们更改区域组合框的值,然后单击您要练习的组合框之一将在 ZoneComboBox_SelectedIndexChanged
方法中出现转换错误。错误的原因是当我们点击 Zone 组合框时,全局 CurCombo
的 SelectedIndexChanged
被连接到指向过滤 Exercise 组合框的方法。因此,当 selected Exercise 组合时,代码将失败并在尝试将组合框转换为 Zone
对象时抛出转换异常,而它实际上是一个 ExerciseAndVideo
对象.
这与之前的评论有关,我们必须确保在用户离开单元格时取消连接 CurCombo
的 SelectedIndexChanged
事件。本例中使用的方法是简单地连接网格的 CellLeave
事件,在这种情况下,我们将检查哪个单元格正在结束其编辑(Zone 或 ExerciseAndVideo),然后取消连接 CurCombo
的SelectedIndexChanged
事件。网格的 CellLeave
事件可能类似于。
private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e) {
Debug.WriteLine("DGV_CellLeave <- Enter");
if (CurCombo != null) {
string colName = dataGridView1.Columns[e.ColumnIndex].Name;
switch (colName) {
case "Exercise":
Debug.WriteLine("----------UN-Wiring Exercise combo box");
CurCombo.SelectedIndexChanged -= new EventHandler(ExerciseComboBox_SelectedIndexChanged);
break;
case "Zone":
Debug.WriteLine("----------UN-Wiring Zone combo box");
CurCombo.SelectedIndexChanged -= new EventHandler(ZoneComboBox_SelectedIndexChanged);
break;
default:
break;
}
}
Debug.WriteLine("DGV_CellLeave -> Leave");
}
最后,连接网格的 DataError
事件以帮助调试。
private void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e) {
MessageBox.Show("Error: From row: " + e.RowIndex + "Col: " + e.ColumnIndex + " Message: " + e.Exception.Message);
}
将所有这些放在一起形成 Load
事件可能如下所示。应该这样做。下面显示了这一点。
using System.Diagnostics;
using System.Linq;
List<ExerciseAndVideo> ExerciseList;
List<Zone> ZoneList;
ComboBox CurCombo;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
SetZoneListFromDB();
SetExerciseListFromDB();
AddColumnsToGrid();
dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter;
}
最后,如前所述,此示例使用未绑定到数据源的网格。如果您打算为包含现有数据的网格使用数据源……那么添加两个额外的步骤是明智的。
在设置网格的数据源之前...强烈建议您检查数据源中的每个区域和运动值。如果有一个区域或练习不是区域或练习列表,那么当设置网格的数据源时,网格将抛出它的 DataError
。此外,如果一个练习不属于给定的区域,那么网格将抛出它的 DataError
。换句话说,如果对一行数据的练习不属于它所拥有的区域,那么您需要在设置网格的 DataSource
.
之前解决此问题
一旦您检查并确保区域和锻炼数据良好,那么在设置网格的数据源之后,您将需要遍历网格中的所有行并“过滤”每一行基于 selected 区域的练习组合框。当数据加载到网格中时,显然我们之前使用的事件不会被触发。幸运的是,您只需要在加载数据后执行一次。
我希望这是有道理的并且有所帮助。
我目前正在使用数据库查询中的列表填充组合框,如下所示:
private List<ExerciseAndVideo> GetExerciseVideoComboBoxListFromDB()
{
List<ExerciseAndVideo> exerciseList = new List<ExerciseAndVideo>();
con = new SqlConnection("my db path etc");
cmd = new SqlCommand();
con.Open();
cmd.Connection = con;
cmd.CommandText = "SELECT nome, link_video, gruppo_muscolare FROM Esercizi ORDER BY nome ASC";
dr = cmd.ExecuteReader();
while (dr.Read())
{
ExerciseAndVideo item = new ExerciseAndVideo();
item.Esercizio = dr.GetString(0);
item.Video = dr.GetString(1);
item.Gruppo = dr.GetString(2);
exerciseList.Add(item);
}
con.Close();
return exerciseList;
}
public class ExerciseAndVideo
{
public string Esercizio { get; set; }
public string Video { get; set; }
public string Gruppo { get; set; }
}
我现在要做的是在 dgv 中添加另一个组合框以过滤练习列表的结果。
我添加了这样的组合:
dataGridView1.Columns.Add(GetGroupComboBoxColumn(GrList));
private List<GroupList> GetGroupComboBoxListFromDB()
{
List<GroupList> GrList = new List<GroupList>();
GrList.Add(new GroupList { Gruppo = "quads" });
GrList.Add(new GroupList { Gruppo = "hamstring" });
GrList.Add(new GroupList { Gruppo = "gluteus" });
return GrList;
}
我该怎么做?
我希望在组合 1 中 select 编辑“股四头肌”时,在组合 2 中我只看到股四头肌的练习。
编辑
以下是 dgv 连击中的火爆事件:
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name == "Esercizio")
{
curCombo = e.Control as ComboBox;
if (curCombo != null)
{
curCombo.SelectedIndexChanged -= new EventHandler(curCombo_SelectedIndexChanged);
curCombo.SelectedIndexChanged += new EventHandler(curCombo_SelectedIndexChanged);
}
}
}
private void curCombo_SelectedIndexChanged(object sender, EventArgs e)
{
if (curCombo != null && curCombo.SelectedValue != null)
{
ExerciseAndVideo selectedExercise = (ExerciseAndVideo)curCombo.SelectedItem;
dataGridView1.CurrentRow.Cells["Video"].Value = selectedExercise.Video;
dataGridView1.CurrentRow.Cells["Gruppo"].Value = selectedExercise.Gruppo;
}
}
private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].Name == "Esercizio")
{
if (curCombo != null)
{
curCombo.SelectedIndexChanged -= new EventHandler(curCombo_SelectedIndexChanged);
}
}
}
这里是组合如何获取数据源:
private DataGridViewComboBoxColumn GetGroupComboBoxColumn(List<GroupList> GrList)
{
DataGridViewComboBoxColumn cbCol = new DataGridViewComboBoxColumn();
cbCol.HeaderText = "Zona";
cbCol.Name = "Zona";
cbCol.DisplayMember = "Zona";
cbCol.DataSource = GrList;
cbCol.Width = 100;
return cbCol;
}
private DataGridViewComboBoxColumn GetExcerciseComboBoxColumn(List<ExerciseAndVideo> exerciseList)
{
DataGridViewComboBoxColumn cbCol = new DataGridViewComboBoxColumn();
cbCol.HeaderText = "Esercizio";
cbCol.Name = "Esercizio";
cbCol.DisplayMember = "Esercizio";
// if I use this string works fine
string selectedGroup = "quadricipiti";
var filteredList = exerciseList.Where(x => x.Gruppo == selectedGroup).ToList();
cbCol.DataSource = filteredList;
cbCol.Width = 140;
return cbCol;
}
编辑 2
我按照建议编辑了 curCombo_SelectedIndexChanged 事件,但我在 exerciseList 上收到错误,因为函数中不存在:
private void curCombo_SelectedIndexChanged(object sender, EventArgs e)
{
if (curCombo != null && curCombo.SelectedValue != null)
{
ExerciseAndVideo selectedExercise = (ExerciseAndVideo)curCombo.SelectedItem;
dataGridView1.CurrentRow.Cells["Video"].Value = selectedExercise.Video;
dataGridView1.CurrentRow.Cells["Gruppo"].Value = selectedExercise.Gruppo;
string selectedGroup = Convert.ToString((GroupList)SelectedCombo.SelectedItem);
DataGridViewComboBoxCell Esercizi = (DataGridViewComboBoxCell)(dataGridView1.CurrentRow.Cells["Esercizi"]);
var filteredList = exerciseList.Where(x => x.Gruppo == selectedGroup).ToList();
Esercizi.DataSource = filteredList;
}
}
编辑 3
更正列表代码以使其作为全局工作后,我没有收到任何错误,但我无法从组合 1 中选择 selected 值作为 selected 组。
如果我使用像“quads”这样的字符串或其他一切正常,否则如果我尝试从组合 1 中选取值,我会在组合 2 上得到一个空白列表。
这是我尝试从组合 1 中获取值的一些代码:
string selectedGroup = Convert.ToString(dataGridView1.CurrentRow.Cells["Zona"]);
string selectedGroup = SelectedCombo.SelectedItem.ToString();
string selectedGroup = Convert.ToString((GroupList)SelectedCombo.SelectedItem);
上次编辑
这里我发现正在努力从组合 1 中获取值:
string selectedGroup = Convert.ToString(dataGridView1.CurrentRow.Cells[0].FormattedValue.ToString());
现在的问题是要使过滤器正常工作,我必须 select 组合 1 中的值的 2 倍。
因此,例如,我在组合 1 中 select“四边形”,在组合 2 中得到一个空白列表。我再次 select“四边形”,我得到过滤后的结果。
我认为问题可能出在事件中,但我没有看到错误:
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name == "Esercizio")
{
curCombo = e.Control as ComboBox;
if (curCombo != null)
{
curCombo.SelectedIndexChanged -= new EventHandler(curCombo_SelectedIndexChanged);
curCombo.SelectedIndexChanged += new EventHandler(curCombo_SelectedIndexChanged);
}
}
if (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name == "Zona")
{
curCombo = e.Control as ComboBox;
if (curCombo != null)
{
curCombo.SelectedIndexChanged -= new EventHandler(ComboBox_SelectedIndexChanged);
curCombo.SelectedIndexChanged += new EventHandler(ComboBox_SelectedIndexChanged);
}
}
}
private void curCombo_SelectedIndexChanged(object sender, EventArgs e)
{
if (curCombo != null && curCombo.SelectedValue != null)
{
ExerciseAndVideo selectedExercise = (ExerciseAndVideo)curCombo.SelectedItem;
dataGridView1.CurrentRow.Cells["Video"].Value = selectedExercise.Video;
dataGridView1.CurrentRow.Cells["Gruppo"].Value = selectedExercise.Gruppo;
}
}
private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (curCombo.SelectedValue != null)
{
string selectedGroup = Convert.ToString(dataGridView1.CurrentRow.Cells[0].FormattedValue.ToString());
DataGridViewComboBoxCell Esercizi = (DataGridViewComboBoxCell)(dataGridView1.CurrentRow.Cells["Esercizio"]);
// string selectedGroup = "femorali";
var filteredList = exerciseList.Where(x => x.Gruppo == selectedGroup).ToList();
Esercizi.DataSource = filteredList;
}
}
private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].Name == "Esercizio")
{
if (curCombo != null)
{
curCombo.SelectedIndexChanged -= new EventHandler(curCombo_SelectedIndexChanged);
}
}
if (dataGridView1.Columns[e.ColumnIndex].Name == "Zona")
{
if (curCombo != null)
{
curCombo.SelectedIndexChanged -= new EventHandler(ComboBox_SelectedIndexChanged);
}
}
}
来自长长的来回评论。我在下面有一个解决方案,应该可以像您描述的那样工作。在我开始之前,我想建议您在 post 提问时更加小心。最初当您 post 编辑这个问题时,遗漏了很多细节,可以避免您看到不必要的扩展评论。您遗漏的细节越多,其他人为理解您的问题而提出的问题越多,您的问题得到解答的机会就越小。
以后,我建议您提供所有需要的信息,当然如果需要的话,一定要编辑您的问题以添加任何相关信息。其他人为帮助您所做的工作越多,您获得任何帮助的机会就越少,更不用说得到答案了。帮自己一个忙,采取额外的步骤来确保你的问题是完全可以理解的,并且更好但可以重现……我保证你不会后悔的。
继续,鉴于下面的图片,我认为这与您 post编辑的相似。
用户可以select更改“区域”组合框项目。发生这种情况时,我们要做的是“过滤”“练习”列组合框单元格,使其仅包含 selected 区域中的练习。那么,如果用户 select 从练习组合框单元格中进行练习,那么,该练习的匹配“视频” link 将显示在该行的“视频”单元格中。希望这是正确的。
观察会导致其他一些假定的行为。
如果一行有一个 selected 区域和一个 selected 练习,并且视频单元格显示练习的视频 link……那么……如果用户更改该行的“区域”值,然后代码将清除练习和视频单元格,因为这些值不一定属于新的 selected 区域。
假设 Zone 组合框单元格为“空”……如果用户尝试 select 在为该行设置 Zone 值之前从 Exercise 组合框进行练习……那么...我们希望练习组合框不包含任何值,因为区域尚未 selected。换句话说,在用户 select 区域之前,练习组合框不会填充值。
下面的代码使用上述假设并在区域更改时清除练习和视频值,并防止用户在区域被 selected 之前 select 进行练习。
如果您创建一个新的 winform 解决方案并将 DataGridView
拖放到窗体上,您应该能够按照以下步骤逐步完成此示例。下面是一些代码和 类 以帮助测试数据和构建网格。
首先,我们将用于组合框列的两个 类。两者都简单明了。
public class ExerciseAndVideo {
public string Exercise { get; set; }
public string Video { get; set; }
public string ZoneName { get; set; }
}
public class Zone {
public string ZoneName { get; set; }
}
一些额外的代码来填充全局变量 ExerciseList
和 ZoneList
以及组合框的一些测试数据…
private void SetExerciseListFromDB() {
ExerciseList = new List<ExerciseAndVideo>();
ExerciseList.Add(new ExerciseAndVideo { Exercise = "-", ZoneName = "-", Video = "" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 1", ZoneName = "quads", Video = "Video 1" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 2", ZoneName = "gluteus", Video = "Video 2" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 3", ZoneName = "quads", Video = "Video 3" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 4", ZoneName = "hamstring", Video = "Video 4" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 5", ZoneName = "quads", Video = "Video 5" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 6", ZoneName = "hamstring", Video = "Video 6" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 7", ZoneName = "quads", Video = "Video 7" });
ExerciseList.Add(new ExerciseAndVideo { Exercise = "Exercise 8", ZoneName = "gluteus", Video = "Video 8" });
}
private void SetZoneListFromDB() {
ZoneList = new List<Zone>();
ZoneList.Add(new Zone { ZoneName = "-" });
ZoneList.Add(new Zone { ZoneName = "quads" });
ZoneList.Add(new Zone { ZoneName = "hamstring" });
ZoneList.Add(new Zone { ZoneName = "gluteus" });
}
注意:在上面的代码中,您可能会注意到每个练习和区域列表都添加了一个额外的项目,用于表示用户没有选择......
ExerciseList.Add(new ExerciseAndVideo { Exercise = "-", ZoneName = "-", Video = "" });
和
ZoneList.Add(new Zone { ZoneName = "-" });
我们可以不用这些“空白”(无选择)值;但是,当 selected 不同的区域时,我们需要一种方法将练习组合框设置为某个“空白”值。您可以像列表中的第一个练习一样设置一个默认值,这样就可以了。这里的要点是,如果我们不将练习值设置为属于“过滤”练习的“过滤”版本的值……您将得到网格的 DataError
抱怨单元格中的值是在项目的组合框列表中不是有效值。
当用户“更改”区域组合框值并且练习单元格已包含先前设置的区域值中的值时,这适用。如果我们不将练习值更改为新过滤版本中的“某物”,而只是将练习值保留为旧值……那么我们将得到网格的 DataError
.
这是向练习列表添加“空白”无选择值的逻辑。当我们过滤列表时,我们会将此“空白”值添加到列表中,然后在区域更改时将练习值设置为该“空白”值。这样我们几乎可以保证我们将避免网格的 DataError
因为练习单元格中的无效值。还有其他解决方法,但是,我发现在处理彼此相关的组合框时,这种“空白”非选择值使事情变得容易得多。我希望这是有道理的。
接下来是手动设置网格列的代码,包括区域和练习组合框列。您可能需要考虑给网格一个 DataSource
…更多关于这个的最后。
private void AddColumnsToGrid() {
DataGridViewComboBoxColumn cbCol = GetComboBoxColumn("Zone", "Zone", "ZoneName", 100);
cbCol.DataSource = ZoneList;
dataGridView1.Columns.Add(cbCol);
cbCol = GetComboBoxColumn("Exercise", "Exercise", "Exercise", 140);
cbCol.DataSource = ExerciseList;
dataGridView1.Columns.Add(cbCol);
dataGridView1.Columns.Add(GetTextBoxColumn("Serie", "serie"));
dataGridView1.Columns.Add(GetTextBoxColumn("Ripetizioni", "ripetizioni"));
dataGridView1.Columns.Add(GetTextBoxColumn("Recupero", "recupero"));
dataGridView1.Columns.Add(GetTextBoxColumn("Time under tension", "tut"));
dataGridView1.Columns.Add(GetLinkColumn("Video", "Video"));
dataGridView1.Columns.Add(GetTextBoxColumn("Note", "note"));
}
private DataGridViewComboBoxColumn GetComboBoxColumn(string headertext, string name, string displayMember, int width) {
DataGridViewComboBoxColumn cbCol = new DataGridViewComboBoxColumn();
cbCol.HeaderText = headertext;
cbCol.Name = name;
cbCol.DisplayMember = displayMember;
cbCol.Width = width;
return cbCol;
}
private DataGridViewTextBoxColumn GetTextBoxColumn(string headerText, string name) {
DataGridViewTextBoxColumn col = new DataGridViewTextBoxColumn();
col.HeaderText = headerText;
col.Name = name;
return col;
}
private DataGridViewLinkColumn GetLinkColumn(string headerText, string name) {
DataGridViewLinkColumn col = new DataGridViewLinkColumn();
col.HeaderText = headerText;
col.Name = name;
return col;
}
如果我们现在 运行 代码,它会像上图一样。用户可以 select 任何区域和任何练习。 Exercise 组合框的过滤尚未实现,Video 单元格的设置也未实现。因此,无论哪个区域 selected.
,您都应该在组合框中看到所有区域和所有练习接下来我们将在用户更改 Zone 组合框值时将“过滤”应用于 Exercise 组合框。总体方法是这样的……首先我们要创建一个全局常规 ComboBox
变量,我们将调用 CurCombo
。然后我们将连接网格的 EditingControlShowing
事件。当用户单击网格单元格并开始编辑该单元格时,将触发此事件。请记住……此事件在用户实际对单元格进行任何更改之前触发。在这种情况下,我们将查看编辑的单元格是否是区域单元格。如果编辑的单元格是区域单元格,那么……我们要做的就是将网格的组合框单元格转换为我们的全局 CurCombo
变量。这看起来像……
CurCombo = e.Control as ComboBox;
其中 e
是传入的 DataGridViewEditingControlShowingEventArgs
变量。它将允许我们将单元格转换为常规组合框。然后,我们将连接 CurCombo
的 SelectedIndexChanged
事件,然后退出并等待用户更改组合框的索引。
当用户确实更改了 Zone 组合框索引,并且组合框 SelectedIndexChanged
事件触发......那么我们就会知道我们需要根据 select编辑区。
让事情变得更复杂……如果用户更改了其中一个练习组合框,那么我们想要更新视频单元格以将 link 显示为 selected 视频。我们可以创建另一个 ComboBox
并执行与区域组合框相同的操作,但是,我们知道用户不能同时 select 两个组合框。所以我们可以对两个组合框使用相同的 CurCombo
变量。但是……我们需要确保在用户离开单元格时取消连接 CurCombo
的 SelectedIndexChanged
事件。否则,当任一组合框更改时,两个事件都将开始触发。
考虑到两个组合框都将触发网格的 EditingControlShowingEvent
事件,如果组合框是练习组合框,我们需要采取额外的步骤。在我们连接 CurCombo
的 SelectedIndexChanged
事件之前,我们要检查 Zone 组合框是否有值。如果 Zone 组合框没有值,那么我们不希望 Exercise 组合框包含除空白无选择值以外的任何值。我们希望用户先 select 一个区域。
因此,如果编辑了练习组合框并且区域组合框单元格不为空,那么我们只需连接 CurCombo
的 SelectedIndexChanged
事件以指向一个不同的事件方法,该方法将更新视频单元格,然后退出并等待用户更改锻炼值。如果区域单元格为空,那么我们将过滤练习组合框以仅包含我们的空白非选择值并且我们不会连接 CurCombo
事件,因为用户无论如何都不能 select 练习。
看起来代码很多;然而,我在代码中添加了一些调试语句,这样我们就可以在输出 window 中看到事件何时进入和何时退出,同时显示哪个事件被连接起来。这可能有助于调试,一旦你让它完全工作,我会删除调试语句。
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) {
Debug.WriteLine("DGV_EditingControlShowing <- Enter");
if (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name == "Exercise") {
if (dataGridView1.CurrentRow.Cells["Zone"].Value != null && // <- Zone is not null
!string.IsNullOrEmpty(dataGridView1.CurrentRow.Cells["Zone"].Value.ToString()) && // <- Zone is not an empty string
dataGridView1.CurrentRow.Cells["Zone"].Value.ToString() != "-") { // <= Zone is not "-" blank value
CurCombo = e.Control as ComboBox;
if (CurCombo != null) {
Debug.WriteLine("----------Wiring up Exercise combo box");
CurCombo.SelectedIndexChanged -= new EventHandler(ExerciseComboBox_SelectedIndexChanged);
CurCombo.SelectedIndexChanged += new EventHandler(ExerciseComboBox_SelectedIndexChanged);
}
}
else {
// NO Zone is selected - set the Exercise combo box item list to our single blank value
DataGridViewComboBoxCell ExerciseCell = (DataGridViewComboBoxCell)(dataGridView1.CurrentRow.Cells["Exercise"]);
var filteredList = ExerciseList.Where(x => x.ZoneName == "-").ToList();
Debug.WriteLine("----------Zone is empty filtering Exercise combo box to single blank value");
ExerciseCell.DataSource = filteredList;
}
}
else {
if (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name == "Zone") {
CurCombo = e.Control as ComboBox;
if (CurCombo != null) {
Debug.WriteLine("----------Wiring up Zone combo box");
CurCombo.SelectedIndexChanged -= new EventHandler(ZoneComboBox_SelectedIndexChanged);
CurCombo.SelectedIndexChanged += new EventHandler(ZoneComboBox_SelectedIndexChanged);
}
}
}
Debug.WriteLine("DGV_EditingControlShowing -> Leave");
}
接下来我们需要实现ExerciseComboBox_SelectedIndexChanged
和ZoneComboBox_SelectedIndexChanged
事件方法……再次添加调试语句以帮助调试。应该注意的是,如果我们使用 List<ExerciseAndVideo>
作为组合框列的 DataSource
,那么不要试图直接从网格单元格中获取组合框值......我建议你获取 ExerciseAndVideo
对象直接来自组合框 SelectedItem
属性。我们应该能够像...
ExerciseAndVideo EandV = (ExerciseAndVideo)CurCombo.SelectedItem;
和
Zone selectedZone = (Zone)CurCombo.SelectedItem;
这样可以更轻松地在网格单元格中获取新 selected 值。
private void ExerciseComboBox_SelectedIndexChanged(object sender, EventArgs e) {
Debug.WriteLine("ExerciseComboBox_SelectedIndexChanged <- Enter");
if (CurCombo != null) {
ExerciseAndVideo EandV = (ExerciseAndVideo)CurCombo.SelectedItem;
dataGridView1.CurrentRow.Cells["Video"].Value = EandV.Video;
}
Debug.WriteLine("ExerciseComboBox_SelectedIndexChanged -> Leave");
}
private void ZoneComboBox_SelectedIndexChanged(object sender, EventArgs e) {
Debug.WriteLine("ZoneComboBox_SelectedIndexChanged <- Enter");
if (CurCombo.SelectedValue != null) {
Zone selectedZone = (Zone)CurCombo.SelectedItem;
DataGridViewComboBoxCell ExerciseCell = (DataGridViewComboBoxCell)(dataGridView1.CurrentRow.Cells["Exercise"]);
var filteredList = ExerciseList.Where(x => x.ZoneName == selectedZone.ZoneName || x.ZoneName == "-").ToList();
Debug.WriteLine("----------Exercises combo filtered");
ExerciseCell.DataSource = filteredList;
dataGridView1.CurrentRow.Cells["Exercise"].Value = "-";
dataGridView1.CurrentRow.Cells["Video"].Value = "";
}
Debug.WriteLine("ZoneComboBox_SelectedIndexChanged -> Leave");
}
几乎完成...如果我们现在 运行 代码,您将能够更改区域组合框,但是,如果我们更改区域组合框的值,然后单击您要练习的组合框之一将在 ZoneComboBox_SelectedIndexChanged
方法中出现转换错误。错误的原因是当我们点击 Zone 组合框时,全局 CurCombo
的 SelectedIndexChanged
被连接到指向过滤 Exercise 组合框的方法。因此,当 selected Exercise 组合时,代码将失败并在尝试将组合框转换为 Zone
对象时抛出转换异常,而它实际上是一个 ExerciseAndVideo
对象.
这与之前的评论有关,我们必须确保在用户离开单元格时取消连接 CurCombo
的 SelectedIndexChanged
事件。本例中使用的方法是简单地连接网格的 CellLeave
事件,在这种情况下,我们将检查哪个单元格正在结束其编辑(Zone 或 ExerciseAndVideo),然后取消连接 CurCombo
的SelectedIndexChanged
事件。网格的 CellLeave
事件可能类似于。
private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e) {
Debug.WriteLine("DGV_CellLeave <- Enter");
if (CurCombo != null) {
string colName = dataGridView1.Columns[e.ColumnIndex].Name;
switch (colName) {
case "Exercise":
Debug.WriteLine("----------UN-Wiring Exercise combo box");
CurCombo.SelectedIndexChanged -= new EventHandler(ExerciseComboBox_SelectedIndexChanged);
break;
case "Zone":
Debug.WriteLine("----------UN-Wiring Zone combo box");
CurCombo.SelectedIndexChanged -= new EventHandler(ZoneComboBox_SelectedIndexChanged);
break;
default:
break;
}
}
Debug.WriteLine("DGV_CellLeave -> Leave");
}
最后,连接网格的 DataError
事件以帮助调试。
private void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e) {
MessageBox.Show("Error: From row: " + e.RowIndex + "Col: " + e.ColumnIndex + " Message: " + e.Exception.Message);
}
将所有这些放在一起形成 Load
事件可能如下所示。应该这样做。下面显示了这一点。
using System.Diagnostics;
using System.Linq;
List<ExerciseAndVideo> ExerciseList;
List<Zone> ZoneList;
ComboBox CurCombo;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
SetZoneListFromDB();
SetExerciseListFromDB();
AddColumnsToGrid();
dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter;
}
最后,如前所述,此示例使用未绑定到数据源的网格。如果您打算为包含现有数据的网格使用数据源……那么添加两个额外的步骤是明智的。
在设置网格的数据源之前...强烈建议您检查数据源中的每个区域和运动值。如果有一个区域或练习不是区域或练习列表,那么当设置网格的数据源时,网格将抛出它的
之前解决此问题DataError
。此外,如果一个练习不属于给定的区域,那么网格将抛出它的DataError
。换句话说,如果对一行数据的练习不属于它所拥有的区域,那么您需要在设置网格的DataSource
.一旦您检查并确保区域和锻炼数据良好,那么在设置网格的数据源之后,您将需要遍历网格中的所有行并“过滤”每一行基于 selected 区域的练习组合框。当数据加载到网格中时,显然我们之前使用的事件不会被触发。幸运的是,您只需要在加载数据后执行一次。
我希望这是有道理的并且有所帮助。