DataGridViewComboBoxColumn 不保存到数据源,除非按下输入
DataGridViewComboBoxColumn not saving to datasource unless enter is pressed
我有一个 DataGridView,其数据源 属性 绑定到一个数据表。所述 DataTable 是手动填充的(不是来自数据库)。我不会详细说明这是如何发生的,因为除了我将要描述的内容之外,一切都完美无缺。构建 DataTable 后,使用以下代码将其绑定到 DataGridView :
DgvResults.DataSource = _data.ResultsData;
此 DataGridView 的最后一列是使用以下代码创建的 DataGridViewComboBoxColumn:
var col = new DataGridViewComboBoxColumn
{
Name = "newMedId",
HeaderText = @"Med ID (NEW PIS)",
DataPropertyName = "newMedId",
DisplayMember = "ItemId",
ValueMember = "ItemId",
ReadOnly = false,
Resizable = DataGridViewTriState.False,
SortMode = DataGridViewColumnSortMode.Programmatic
};
col.Items.Add("");
col.Items.Add("DELETE");
_data.NewFormularyData.AsEnumerable().Select(r => r.Field<string>("ItemId")).ToList()
.ForEach(m => col.Items.Add(m));
DgvResults.Columns.Add(col);
这实际上是用另一个 DataTable 中的所有 ID 填充此列中的每个 ComboBox,并在顶部添加一个空白值和一个“DELETE”值。
我还对此 DataGridView 进行了自定义编程排序。我不会 post 代码,因为我认为它不相关,但本质上它是通过 ColumnHeaderMouseClick 事件触发的,并根据您单击的任何列简单地对基础 DataTable 进行排序,使 DataGridView 的数据源无效 属性 和重新绑定它。
这一切都很好,除了这个:假设 DataGridViewComboBoxColumn 中的一个下拉列表是空白的,我手动将值更新为其他值。如果我在选择所述值后立即对 DataGridView 进行排序,则该值不会更新基础 DataTable 并且会丢失。如果我做同样的事情但是我在选择值后按下回车键,它会正确更新。
我的应用程序具有将所述 DataTable 导出到 Excel 电子表格的功能。单击该按钮会生成包含我更新的值的电子表格,即使我在选择它后没有按回车键也是如此。它的行为就好像 DataGridViewComboBoxCell 在更新它绑定到的 DataTable 之前需要失去焦点。立即单击列 header 对其进行排序似乎不会提供这种丢失的焦点,并且值不会更新。
如何在 DataTable 中立即更新这个值?
这是重现问题的MRE
using System;
using System.ComponentModel;
using System.Data;
using System.Windows.Forms;
namespace MRE
{
public partial class Form1 : Form
{
private DataTable dt;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
SetupDgv();
CreateDT();
Dgv.DataSource = dt;
}
private void CreateDT()
{
dt = new DataTable();
dt.Columns.Add("test1", typeof(string));
dt.Columns[0].ColumnName = "test1";
dt.Columns[0].Caption = "test1";
dt.Columns.Add("test2", typeof(string));
dt.Columns[1].ColumnName = "test2";
dt.Columns[1].Caption = "test2";
var row = dt.NewRow();
row[0] = 1;
row[1] = 1;
dt.Rows.Add(row);
row = dt.NewRow();
row[0] = 2;
row[1] = 2;
dt.Rows.Add(row);
row = dt.NewRow();
row[0] = 3;
row[1] = 3;
dt.Rows.Add(row);
}
private void SetupDgv()
{
Dgv.Columns.Add("test1", "test1");
Dgv.Columns[0].DataPropertyName = "test1";
Dgv.Columns[0].ReadOnly = true;
Dgv.Columns[0].Resizable = DataGridViewTriState.False;
Dgv.Columns[0].SortMode = DataGridViewColumnSortMode.Programmatic;
var col = new DataGridViewComboBoxColumn
{
Name = "test2",
HeaderText = "test2",
DataPropertyName = "test2",
ReadOnly = false,
Resizable = DataGridViewTriState.False,
SortMode = DataGridViewColumnSortMode.Programmatic
};
col.Items.Add("");
col.Items.Add("DELETE");
col.Items.Add("1");
col.Items.Add("2");
col.Items.Add("3");
Dgv.Columns.Add(col);
}
private void Dgv_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
var newColumn = Dgv.Columns[e.ColumnIndex];
var oldColumn = Dgv.GetSortedColumnFromDataTable(dt);
ListSortDirection direction;
if (oldColumn != null)
{
if (oldColumn == newColumn && dt.GetDataTableSortOrder() == "ASC")
direction = ListSortDirection.Descending;
else
{
direction = ListSortDirection.Ascending;
oldColumn.HeaderCell.SortGlyphDirection = SortOrder.None;
}
}
else
direction = ListSortDirection.Ascending;
Dgv.ClearSortGlyphInAllColumnsExcept(e.ColumnIndex);
dt.DefaultView.Sort = direction == ListSortDirection.Ascending ?
Dgv.Columns[e.ColumnIndex].Name + " ASC" : Dgv.Columns[e.ColumnIndex].Name + " DESC";
newColumn.HeaderCell.SortGlyphDirection =
direction == ListSortDirection.Ascending ? SortOrder.Ascending : SortOrder.Descending;
}
}
public static class DGVExtensions
{
public static DataGridViewColumn GetSortedColumnFromDataTable(this DataGridView dgv, DataTable dt)
{
var dtSort = dt.DefaultView.Sort;
string colName;
if (dtSort.IndexOf(" ") != -1)
colName = dtSort.Substring(0, dtSort.IndexOf(" "));
else
colName = dtSort;
return dgv.Columns[colName];
}
public static void ClearSortGlyphInAllColumnsExcept(this DataGridView dgv, int index)
{
foreach (DataGridViewColumn col in dgv.Columns)
{
if (col.Index != index)
col.HeaderCell.SortGlyphDirection = SortOrder.None;
}
}
}
public static class DTExtensions
{
public static string GetDataTableSortOrder(this DataTable dt)
{
if (dt.DefaultView.Sort.IndexOf(" ") == -1)
return "ASC";
else
{
var startIndex = dt.DefaultView.Sort.IndexOf(" ") + 1;
return dt.DefaultView.Sort.Substring(startIndex, dt.DefaultView.Sort.Length - startIndex).ToUpper();
}
}
}
}
在Dgv_ColumnHeaderMouseClick
事件中添加以下代码行作为事件中代码的第一行...
Dgv.CommitEdit(DataGridViewDataErrorContexts.Commit);
我有一个 DataGridView,其数据源 属性 绑定到一个数据表。所述 DataTable 是手动填充的(不是来自数据库)。我不会详细说明这是如何发生的,因为除了我将要描述的内容之外,一切都完美无缺。构建 DataTable 后,使用以下代码将其绑定到 DataGridView :
DgvResults.DataSource = _data.ResultsData;
此 DataGridView 的最后一列是使用以下代码创建的 DataGridViewComboBoxColumn:
var col = new DataGridViewComboBoxColumn
{
Name = "newMedId",
HeaderText = @"Med ID (NEW PIS)",
DataPropertyName = "newMedId",
DisplayMember = "ItemId",
ValueMember = "ItemId",
ReadOnly = false,
Resizable = DataGridViewTriState.False,
SortMode = DataGridViewColumnSortMode.Programmatic
};
col.Items.Add("");
col.Items.Add("DELETE");
_data.NewFormularyData.AsEnumerable().Select(r => r.Field<string>("ItemId")).ToList()
.ForEach(m => col.Items.Add(m));
DgvResults.Columns.Add(col);
这实际上是用另一个 DataTable 中的所有 ID 填充此列中的每个 ComboBox,并在顶部添加一个空白值和一个“DELETE”值。
我还对此 DataGridView 进行了自定义编程排序。我不会 post 代码,因为我认为它不相关,但本质上它是通过 ColumnHeaderMouseClick 事件触发的,并根据您单击的任何列简单地对基础 DataTable 进行排序,使 DataGridView 的数据源无效 属性 和重新绑定它。
这一切都很好,除了这个:假设 DataGridViewComboBoxColumn 中的一个下拉列表是空白的,我手动将值更新为其他值。如果我在选择所述值后立即对 DataGridView 进行排序,则该值不会更新基础 DataTable 并且会丢失。如果我做同样的事情但是我在选择值后按下回车键,它会正确更新。
我的应用程序具有将所述 DataTable 导出到 Excel 电子表格的功能。单击该按钮会生成包含我更新的值的电子表格,即使我在选择它后没有按回车键也是如此。它的行为就好像 DataGridViewComboBoxCell 在更新它绑定到的 DataTable 之前需要失去焦点。立即单击列 header 对其进行排序似乎不会提供这种丢失的焦点,并且值不会更新。
如何在 DataTable 中立即更新这个值?
这是重现问题的MRE
using System;
using System.ComponentModel;
using System.Data;
using System.Windows.Forms;
namespace MRE
{
public partial class Form1 : Form
{
private DataTable dt;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
SetupDgv();
CreateDT();
Dgv.DataSource = dt;
}
private void CreateDT()
{
dt = new DataTable();
dt.Columns.Add("test1", typeof(string));
dt.Columns[0].ColumnName = "test1";
dt.Columns[0].Caption = "test1";
dt.Columns.Add("test2", typeof(string));
dt.Columns[1].ColumnName = "test2";
dt.Columns[1].Caption = "test2";
var row = dt.NewRow();
row[0] = 1;
row[1] = 1;
dt.Rows.Add(row);
row = dt.NewRow();
row[0] = 2;
row[1] = 2;
dt.Rows.Add(row);
row = dt.NewRow();
row[0] = 3;
row[1] = 3;
dt.Rows.Add(row);
}
private void SetupDgv()
{
Dgv.Columns.Add("test1", "test1");
Dgv.Columns[0].DataPropertyName = "test1";
Dgv.Columns[0].ReadOnly = true;
Dgv.Columns[0].Resizable = DataGridViewTriState.False;
Dgv.Columns[0].SortMode = DataGridViewColumnSortMode.Programmatic;
var col = new DataGridViewComboBoxColumn
{
Name = "test2",
HeaderText = "test2",
DataPropertyName = "test2",
ReadOnly = false,
Resizable = DataGridViewTriState.False,
SortMode = DataGridViewColumnSortMode.Programmatic
};
col.Items.Add("");
col.Items.Add("DELETE");
col.Items.Add("1");
col.Items.Add("2");
col.Items.Add("3");
Dgv.Columns.Add(col);
}
private void Dgv_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
var newColumn = Dgv.Columns[e.ColumnIndex];
var oldColumn = Dgv.GetSortedColumnFromDataTable(dt);
ListSortDirection direction;
if (oldColumn != null)
{
if (oldColumn == newColumn && dt.GetDataTableSortOrder() == "ASC")
direction = ListSortDirection.Descending;
else
{
direction = ListSortDirection.Ascending;
oldColumn.HeaderCell.SortGlyphDirection = SortOrder.None;
}
}
else
direction = ListSortDirection.Ascending;
Dgv.ClearSortGlyphInAllColumnsExcept(e.ColumnIndex);
dt.DefaultView.Sort = direction == ListSortDirection.Ascending ?
Dgv.Columns[e.ColumnIndex].Name + " ASC" : Dgv.Columns[e.ColumnIndex].Name + " DESC";
newColumn.HeaderCell.SortGlyphDirection =
direction == ListSortDirection.Ascending ? SortOrder.Ascending : SortOrder.Descending;
}
}
public static class DGVExtensions
{
public static DataGridViewColumn GetSortedColumnFromDataTable(this DataGridView dgv, DataTable dt)
{
var dtSort = dt.DefaultView.Sort;
string colName;
if (dtSort.IndexOf(" ") != -1)
colName = dtSort.Substring(0, dtSort.IndexOf(" "));
else
colName = dtSort;
return dgv.Columns[colName];
}
public static void ClearSortGlyphInAllColumnsExcept(this DataGridView dgv, int index)
{
foreach (DataGridViewColumn col in dgv.Columns)
{
if (col.Index != index)
col.HeaderCell.SortGlyphDirection = SortOrder.None;
}
}
}
public static class DTExtensions
{
public static string GetDataTableSortOrder(this DataTable dt)
{
if (dt.DefaultView.Sort.IndexOf(" ") == -1)
return "ASC";
else
{
var startIndex = dt.DefaultView.Sort.IndexOf(" ") + 1;
return dt.DefaultView.Sort.Substring(startIndex, dt.DefaultView.Sort.Length - startIndex).ToUpper();
}
}
}
}
在Dgv_ColumnHeaderMouseClick
事件中添加以下代码行作为事件中代码的第一行...
Dgv.CommitEdit(DataGridViewDataErrorContexts.Commit);