我们使用CellFormatting事件在我们的应用程序中为各种网格中的单元格着色。
我们有一些通用代码可以处理导出到Excel(和打印)但是它在Black&白色。现在我们想要更改它并从网格中获取颜色。
这个question & answer已经帮助(并且它可以工作)......除了大型网格的问题超出了单个屏幕。网格中尚未显示的部分(逻辑上)从未获取其CellFormatting代码,因此它们的基础颜色永远不会被设置。因此,在Excel中,颜色编码在页面的一半处消失。
似乎有三种解决方案:
1)告诉用户在导出到Excel之前必须滚动到网格的所有部分。 哈!不是一个严肃的解决方案
2)在执行导出到Excel之前,以编程方式滚动到网格的所有部分。 只比(1)
更可怕3)在我们的导出到Excel代码中,在顶部触发一些东西,告诉DataGridView绘制/格式化整个区域,例如。
MyDataGridView.FormatAllCells()
有什么东西能做到这样吗???
哦,还有第四种选择,但这涉及触及大量现有代码:
4)停止使用CellFormatting事件,在加载时格式化单元格。问题是我们必须在我们的应用程序中重新设置每个网格,因为CellFormatting是我们从年份开始就完成它的方式。
答案 0 :(得分:6)
我有一个可能的解决方案 - 在导出函数中访问每个单元格的Cell.FormattedValue属性。根据{{3}},这会强制CellFormatting事件触发。
答案 1 :(得分:3)
正如其他答案中所述,访问DataGridViewCell.FormattedValue
确实是一种简单的方法,可以强制(重新)为特定单元格调用CellFormatting
事件。然而,在我的情况下,这个属性也导致了涉及自动调整列的大小的不良副作用。在长时间搜索可行的解决方案时,我终于遇到了以下完美运行的魔术方法: DataGridView.Invalidate()
,DataGridView.InvalidateColumn()
,DataGridView.InvalidateRow()
和 DataGridView.InvalidateCell()
这四种方法强制仅为指定的范围(单元格,列,行或整个表)重新调用CellFormatting
事件,并且不会导致任何讨厌的自动调整大小的工件。
答案 2 :(得分:2)
假设,正如@DavidHall建议的那样,没有魔法.FormatAllCells
我们唯一的选择就是停止使用CellFormatting。
但是,这里的新问题是在加载期间应用单元格样式格式似乎没有任何效果。如果你谷歌它的很多帖子。他们还指出,如果您将相同的代码放在表单上的按钮下并在加载后单击它(而不是在加载中,代码将起作用...因此在样式可以应用之前必须可见网格)。关于该主题的大多数建议建议您使用... drumroll ... CellFormatting。 AARGH!强>
最终发现了一条建议使用网格DataBindingComplete
事件的帖子。这很有效。
不可否认,此解决方案是我不想要的选项“4”的变体。
答案 3 :(得分:2)
我遇到了同样的问题,我最终得到的东西与你的解决方案#4非常相似。
像你一样,我使用了DataBindingComplete
事件。但是,由于我使用了Extension方法,现有代码中的更改是可以忍受的:
internal static class DataGridViewExtention
{
public static void SetGridBackColorMyStyle(this DataGridView p_dgvToManipulate)
{
p_dgvToManipulate.RowPrePaint += p_dgvToManipulate_RowPrePaint;
p_dgvToManipulate.DataBindingComplete += p_dgvToManipulate_DataBindingComplete;
}
// for the first part - Coloring the whole grid I used the `DataGridView.DataBindingComplete` event:
private static void p_dgvToManipulate_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
foreach (DataGridViewRow objCurrRow in ((DataGridView)sender).Rows)
{
// Get the domain object from row
DomainObject objSelectedItem = (DomainObject)objCurrRow.DataBoundItem;
// if item is valid ....
if objSelectedItem != null)
{
// Change backcolor of row using my method
objCurrRow.DefaultCellStyle.BackColor = GetColorForMyRow(objSelectedItem);
}
}
}
// for the second part (disabling the Selected row from effecting the BackColor i've setted myself, i've used `DataGridView.RowPrePaint` event:
private static void p_dgvToManipulate_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
// If current row about to be painted is selected by user
if (((DataGridView)sender).Rows[e.RowIndex].Selected)
{
// Get current grid row
var objGridRow = ((DataGridView)sender).Rows[e.RowIndex];
// Get selectedItem
DomainObject objSelectedItem = (DomainObject)objGridRow.DataBoundItem;
// if item is valid ....
if (objSelectedItem != null && objSelectedItem.ObjectId != 0)
{
// Set color for row instead of "DefaultCellStyle" (same color as we used at DataBindingComplete event)
objGridRow.DefaultCellStyle.SelectionBackColor = GetColorForMyRow(objSelectedItem);
}
// Since the selected row is no longer unique, we need to let the used to identify it by making the font Bold
objGridRow.DefaultCellStyle.Font = new Font(((DataGridView)sender).Font.FontFamily, ((DataGridView)sender).Font.Size, FontStyle.Bold);
}
// If current row is not selected by user
else
{
// Make sure the Font is not Bold. (for not misleading the user about selected row...)
((DataGridView)sender).Rows[e.RowIndex].DefaultCellStyle.Font = new Font(((DataGridView)sender).Font.FontFamily,
((DataGridView)sender).Font.Size, FontStyle.Regular);
}
}
}
答案 4 :(得分:1)
如果您想要重复使用Cellformatting事件期间提供的格式(例如像fontbold和backgroundcolor这样的cellstyle元素),可能的解决方案。这些单元格样式似乎只能在“cellformatting”和“cellpainting”事件之间使用,而不能在datagridview-cell的样式本身中使用..
在cellformatting-event期间使用第二个处理程序捕获cellstyles:
添加一个共享列表,数组或字典来存储单元格样式:
Dim oDataGridFormattingDictionary as Dictionary(Of String, DataGridViewCellStyle) = nothing
初始化字典并在打印或导出代码中向datagridview添加第二个处理程序。在vb.net中是这样的:
oDataGridFormattingDictionary = New Dictionary(Of String, DataGridViewCellStyle)
AddHandler MyDatagridviewControl.CellFormatting, AddressOf OnPrintDataGridView_CellFormatting
添加处理程序的代码
Private Sub OnPrintDataGridView_CellFormatting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellFormattingEventArgs)
If e.RowIndex > -1 AndAlso e.ColumnIndex > -1 AndAlso Not e.CellStyle Is Nothing Then
If Not oDataGridFormattingDictionary Is Nothing andalso oDataGridFormattingDictionary.ContainsKey(e.RowIndex & "_" & e.ColumnIndex) = False Then
oDataGridFormattingDictionary.Add(e.RowIndex & "_" & e.ColumnIndex, e.CellStyle)
End If
End If
End Sub
非常重要:要确保实际调用原始的cellformating-event(以及之后的第二个cellformatting-handler),您必须请求 formattedvalue 对于您要打印的每个单元格(例如
oValue = Datagridview.rows(printRowIndex).Cells(printColumnIndex).FormattedValue)
<!/ p>
打印时,您现在可以检查单元格是否格式化。 E.g:
if not oDataGridFormattingDictionary is nothing andalso oDataGridFormattingDictionary.ContainsKey(printRowIndex & "_" & printColumnIndex) Then
... the cellstyle is accesible via:
oDataGridFormattingDictionary(printRowIndex & "_" & printColumnIndex)
end if
删除处理程序并将字典设置为空
RemoveHandler DirectCast(itemToPrint.TheControl, DataGridView).CellFormatting, AddressOf OnPrintDataGridView_CellFormatting
oDataGridFormattingDictionary = nothing