DataGridView "CellPainting" 事件未绘制正确的单元格
DataGridView "CellPainting" event not painting the correct cell
我的 DataGridView
控件有一个列移动功能,我可以在 table 的左侧和右侧移动列,我还有一个大纲 painting/drawing 事件在“无效”的单元格上绘制红色轮廓。
不幸的是,当我移动分配了这些轮廓的列时,轮廓无法以一种非常奇怪的方式绘制到正确的单元格,其中轮廓停留在单元格的左侧或右侧,它应该根据大纲原来是。
我创建了一个具有这两个功能的项目来演示这种奇怪的行为:
这是与创建大纲相关的代码:
//Dictionary<colIndex,List<RowIndex>>
private Dictionary<int,List<int>> invalidCellIndexes = new Dictionary<int,List<int>>();
public void AddInvalidCellIndexes(int colIndex, int rowIndex)
{
Console.WriteLine("Adding outline to Column: " + colIndex.ToString() + ", at Row: " + rowIndex.ToString());
if (!invalidCellIndexes.ContainsKey(colIndex))
{
invalidCellIndexes[colIndex] = new List<int>();
}
if (!invalidCellIndexes[colIndex].Contains(rowIndex))
{
invalidCellIndexes[colIndex].Add(rowIndex);
}
}
public void RemoveInvalidCellIndexes(int colIndex, int rowIndex)
{
if (invalidCellIndexes.ContainsKey(colIndex))
{
invalidCellIndexes[colIndex].Remove(rowIndex);
if (invalidCellIndexes[colIndex].Count == 0)
{
invalidCellIndexes.Remove(colIndex);
}
}
}
//takes old ColumnOrder and new ColumnOrder and translates the invalidCellIndexes accordingly
public void ShiftColumnsOfInvalidCellIndexes(List<string> oldColumnOrder, List<string> newColumnOrder)
{
Dictionary<int, List<int>> oldInvalidCellIndexes = invalidCellIndexes;
Dictionary<int, List<int>> newInvalidCellIndexes = new Dictionary<int, List<int>>();
for (int i = 0; i < oldColumnOrder.Count; i++)
{
string colName = oldColumnOrder[i];
int oldIndex = i;
int newIndex = newColumnOrder.IndexOf(colName);
if (oldInvalidCellIndexes.ContainsKey(oldIndex))
{
Console.WriteLine("shifting outline at index " + oldIndex.ToString() + " TO " + newIndex.ToString());
newInvalidCellIndexes[newIndex] = oldInvalidCellIndexes[oldIndex];
}
}
invalidCellIndexes = newInvalidCellIndexes;
}
//code linked to CellPainting Event
private void DataGridView1_CellPainting(object sender, System.Windows.Forms.DataGridViewCellPaintingEventArgs e)
{
//DataGridView senderDGV = (DataGridView)sender;
if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
{
if (invalidCellIndexes.ContainsKey(e.ColumnIndex) && invalidCellIndexes[e.ColumnIndex].Contains(e.RowIndex))
{
//DataGridViewCell cell = senderDGV.Rows[e.RowIndex].Cells[e.ColumnIndex];
Console.WriteLine("painting: Row " + e.RowIndex.ToString() + ", column " + e.ColumnIndex.ToString());
e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);
using (Pen p = new Pen(Color.Red, 1))
{
Rectangle rect = e.CellBounds;
rect.Width -= 2;
rect.Height -= 2;
e.Graphics.DrawRectangle(p, rect);
}
e.Handled = true;
}
}
}
这里是与添加列、添加大纲和列移动相关的代码:
//orderList tracks the column display order
List<string> orderList = new List<string>();
private void button2_Click(object sender, EventArgs e)
{
dataGridView1.Columns.Add("B", "B");
dataGridView1.Columns.Add("C", "C");
dataGridView1.Columns.Add("D", "D");
dataGridView1.Columns.Add("A", "A");
dataGridView1.Rows.Add();
dataGridView1.Rows.Add();
dataGridView1.Rows.Add();
//add outline to second row of column "A"
int AColIndex = dataGridView1.Columns.IndexOf(dataGridView1.Columns["A"]);
int ARowIndex = 1;
AddInvalidCellIndexes(AColIndex, ARowIndex);
//add columns to orderlist
foreach (DataGridViewColumn col in dataGridView1.Columns)
{
orderList.Add(col.Name);
}
button2.Enabled = false;
}
private void button1_Click(object sender, EventArgs e)
{
int AColIndex = dataGridView1.Columns.IndexOf(dataGridView1.Columns["A"]);
//shift "A" column to the left
ShiftColumn("A", true);
}
private void button3_Click(object sender, EventArgs e)
{
int AColIndex = dataGridView1.Columns.IndexOf(dataGridView1.Columns["A"]);
//shift "A" column to the right
ShiftColumn("A", false);
}
internal void ShiftColumn(string colName, bool isLeft)
{
int newIndex = orderList.IndexOf(colName);
if (isLeft)
{
newIndex -= 1;
}
else
{
newIndex += 1;
}
if (newIndex > -1 && newIndex < orderList.Count)
{
//duplicate orderList
List<string> oldOrderList = new List<string>(orderList);
orderList.Remove(colName);
orderList.Insert(newIndex, colName);
//for all columns which have shifted position due to this change
//if shifted right, a single column to the right has been shifted before the new index
int colI = newIndex - 1;
if (isLeft)
{
//if shifted to the left, only the new index and indexes after it have been shifted
colI = newIndex;
}
//shift column DisplayIndexes
while (colI < orderList.Count)
{
string thisColName = orderList[colI];
int thisOldIndex = oldOrderList.IndexOf(thisColName);
int thisNewIndex = colI;
dataGridView1.Columns[thisColName].DisplayIndex = thisNewIndex;
colI++;
}
//shift cell outlines as well
ShiftColumnsOfInvalidCellIndexes(oldOrderList, orderList);
}
}
我没有调试你的代码来判断你的代码有什么问题,但你只需要设置 DisplayIndex
并且你不需要移动数据我可以快速显示在非常简单的示例,您如何以正确的方式做到这一点。
在示例中,我使用数据table 来保存数据(它可以是任何其他支持数据绑定的数据结构)。还有有效或无效的行,我假设你可以根据单元格值判断有效性;例如这里的“O”是无效的。还有一个将活动列向左移动的按钮和一个向右移动的按钮:
private void Form1_Load(object sender, EventArgs e)
{
var dt = new DataTable();
dt.Columns.Add("A");
dt.Columns.Add("B");
dt.Columns.Add("C");
dt.Columns.Add("D");
dt.Rows.Add(new[] { "O", "O", "O", "O" });
dt.Rows.Add(new[] { "X", "O", "O", "O" });
dt.Rows.Add(new[] { "X", "X", "O", "O" });
dt.Rows.Add(new[] { "X", "X", "X", "O" });
dgv1.DataSource = dt;
}
private void dgv1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.FormattedValue as string == "O")
{
//Invalid
e.Graphics.FillRectangle(Brushes.Pink, e.CellBounds);
e.Paint(e.CellBounds, DataGridViewPaintParts.All &
~DataGridViewPaintParts.Background);
e.Handled = true;
}
}
private void ShiftLeftButton_Click(object sender, EventArgs e)
{
if (dgv1.CurrentCell != null &&
dgv1.CurrentCell.OwningColumn.DisplayIndex > 0)
dgv1.CurrentCell.OwningColumn.DisplayIndex -= 1;
}
private void ShiftRightButton_Click(object sender, EventArgs e)
{
if (dgv1.CurrentCell != null &&
dgv1.CurrentCell.OwningColumn.DisplayIndex < dgv1.Columns.Count - 1)
dgv1.CurrentCell.OwningColumn.DisplayIndex += 1;
}
我的 DataGridView
控件有一个列移动功能,我可以在 table 的左侧和右侧移动列,我还有一个大纲 painting/drawing 事件在“无效”的单元格上绘制红色轮廓。
不幸的是,当我移动分配了这些轮廓的列时,轮廓无法以一种非常奇怪的方式绘制到正确的单元格,其中轮廓停留在单元格的左侧或右侧,它应该根据大纲原来是。
我创建了一个具有这两个功能的项目来演示这种奇怪的行为:
这是与创建大纲相关的代码:
//Dictionary<colIndex,List<RowIndex>>
private Dictionary<int,List<int>> invalidCellIndexes = new Dictionary<int,List<int>>();
public void AddInvalidCellIndexes(int colIndex, int rowIndex)
{
Console.WriteLine("Adding outline to Column: " + colIndex.ToString() + ", at Row: " + rowIndex.ToString());
if (!invalidCellIndexes.ContainsKey(colIndex))
{
invalidCellIndexes[colIndex] = new List<int>();
}
if (!invalidCellIndexes[colIndex].Contains(rowIndex))
{
invalidCellIndexes[colIndex].Add(rowIndex);
}
}
public void RemoveInvalidCellIndexes(int colIndex, int rowIndex)
{
if (invalidCellIndexes.ContainsKey(colIndex))
{
invalidCellIndexes[colIndex].Remove(rowIndex);
if (invalidCellIndexes[colIndex].Count == 0)
{
invalidCellIndexes.Remove(colIndex);
}
}
}
//takes old ColumnOrder and new ColumnOrder and translates the invalidCellIndexes accordingly
public void ShiftColumnsOfInvalidCellIndexes(List<string> oldColumnOrder, List<string> newColumnOrder)
{
Dictionary<int, List<int>> oldInvalidCellIndexes = invalidCellIndexes;
Dictionary<int, List<int>> newInvalidCellIndexes = new Dictionary<int, List<int>>();
for (int i = 0; i < oldColumnOrder.Count; i++)
{
string colName = oldColumnOrder[i];
int oldIndex = i;
int newIndex = newColumnOrder.IndexOf(colName);
if (oldInvalidCellIndexes.ContainsKey(oldIndex))
{
Console.WriteLine("shifting outline at index " + oldIndex.ToString() + " TO " + newIndex.ToString());
newInvalidCellIndexes[newIndex] = oldInvalidCellIndexes[oldIndex];
}
}
invalidCellIndexes = newInvalidCellIndexes;
}
//code linked to CellPainting Event
private void DataGridView1_CellPainting(object sender, System.Windows.Forms.DataGridViewCellPaintingEventArgs e)
{
//DataGridView senderDGV = (DataGridView)sender;
if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
{
if (invalidCellIndexes.ContainsKey(e.ColumnIndex) && invalidCellIndexes[e.ColumnIndex].Contains(e.RowIndex))
{
//DataGridViewCell cell = senderDGV.Rows[e.RowIndex].Cells[e.ColumnIndex];
Console.WriteLine("painting: Row " + e.RowIndex.ToString() + ", column " + e.ColumnIndex.ToString());
e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);
using (Pen p = new Pen(Color.Red, 1))
{
Rectangle rect = e.CellBounds;
rect.Width -= 2;
rect.Height -= 2;
e.Graphics.DrawRectangle(p, rect);
}
e.Handled = true;
}
}
}
这里是与添加列、添加大纲和列移动相关的代码:
//orderList tracks the column display order
List<string> orderList = new List<string>();
private void button2_Click(object sender, EventArgs e)
{
dataGridView1.Columns.Add("B", "B");
dataGridView1.Columns.Add("C", "C");
dataGridView1.Columns.Add("D", "D");
dataGridView1.Columns.Add("A", "A");
dataGridView1.Rows.Add();
dataGridView1.Rows.Add();
dataGridView1.Rows.Add();
//add outline to second row of column "A"
int AColIndex = dataGridView1.Columns.IndexOf(dataGridView1.Columns["A"]);
int ARowIndex = 1;
AddInvalidCellIndexes(AColIndex, ARowIndex);
//add columns to orderlist
foreach (DataGridViewColumn col in dataGridView1.Columns)
{
orderList.Add(col.Name);
}
button2.Enabled = false;
}
private void button1_Click(object sender, EventArgs e)
{
int AColIndex = dataGridView1.Columns.IndexOf(dataGridView1.Columns["A"]);
//shift "A" column to the left
ShiftColumn("A", true);
}
private void button3_Click(object sender, EventArgs e)
{
int AColIndex = dataGridView1.Columns.IndexOf(dataGridView1.Columns["A"]);
//shift "A" column to the right
ShiftColumn("A", false);
}
internal void ShiftColumn(string colName, bool isLeft)
{
int newIndex = orderList.IndexOf(colName);
if (isLeft)
{
newIndex -= 1;
}
else
{
newIndex += 1;
}
if (newIndex > -1 && newIndex < orderList.Count)
{
//duplicate orderList
List<string> oldOrderList = new List<string>(orderList);
orderList.Remove(colName);
orderList.Insert(newIndex, colName);
//for all columns which have shifted position due to this change
//if shifted right, a single column to the right has been shifted before the new index
int colI = newIndex - 1;
if (isLeft)
{
//if shifted to the left, only the new index and indexes after it have been shifted
colI = newIndex;
}
//shift column DisplayIndexes
while (colI < orderList.Count)
{
string thisColName = orderList[colI];
int thisOldIndex = oldOrderList.IndexOf(thisColName);
int thisNewIndex = colI;
dataGridView1.Columns[thisColName].DisplayIndex = thisNewIndex;
colI++;
}
//shift cell outlines as well
ShiftColumnsOfInvalidCellIndexes(oldOrderList, orderList);
}
}
我没有调试你的代码来判断你的代码有什么问题,但你只需要设置 DisplayIndex
并且你不需要移动数据我可以快速显示在非常简单的示例,您如何以正确的方式做到这一点。
在示例中,我使用数据table 来保存数据(它可以是任何其他支持数据绑定的数据结构)。还有有效或无效的行,我假设你可以根据单元格值判断有效性;例如这里的“O”是无效的。还有一个将活动列向左移动的按钮和一个向右移动的按钮:
private void Form1_Load(object sender, EventArgs e)
{
var dt = new DataTable();
dt.Columns.Add("A");
dt.Columns.Add("B");
dt.Columns.Add("C");
dt.Columns.Add("D");
dt.Rows.Add(new[] { "O", "O", "O", "O" });
dt.Rows.Add(new[] { "X", "O", "O", "O" });
dt.Rows.Add(new[] { "X", "X", "O", "O" });
dt.Rows.Add(new[] { "X", "X", "X", "O" });
dgv1.DataSource = dt;
}
private void dgv1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.FormattedValue as string == "O")
{
//Invalid
e.Graphics.FillRectangle(Brushes.Pink, e.CellBounds);
e.Paint(e.CellBounds, DataGridViewPaintParts.All &
~DataGridViewPaintParts.Background);
e.Handled = true;
}
}
private void ShiftLeftButton_Click(object sender, EventArgs e)
{
if (dgv1.CurrentCell != null &&
dgv1.CurrentCell.OwningColumn.DisplayIndex > 0)
dgv1.CurrentCell.OwningColumn.DisplayIndex -= 1;
}
private void ShiftRightButton_Click(object sender, EventArgs e)
{
if (dgv1.CurrentCell != null &&
dgv1.CurrentCell.OwningColumn.DisplayIndex < dgv1.Columns.Count - 1)
dgv1.CurrentCell.OwningColumn.DisplayIndex += 1;
}