I have a column shifting function for my DataGridView control where I can shift columns to the left and right of the table, and I also have an outline painting/drawing event that draws a red outline over cells which are "invalid".
Unfortunately, when I shift a column with these outlines assigned to it, the outlines fail to draw to the correct cell in a pretty strange manner, where the outline stays to the left or right of the cell it should be drawn to based on where the outline was originally.
I've created a project with these two features to demonstrate this strange behaviour:

Here is the code relevant to creating the outline(s):
//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;
}
}
}
and here is the code relevant to adding the columns, adding the outline, and column shifting:
//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);
}
}
