在Winform中,如何正确设置DataGridViewCheckBoxCell ReadOnly标志并将方框绘制为灰色?

时间:2015-11-13 23:06:11

标签: c# .net winforms datagridview

如何正确设置DataGridViewCheckBoxCell.ReadOnly属性并将其绘制为灰色?原始的DataGridCheckBoxCell不会这样做。

我的DataGridView的数据来自BindingSource。加载数据后,我将特定单元格设置为ReadOnly。

然而,实验表明它使其他单元格的ReadOnly属性不一致。许多调试会话显示 - 有时 - 同一列中的其他单元重新实例化,从而重置其ReadOnly标志。这导致绘制单元格不一致。

以下是工作示例应用程序的代码。它有4行。但是,如果在单元格的构造函数上设置断点,则会看到它实例化的次数超过4次。单击该复选框时,有时您会看到该单元格也会重新复制。这真让我困惑。

我正在运行.NET 3.5

Form1.cs的

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace DataGridPaintingIssue
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            estimateLineBindingSource.DataSource = createMockData();
            this.Load += Form_Load;
        }

        private void Form_Load(object sender, EventArgs eventArgs)
        {
            setReadOnly();
        }

        private List<EstimateLineNet> createMockData()
        {
            var result = new List<EstimateLineNet>()
            {
                new EstimateLineNet("*", false, "HEADER"),
                new EstimateLineNet(null, false, "Child"),
                new EstimateLineNet(null, true, "openitem"),
                new EstimateLineNet(null, false, "Child3"),
            };
            return result;
        }

        private void setReadOnly()
        {
            estimateGridView.Rows[1].Cells[2].ReadOnly = true; //manually set a specific cell's ReadOnly flag.
        }
    }


    public class OpenItemCheckBoxColumn : DataGridViewCheckBoxColumn
    {
        public OpenItemCheckBoxColumn()
        {
            init();
        }
        private void init()
        {
            CellTemplate = new OpenItemCheckBoxCell();
        }

        public class OpenItemCheckBoxCell : DataGridViewCheckBoxCell
        {
            public OpenItemCheckBoxCell()
            {
                ;//breakpoint shows sometimes the cell reinstantiates.
            }

            private DataGridViewElementStates _lastState;
            private bool _lastReadOnly;

            protected override void Paint(
                Graphics graphics,
                Rectangle clipBounds,
                Rectangle cellBounds,
                int rowIndex,
                DataGridViewElementStates elementState,
                object value,
                object formattedValue,
                string errorText,
                DataGridViewCellStyle cellStyle,
                DataGridViewAdvancedBorderStyle advancedBorderStyle,
                DataGridViewPaintParts paintParts)
            {
                //breakpoint with condition _lastState != elementState shows the ReadOnly flag resets to false
                base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText,
                    cellStyle, advancedBorderStyle, paintParts);
                _lastState = elementState;
                _lastReadOnly = ReadOnly; //need to persist this ReadOnly flag.
            }

        }
    }


    public class EstimateLineNet
    {
        public EstimateLineNet(string asterisk, bool openItem, string description)
        {
            Asterisk = asterisk;
            OpenItem = openItem;
            Description = description;
        }
        public string Asterisk { get; set; }
        public bool OpenItem { get; set; }
        public string Description { get; set; }
    }
}

Form1.Designer.cs

namespace DataGridPaintingIssue
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.estimateGridView = new System.Windows.Forms.DataGridView();
            this.Asterisk = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.OpenItem = new DataGridPaintingIssue.OpenItemCheckBoxColumn();
            this.Desc = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.estimateLineBindingSource = new System.Windows.Forms.BindingSource(this.components);
            ((System.ComponentModel.ISupportInitialize)(this.estimateGridView)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.estimateLineBindingSource)).BeginInit();
            this.SuspendLayout();
            // 
            // estimateGridView
            // 
            this.estimateGridView.AllowUserToAddRows = false;
            this.estimateGridView.AllowUserToDeleteRows = false;
            this.estimateGridView.AllowUserToResizeRows = false;
            this.estimateGridView.AutoGenerateColumns = false;
            this.estimateGridView.ColumnHeadersHeight = 19;
            this.estimateGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
            this.estimateGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
            this.Asterisk,
            this.OpenItem,
            this.Desc});
            this.estimateGridView.DataSource = this.estimateLineBindingSource;
            this.estimateGridView.Dock = System.Windows.Forms.DockStyle.Fill;
            this.estimateGridView.Location = new System.Drawing.Point(0, 0);
            this.estimateGridView.Name = "estimateGridView";
            this.estimateGridView.Size = new System.Drawing.Size(284, 261);
            this.estimateGridView.TabIndex = 0;
            // 
            // Asterisk
            // 
            this.Asterisk.DataPropertyName = "Asterisk";
            this.Asterisk.HeaderText = "*";
            this.Asterisk.MaxInputLength = 2;
            this.Asterisk.Name = "Asterisk";
            this.Asterisk.Width = 20;
            // 
            // OpenItem
            // 
            this.OpenItem.DataPropertyName = "OpenItem";
            this.OpenItem.HeaderText = "O";
            this.OpenItem.Name = "OpenItem";
            this.OpenItem.Resizable = System.Windows.Forms.DataGridViewTriState.True;
            this.OpenItem.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
            this.OpenItem.Width = 30;
            // 
            // Desc
            // 
            this.Desc.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
            this.Desc.DataPropertyName = "Description";
            this.Desc.HeaderText = "Description";
            this.Desc.MaxInputLength = 60;
            this.Desc.Name = "Desc";
            // 
            // estimateLineBindingSource
            // 
            this.estimateLineBindingSource.DataSource = typeof(DataGridPaintingIssue.EstimateLineNet);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(284, 261);
            this.Controls.Add(this.estimateGridView);
            this.Name = "Form1";
            this.Text = "Form1";
            ((System.ComponentModel.ISupportInitialize)(this.estimateGridView)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.estimateLineBindingSource)).EndInit();
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.DataGridViewTextBoxColumn Asterisk;
        private OpenItemCheckBoxColumn OpenItem;
        private System.Windows.Forms.DataGridViewTextBoxColumn Desc;
        private System.Windows.Forms.DataGridView estimateGridView;
        private System.Windows.Forms.BindingSource estimateLineBindingSource;
    }
}

2 个答案:

答案 0 :(得分:0)

两个选项:

  1. 如果您只想将ReadOnly OpenItemCheckBoxCell涂成灰色,请在Paint方法的第一行添加以下内容:

    this.Style.BackColor = this.ReadOnly ? Color.Gray : Color.White;
    
  2. 但如果您希望任何 ReadOnly单元格显示为灰色,请在Form1构造函数中添加以下事件处理程序:

    estimateGridView.CellFormatting += estimateGridView_CellFormatting;
    
    private void estimateGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
    {
      DataGridViewCell cell = estimateGridView[e.ColumnIndex, e.RowIndex];
      cell.Style.BackColor = cell.ReadOnly ? Color.Gray : Color.White;
    }
    
  3. 在以下选项2中,您会注意到所有单元格都是ReadOnly。检查您的Form1.Designer,您就会知道原因。删除以下行:

    this.estimateGridView.ReadOnly = true;
    this.Asterisk.ReadOnly = true;
    this.OpenItem.ReadOnly = true;
    this.Desc.ReadOnly = true;
    

    现在您会注意到,您手动设置为ReadOnly的单元格不是OpenItemCheckBoxCell。进行以下更改并完成测试:

    private void setReadOnly()
    {
        estimateGridView.Rows[1].Cells[1].ReadOnly = true;
    }
    

    旁注:如果您按照选项2,则可以完全删除自定义CheckBoxColumnCheckBoxCell类。

    附加说明:如果您只想绘制实际的CheckBox背景灰色 - 而不是整个单元格背景 - 您将必须覆盖{{1}的绘制方法}。这是更多的工作,但您可以首先查看有关如何Create custom UI appearance for WinForms CheckBox的文章。在这种情况下,您不需要选项2。

答案 1 :(得分:0)

从多方面解决了这个问题几个星期之后,我发现每次刷新DataGrid绑定数据时,都会重新验证其所有CellTemplate。因此,它以前的所有ReadOnly值都会丢失。答案是每次刷新后再次设置ReadOnly值。

如果你像我一样使用Cell属性(比如ReadOnly)进行自定义绘制,请记住在每次DataGrid数据刷新时首先设置值并再次重新绘制单元格。

DataGrid数据刷新 - &gt;用默认值绘制的单元格 - &gt;设置自定义单元格属性 - &gt;重新粉刷细胞