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;
}