将今天的日期与一列进行比较并突出显示该单元格
Compare today's date to a column and highlight the cell
在我的 winform 应用程序中,有一个名为“Next_Calibration_On”的列(格式为“dd-MM-yyyy”),我必须与它比较今天的日期,如果它小于它,那么我想要以红色突出显示数据网格视图中的单元格。
我有以下代码:
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
DateTime currentToday = (DateTime)this.dataGridView1.Rows[e.RowIndex].Cells["Next_Calibration_On"].Value;
if (currentToday <= DateTime.Now.Date)
{
e.CellStyle.ForeColor = Color.Red; //Font Color
e.CellStyle.SelectionForeColor = Color.Red; //Selection Font color
}
然而,这显示错误消息如下:
System.ArgumentException: 'Column named Next_Calibration_On cannot be found.Parameter name: columnName'
但是我的 table 中确实有专栏..如何解决这个问题?
不要编辑您的单元格。告诉您的 DataGridView 从何处获取其数据
不要将数据直接放在DataGridView 中,告诉它从哪里获取它的数据,以及如何显示获取的数据。这将您的数据与其显示方式分开。每当您决定以不同方式显示它时,您不必更改原始数据。
您可以看到数据和显示之间的这种分离是如何在电子表格中完成的。电子表格数据可以显示为按列和行排列的 collection 单元格,并显示单元格中值的文本表示。
显示相同数据的另一种方法是在图表中显示:即使显示与 collection 单元格完全不同,但背后的数据是相同的。
同样的数据,不同的显示。
在 winforms 中,所有显示数据序列的控件都有相同的分隔:ListBox、ListView、DataGridView、Chart 等。
所有这些 classes 都提供了直接将数据添加到组件的可能性,但它们也有一个 属性 DataSource
.
如果您将序列分配给数据源,例如列表或数组,则会显示数据。其他属性决定数据源的每个元素必须如何显示。
在 DataGridView 中,DataGridViewColumns 定义必须显示每行的 属性 以及它们必须如何显示。
最简单的形式:
假设您有一个 class 客户:
class Customer
{
public int Id {get; set;}
public string Name {get; set;}
public Address Address {get; set;}
public string PhoneNr {get; set;}
};
假设您还有一个仅显示客户 ID 和姓名的 DataGridView
DataGridViewColumn columnCustomerId = new DateGridViewColumn
{
DataPropertyName = nameof(Customer.Id),
ValueType = typeof(int),
};
DataGridViewColumn columnCustomerName = new DateGridViewColumn
{
DataPropertyName = nameof(Customer.Name),
ValueType = typeof(string),
};
DataGridView customersDataGridView = new DataGridView(...) {...}
customersDataGridView.Columns.Add(columnCustomerId);
customersDataGridView.Columns.Add(columnCustomerName);
现在向客户展示:
List<Customer> customers = FetchCustomers(...);
customersDataGridview.DataSource = customers;
这足以显示客户的 ID 和姓名。如果您还想显示电话号码,只需添加一个列。您不必更改原始数据。
同样,如果您想要以不同方式格式化某些客户的单元格:这对您的原始客户没有影响 collection。只有显示发生变化。
旁注
虽然上述方法有效,但如果操作员编辑显示的数据,您仍然会遇到问题。如果要自动更新操作员所做的更改,请不要将数据放在列表中,而是放在 System.ComponentModel.BindingList:
BindingList<Customer> customers = new BindingList<Customer>(FetchCustomers(...));
customerDataGridView.DataSource = customers;
现在,如果操作员从 DataGridView 添加/删除/更改 Customers,它们会在 BindingList 中自动更新。
还有一个方便的提示:如果您希望通过单击列 header 进行自动排序,并且如果您希望轻松过滤:“仅显示居住在 'Amsterdam' 的客户”而无需更改Customers 列表,考虑使用 Nuget package BindingListView
BindingListView<Customer> customers = new BindingListView<Customer>(FetchCustomers(...));
customerDataGridView.DataSource = customers;
转眼之间:你有可排序的列;可编辑的客户。筛选很简单:
// show only Amsterdam customers:
customers.ApplyFilter( customer => customer.Address.City == "Amsterdam");
即使您没有在 DataGridView 中显示客户的城市,您也可以轻松地对其进行过滤。
顺便说一下:你有没有注意到我从 DataSource 切换是多么容易,甚至没有更改我的 DataGridView?这是因为我把显示和源数据分开了。
回到你的问题
您想更改 NextCalibration 列中单元格的布局。值高于 xxx 的每个单元格都应为红色。
单元格的布局在 DataGridViewCellStyle 中完成。如果您的 Cell 没有自己的 CellStyle,它会使用 DataGridViewColumn 的 CellStyle。
您想在显示的值 属性 满足某些要求时更改单元格样式。在这种情况下:如果小于今天的日期,前景色为红色,否则为默认值。复制列的默认单元格样式。
DataGridViewColumn columnNextCalibration = ...
DataGridViewCellStyle specialCellStyle = (DataGridViewCellStyle)columnNextCalibration
.CellTemplate
.CellStyle
.Clone();
如果您的列没有特殊样式(它为空),请使用 InheritedStyle。
// adjust the CellStyle to the style it should have when the value meets the requirements
specialCellStyle.ForeColor = Color.Red;
// if desired: change the Font, the fontSize, or the BackColor, the frame whatever!
您想 select 默认 CellStyle (null) 或此特殊单元格样式,具体取决于显示的 DateTime 值:
现在您有一个特殊的 CellStyle,等待显示的值发生变化:
this.customersDataGridView.CellValueChanges += OnCellValueChanged;
private void OnCellValueChanged(object sender, DataGridViewCellEventArgs eventArgs)
{
DataGridView dgv = (DataGridView)sender;
// is the changed cell from my column in my DataGridView?
if (Object.ReferencEquals(sender, customersDataGridView)
&& e.ColumnIndex == columnNextCalibation.DisplayIndex)
{
DataGridViewCell changedCell = dgv.Rows[e.RowIndex].Column[e.ColumnIndex];
DateTime cellValue = (DateTime)cell.Value;
DateTime today = ...
if (cellValue < today)
{
// use the special CellStyle:
changedCell.CellStyle = specialCellStyle;
}
else
{
// use the default CellStyle of the column, not a special one for this cell
changedCell.CellStyle = null;
}
}
}
在我的 winform 应用程序中,有一个名为“Next_Calibration_On”的列(格式为“dd-MM-yyyy”),我必须与它比较今天的日期,如果它小于它,那么我想要以红色突出显示数据网格视图中的单元格。 我有以下代码:
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
DateTime currentToday = (DateTime)this.dataGridView1.Rows[e.RowIndex].Cells["Next_Calibration_On"].Value;
if (currentToday <= DateTime.Now.Date)
{
e.CellStyle.ForeColor = Color.Red; //Font Color
e.CellStyle.SelectionForeColor = Color.Red; //Selection Font color
}
然而,这显示错误消息如下:
System.ArgumentException: 'Column named Next_Calibration_On cannot be found.Parameter name: columnName'
但是我的 table 中确实有专栏..如何解决这个问题?
不要编辑您的单元格。告诉您的 DataGridView 从何处获取其数据
不要将数据直接放在DataGridView 中,告诉它从哪里获取它的数据,以及如何显示获取的数据。这将您的数据与其显示方式分开。每当您决定以不同方式显示它时,您不必更改原始数据。
您可以看到数据和显示之间的这种分离是如何在电子表格中完成的。电子表格数据可以显示为按列和行排列的 collection 单元格,并显示单元格中值的文本表示。
显示相同数据的另一种方法是在图表中显示:即使显示与 collection 单元格完全不同,但背后的数据是相同的。
同样的数据,不同的显示。
在 winforms 中,所有显示数据序列的控件都有相同的分隔:ListBox、ListView、DataGridView、Chart 等。
所有这些 classes 都提供了直接将数据添加到组件的可能性,但它们也有一个 属性 DataSource
.
如果您将序列分配给数据源,例如列表或数组,则会显示数据。其他属性决定数据源的每个元素必须如何显示。
在 DataGridView 中,DataGridViewColumns 定义必须显示每行的 属性 以及它们必须如何显示。
最简单的形式:
假设您有一个 class 客户:
class Customer
{
public int Id {get; set;}
public string Name {get; set;}
public Address Address {get; set;}
public string PhoneNr {get; set;}
};
假设您还有一个仅显示客户 ID 和姓名的 DataGridView
DataGridViewColumn columnCustomerId = new DateGridViewColumn
{
DataPropertyName = nameof(Customer.Id),
ValueType = typeof(int),
};
DataGridViewColumn columnCustomerName = new DateGridViewColumn
{
DataPropertyName = nameof(Customer.Name),
ValueType = typeof(string),
};
DataGridView customersDataGridView = new DataGridView(...) {...}
customersDataGridView.Columns.Add(columnCustomerId);
customersDataGridView.Columns.Add(columnCustomerName);
现在向客户展示:
List<Customer> customers = FetchCustomers(...);
customersDataGridview.DataSource = customers;
这足以显示客户的 ID 和姓名。如果您还想显示电话号码,只需添加一个列。您不必更改原始数据。
同样,如果您想要以不同方式格式化某些客户的单元格:这对您的原始客户没有影响 collection。只有显示发生变化。
旁注
虽然上述方法有效,但如果操作员编辑显示的数据,您仍然会遇到问题。如果要自动更新操作员所做的更改,请不要将数据放在列表中,而是放在 System.ComponentModel.BindingList:
BindingList<Customer> customers = new BindingList<Customer>(FetchCustomers(...));
customerDataGridView.DataSource = customers;
现在,如果操作员从 DataGridView 添加/删除/更改 Customers,它们会在 BindingList 中自动更新。
还有一个方便的提示:如果您希望通过单击列 header 进行自动排序,并且如果您希望轻松过滤:“仅显示居住在 'Amsterdam' 的客户”而无需更改Customers 列表,考虑使用 Nuget package BindingListView
BindingListView<Customer> customers = new BindingListView<Customer>(FetchCustomers(...));
customerDataGridView.DataSource = customers;
转眼之间:你有可排序的列;可编辑的客户。筛选很简单:
// show only Amsterdam customers:
customers.ApplyFilter( customer => customer.Address.City == "Amsterdam");
即使您没有在 DataGridView 中显示客户的城市,您也可以轻松地对其进行过滤。
顺便说一下:你有没有注意到我从 DataSource 切换是多么容易,甚至没有更改我的 DataGridView?这是因为我把显示和源数据分开了。
回到你的问题
您想更改 NextCalibration 列中单元格的布局。值高于 xxx 的每个单元格都应为红色。
单元格的布局在 DataGridViewCellStyle 中完成。如果您的 Cell 没有自己的 CellStyle,它会使用 DataGridViewColumn 的 CellStyle。
您想在显示的值 属性 满足某些要求时更改单元格样式。在这种情况下:如果小于今天的日期,前景色为红色,否则为默认值。复制列的默认单元格样式。
DataGridViewColumn columnNextCalibration = ...
DataGridViewCellStyle specialCellStyle = (DataGridViewCellStyle)columnNextCalibration
.CellTemplate
.CellStyle
.Clone();
如果您的列没有特殊样式(它为空),请使用 InheritedStyle。
// adjust the CellStyle to the style it should have when the value meets the requirements
specialCellStyle.ForeColor = Color.Red;
// if desired: change the Font, the fontSize, or the BackColor, the frame whatever!
您想 select 默认 CellStyle (null) 或此特殊单元格样式,具体取决于显示的 DateTime 值:
现在您有一个特殊的 CellStyle,等待显示的值发生变化:
this.customersDataGridView.CellValueChanges += OnCellValueChanged;
private void OnCellValueChanged(object sender, DataGridViewCellEventArgs eventArgs)
{
DataGridView dgv = (DataGridView)sender;
// is the changed cell from my column in my DataGridView?
if (Object.ReferencEquals(sender, customersDataGridView)
&& e.ColumnIndex == columnNextCalibation.DisplayIndex)
{
DataGridViewCell changedCell = dgv.Rows[e.RowIndex].Column[e.ColumnIndex];
DateTime cellValue = (DateTime)cell.Value;
DateTime today = ...
if (cellValue < today)
{
// use the special CellStyle:
changedCell.CellStyle = specialCellStyle;
}
else
{
// use the default CellStyle of the column, not a special one for this cell
changedCell.CellStyle = null;
}
}
}