【问题标题】:How do I color a row in a WinForm DataGridView and Hide the Column being used to set the color?如何在 WinForm DataGridView 中为一行着色并隐藏用于设置颜色的列?
【发布时间】:2021-04-09 19:21:05
【问题描述】:

我有一个数据网格视图,它可以根据通知列正确填充并为行着色。

我正在使用dataGridView1_CellFormatting 事件为行着色。

但是,当我发出隐藏列的命令时,我也会失去颜色。

dataGridView1.Columns["Notify"].Width = 0;

想使用颜色来节省网格中其他列的空间。将宽度设置为 0,即第二列仍显示该列的一部分。

当我添加 dataGridView1.Columns["Notify"].Visible = false; 时,我会丢失格式:

 private void PopulateLogs()
        {
            

            var logs = logManager.GetLogRecordsByDay(selectedDay);
            dataGridView1.DataSource = logs;

            dataGridView1.AllowUserToAddRows = false;
            dataGridView1.AllowUserToDeleteRows = false;
            dataGridView1.AllowUserToResizeRows = false;
            dataGridView1.Columns["Id"].Visible = false;
            dataGridView1.Columns["Notify"].Visible = false;
            dataGridView1.Columns["LogDateTime"].DefaultCellStyle.Format = "HH:mm";
            dataGridView1.Columns["LogDateTime"].Width = 20;
            dataGridView1.Columns["LogEntry"].Width = 100;
            dataGridView1.Columns["Analyst"].Width = 15;
            dataGridView1.AllowUserToAddRows = false;
        }
 private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {

            if (this.dataGridView1.Columns[e.ColumnIndex].Name == "Notify")
            {
                if (e.Value != null)
                {
                    string stringValue = (string)e.Value;
                    stringValue = stringValue.ToLower();
                    if ((stringValue.IndexOf("1") > -1))
                    {
                       this.dataGridView1.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.MistyRose;
                    }

                }
            }
             
        }

【问题讨论】:

  • 如果你隐藏一个列(设置它Visible = false),你不会丢失它。它仍然存在,并且可以访问相关的单元格。
  • 我更新了我的问题,当我添加 dataGridView1.Columns["Notify"].Visible = false;格式随列消失。
  • 我会使用RowPrePaint 事件,但通常当您的代码不起作用时,您需要发布代码而不是关于代码的故事。
  • 您不是在处理CellFormatting 来更改行的颜色吗? 他的格式如何在没有通知的情况下消失?您正在应用格式,因此您的代码有效或无效。只需发布该代码。
  • 因此,您正在检查是否正在格式化不可见的单元格。该列在不可见时可能仅格式化一次。正如建议的那样,使用RowPrePaintRowPostPaint 事件,因为您处理的是行的属性,而不是每个单元格的属性(CellFormatting 被提高了无数次)。只需根据dataGridView1["Notify", e.RowIndex].Value.ToString().Equals("0") 设置颜色即可。

标签: c# winforms datagridview


【解决方案1】:

这是对我有用的解决方案。谢谢吉米

private void gvLogs_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
{

    if (gvLogs["Notify", e.RowIndex].Value.ToString().Equals("1"))
    {
        this.gvLogs.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.MistyRose;
    }
 }

【讨论】:

    【解决方案2】:

    在现代编程中,人们倾向于将数据(= 模型)与数据的显示方式(= 视图)分开。

    通过这种方式,他们可以更改数据的显示方式,而无需更改模型。无需表单即可对模型进行单元测试,无需更改显示即可更改模型。

    您正在显示一系列日志项。特定显示日志项的颜色取决于日志项属性之一的值。

    class DislayedLogItem
    {
        public int Id {get; set;}
        public string Notify {get; set;}
        public DateTime LogTime {get; set;}
        ...
    }
    

    显然有一些关于值的东西让您想要更改行的背景颜色。您没有告诉我们有什么特别之处,但您需要这样的方法:

    // this displayed log item is special if property Notify contains the character '1'
    public bool IsSpecial => this.Notify.Contains('1');
    

    分开这一点的好处是,如果您后来决定显示的日志项是特殊的,因为它的日期早于 2000 年,那么这是唯一需要更改的地方。

    同样,您需要一个背景属性:

    private Color SpecialColor = Color.MystyRose;
    

    再次重申:这是为改变而设计的:如果您想要不同的颜色,只需改变一个地方。

    您可能已经使用 Visual Studio 设计器来添加列。每列显示您要显示的属性之一。构造函数中的概率:

    InitializeComponent();
    
    columnId.DataPropertyName = nameof(DisplayedLogItem.Id);
    columnLogTime.DataPropertyName = nameof(DisplayedLogItem.Log)
    columnAnalyst.DataPropertyName = nameof(DisplayedLogItem.Analyst);
    

    没有显示通知的列。无论如何,您都不想显示此列。

    但您确实想要的是,每当要添加“特殊”行时,您都想给它一个特殊的背景色。

    为此,您需要事件DataGridView.RowPrePaint

    private void OnRowPrepaint(object sender, DataGridViewRowPrePaintEventArgs e)
    {
        DataGridViewRow row = e.Row;
        DisplayedLogItem logItem = (DisplayedLogItem)row.DataBoundItem;
        if (logItem.IsSpecial)
           row.BackColor = this.SpecialColor;
    }
    

    也许您可以在添加行时执行此操作:DataGridView.RowsAdded 事件。

    显示所有 DisplayedLogItems

    您需要一个过程来获取需要显示的日志项目。超出问题范围:

    public IEnumerable<DisplayedLogItem> FetchLogItemsToDisplay()
    {
        ...
    }
    

    以下内容足以显示日志

    this.dataGridView1.DataSource = this.FetchLogItemsToDisplay().ToList();
    

    这足以显示数据。但是,如果您想在添加行时收到通知 / 删除/更新,你需要一个 BindingList:

    private BindingList<DisplayedLogItem> DisplayedLogItems
    {
        get => (BindingList<DisplayedLogItem>)this.dataGridView1.DataSource;
        set => this.dataGridView.DataSource = value;
    }
    

    显示,例如加载后:

    void Form_Loaded(object sender, ...
    {
        this.DisplayedLogItems = new BindingList<DisplayedLogItem>(
            this.FetchLogItemsToDisplay().ToList());
    }
    

    现在,每当操作员添加/删除/编辑一行时,都会在 DisplayedLogItems 中更新。因此,如果操作员指示他已完成数据编辑,例如通过单击确定按钮:

    void ButtonOk_Clicked(object sender, ...)
    {
        ICollection<DisplayedLogItem> editedLogItems = this.DisplayedLogItems;
        // find out which items are added / removed / changed and process them:
        this.ProcessEditedLogItems(editedLogItems);
    }
    

    如果您需要处理选定的行,以下内容可能会很有用:

    DisplayedLogItem CurrentLogItem => (DisplayedLogItem)this.dataGridView1.SelectedRow;
    
    IEnumerable<DisplayedLogItem> SelectedLogItems => this.dataGridView1.SelectedRows
        .Cast<DataGridViewRow>()
        .Select(row => row.DataBoundItem)
        .Cast<DisplayedLogItem>();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-31
      • 2011-05-29
      • 2014-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-06
      • 1970-01-01
      相关资源
      最近更新 更多