简体   繁体   中英

How do I color a row in a WinForm DataGridView and Hide the Column being used to set the color?

I have a datagridview that fills correctly and colors the rows based on the Notify column.

示例网格

I am using the dataGridView1_CellFormatting event to color the row.

However when I issue the command to hide the column I lose the color as well.

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

Would like to use the color to save the space in the grid for other columns. Setting the width to 0 ie the second column still shows part of the column.

When I add dataGridView1.Columns["Notify"].Visible = false; I loose the formatting:

在此处输入图像描述

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

                }
            }
             
        }

This is the solution that worked for me. Thanks Jimi

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

In modern programming people tend to separate the data (= model) from the way that this data is displayed (= view).

This way they can change the way that data is displayed without having to change the model. You can unit test the model without needing a form, and you can change the model without having to change the display.

You are displaying a sequence of log items. The color of a particular displayed log item depends on the value of one of the log item properties.

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

Apparently there is something about the value that makes your want to change the back color of the row. You didn't tell us what is so special, but you need a method like:

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

The nice thing of separating this, is that if you later decide that a displayed log item is special because it has a date before the year 2000, this is the only place that needs to change.

Similarly, you want a property for the background:

private Color SpecialColor = Color.MystyRose;

Again: this is designed for change: only one place that has to be changed if you want a different color.

You've probably used the visual studio designer to add the columns. Every Column displays one of the properties that you want to show. Probaby in the constructor:

InitializeComponent();

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

No column to display Notify. You didn't want to show this column anyway.

But what you do want, is whenever a "special" row is about to be added, you want to give it a special backcolor.

For this you need event 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;
}

Maybe you can do this when a row is added: DataGridView.RowsAdded event.

Displaying all DisplayedLogItems

You need a procedure to fetch the Log items that need to be displayed. Out of scope of the question:

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

The following is enough to display the log

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

This is enough to show the data. However, if you want to be notified when rows are added / removed / updated, you need a BindingList:

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

To display, for instance after loading:

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

Now whenever the operator Adds / Removes / Edits a row, this is updated in the DisplayedLogItems. So if the operator indicates that he has finished editing the data, for instance by clicking the Ok button:

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

The following might be useful if you need to process selected rows:

DisplayedLogItem CurrentLogItem => (DisplayedLogItem)this.dataGridView1.SelectedRow;

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM