none
DataGridView Cell style only works after DataGridView is shown once. RRS feed

  • 質問

  • Hi there,

    I wrote a windows form app with several DataGridView controls on several tabs to display various information. I compare cells and sets some cell font color to red and underline when the compared values are not as expected.
    Here is an example :

    Code Snippet

                //Set font color
                Font oF = new Font("Arial", 8, FontStyle.Underline);
                //Set Source
                dtgvDrives.DataSource = in_aDriveList;
                for (int i = 0; i < in_aDriveList.Count; i++)
                {
                    if ((in_aDriveList[i].FreeSpaceInBytes * 10) > in_aDriveList[i].SizeInBytes)
                    {
                        dtgvDrives[5, i].Style.ForeColor = Color.Black;
                    }
                    else
                    {
                        dtgvDrives[5, i].Style.Font = oF;
                        dtgvDrives[5, i].Style.ForeColor = Color.Crimson;
                    }
                }
              dtgvDrives.Refresh();



    This style change works fine only when the DataGridView control has been displayed at least once after the application main form was loaded. That means that when I run the app and cycle through each tab, then run the tests, the cells that should be red are red.
    If I start the application, and run the test directly, without previously cycling through all tabs to display each DataGridView once, the style does not apply on the cells.
    However, after running the test, when I programmatically check if a cell font is red, it says it is even though it is not (but should be) when I click on the tab to display the DataGridView.

    Anyboy has any idea how to overcome that ?
    Am I missing something ?

    Thanks
    Philippe
    2007年4月20日 15:15

回答

  • I can't reproduce your problem with this simple test program:

      public partial class Form1 : Form {
        public Form1() {
          InitializeComponent();
          dataGridView1.Columns.Add(new DataGridViewTextBoxColumn());
          dataGridView1.Rows.Add("nobugz");
          dataGridView1.Rows[0].Cells[0].Style.ForeColor = Color.Crimson;
        }
      }

    The typical reason for seeing this kind of problem (can see changes in the debugger but not on the screen) is that you've accidentally created a new instance of the form instead of referencing the existing instance.
    2007年4月22日 12:19
    モデレータ

すべての返信

  • I can't reproduce your problem with this simple test program:

      public partial class Form1 : Form {
        public Form1() {
          InitializeComponent();
          dataGridView1.Columns.Add(new DataGridViewTextBoxColumn());
          dataGridView1.Rows.Add("nobugz");
          dataGridView1.Rows[0].Cells[0].Style.ForeColor = Color.Crimson;
        }
      }

    The typical reason for seeing this kind of problem (can see changes in the debugger but not on the screen) is that you've accidentally created a new instance of the form instead of referencing the existing instance.
    2007年4月22日 12:19
    モデレータ
  • Hi there,

    Thanks for the answer. Your code works fine indeed, so it must be a glitch somewhere in my code (can't find it though) ...

    I will keep looking and will keep you posted.

    Thanks again

    Philippe

    2007年4月24日 15:22
  • Hi Again,

    I found a way to repro my problem.

    The thing is, I am not creating the DataGridView like you do. I use a class object (in this example it is called cTest) as DataSource for the grid. And in that case, if the DataGridView is not visible, the problem occurs. 

    1- On Form1, put a Tab control with the default 2 TabPages.

    2- On TabPage1, put a Button (button1), with the text "Red".

    3- On TabPage2, put an empy DataGridView (dataGridView1) docked in the page.

     

    Then paste the following code in the Form1.cs file:

     

    Code Snippet

    namespace DataGridViewTest

    {

    public partial class Form1 : Form

    {

    public Form1()

    {

    InitializeComponent();

    CreateDataGridView(dataGridView1);

    }

    private void button1_Click(object sender, EventArgs e)

    {

    ChangeColor(dataGridView1, button1.Text);

    }

    private void ChangeColor(DataGridView in_oDat, string in_sColor)

    {

    Color oCol = new Color();

    if (in_sColor == "Red")

    {

    button1.Text = "Black";

    oCol = Color.Crimson;

    }

    else

    {

    button1.Text = "Red";

    oCol = Color.Black;

    }

    for (int i = 0; i < in_oDat.Rows.Count; i++)

    {

    in_oDat.Rows[i].Cells[0].Style.ForeColor = oCol;

    }

    }

    private void CreateDataGridView(DataGridView in_oDat)

    {

    List<cTest> aList = new List<cTest>();

    for (int i = 0; i < 10; i++)

    {

    cTest oTest = new cTest("Phil" + i.ToString(), "Test" + i.ToString());

    aList.Add(oTest);

    }

    in_oDat.DataSource = aList;

    in_oDat.RowHeadersVisible = false;

    }

    }

    public class cTest

    {

    public cTest(string sFirst, string sLast)

    {

    this.FirstName = sFirst;

    this.LastName = sLast;

    }

    private string m_FirstName = string.Empty;

    private string m_LastName = string.Empty;

    public string FirstName

    {

    get { return m_FirstName; }

    set { m_FirstName = value; }

    }

    public string LastName

    {

    get { return m_LastName; }

    set { m_LastName = value; }

    }

    }

    }

     

    Now try this :

    1- Run the app a first time, do not switch to TabPage2

    2- Click on the button "Red".

    3- Switch to TabPage2 : the first column of text in the grid is still black (it should be red then).

    4- Go back to the TabPage1, click on button1 ("Black") to revert to black text, then click again to apply red to the text.

    5- Switch back to TabPage2 : this time, it worked fine ...

     

    Now this way :

    1- Close down the App, restart it.

    2- Once the form is displayed, switch right away to TabPage2 : All text in the DataGridView is black as it should be.

    3- Switch to TabPage1, click on "Red".

    4- Switch to TabPage2 -> The text in column 1 is red ... because the DataGridView was displayed once before ...

     

    Any idea why ?

     

    Thanks

    Philippe

    2007年4月24日 19:55
  • Looks like a bit of a bug to me, the DGV applies the DefaultStyle to the cells when it becomes visible.  Here's a workaround:

          for (int i = 0; i < in_oDat.Rows.Count; i++) {
            if (!in_oDat.RowsIdea.Cells[0].HasStyle)
              in_oDat.RowsIdea.Cells[0].Style = in_oDat.DefaultCellStyle;
            in_oDat.RowsIdea.Cells[0].Style.ForeColor = oCol;
          }

    2007年4月24日 20:36
    モデレータ
  • Hi,

     

    I tried the workaround, but it does not really help : now the whole grid becomes red ... not only a specific cell ...

    I am missing something ?

     

    Thanks

    Philippe

     

    2007年4月24日 21:02
  • I have a similar problem, only I don't get an opportunity to refresh my screen.

     

    My problem is that I would like to display the significance of some cells dynamically, but when I set the cell level style it gets ignored, as with Philippe's problem. I can however, set the style for whole columns, column headers and row headers, as well as alternating row styles, but I cannot set individual row styles or single cell styles.

     

    My investigations show that the styles are being set (when viewed in the debugger), and they are not being overridden by inheritance, but as soon as the form displays, they are gone!

     

    If anyone can help Philippe or myself I would really appreciate it.

    Ross

     

    2007年5月1日 1:33
  • Hi Ross and all.

     

    I actually found a workaround to my problem : I only check the cells values after entering the TabPage (so that the DatagridView  is displayed).

    Do you set a "DefaultCellStyle" when first creating the grid ? There may need to be one before a new "non-default" one can be applied (just guessing).

     

    Philippe 

    2007年5月1日 17:23
  • Thanks for that Philippe,

     

    I found a workaround for my problem too. I have decided to present my form to the end user and invite them to apply the cell styling using other controls on the form. This isn't quite as slick, but it certainly gets around the problem, and the information can be presented, if the end user chooses.

     

    It is annoying though to have to resort to such a 'fix'. I suspect what is going wrong happens when the datagridview control is first painted, something in those final presentation routines is losing any individual row or cell styling overrides. This isn't happening once the form has been displayed. So I label this one a Microsoft bug, with no currently effective solution or workaround.

     

    Ross

    2007年5月3日 3:09
  • I'm not sure that this behaviour is actually a bug. I just think its poorly documented.

     

    A paragraph from the MSDN page talking about how styles are applied is significant:

    Each of the style properties has a corresponding PropertyNameChanged event on the DataGridView control. For row, column, and cell properties, the name of the event begins with "Row", "Column", or "Cell" (for example, RowDefaultCellStyleChanged). Each of these events occurs when the corresponding style property is set to a different DataGridViewCellStyle object. These events do not occur when you retrieve a DataGridViewCellStyle object from a style property and modify its property values. To respond to changes to the cell style objects themselves, handle the CellStyleContentChanged event.

     

    I think that hilighted sentence is the problem you are running into when you do this:

    Code Snippet

    in_oDat.Rows[i].Cells[0].Style.ForeColor = oCol;

     

    So add this line to your example program and see if it helps:

     

    Code Snippet

     

    private void ChangeColor(DataGridView in_oDat, string in_sColor)

    {

     Color oCol = new Color();

     if (in_sColor == "Red")

     {

      button1.Text = "Black";

      oCol = Color.Crimson;

     }

     else

     {

      button1.Text = "Red";

      oCol = Color.Black;

     }

     for (int i = 0; i < in_oDat.Rows.Count; i++)

     {

      in_oDat.Rows[i].Cells[0].Style.ForeColor = oCol;

     }

     dataGridView1.InvalidateColumn(0); 

    }

     

    Does it work? (note there is also InvalidateCell() and InvalidateRow() )

     

     I hope that works (I haven't had a chance to test it myself sorry)

     

    Regards

    Jero

    2007年5月4日 3:17
  • I tried this out and it didn't work for me. Just want to put this out there for anyone else who read this thread.
    • 回答の候補に設定 ZenithSP 2009年10月9日 19:48
    2009年2月13日 4:23
  • I found a workaround:
    For applying cell styles handle the RowsAdded event of DataGridView.

     

    2009年10月9日 19:53
  • It solves for me.

    The only drawback is that this event is fired many times when the grid is binded to a datasorce.


    Mds
    2010年3月28日 15:13
  • Put the styling in frm.shown and your done.

    2016年2月12日 8:27
  • old post but I stumbled as I had the same problem. Seems like I've mistakenly overwritten the style in CellFormatting, so the default inherited style render that new style I'm trying to put in useless. Overriding the style works. Didn't even need to InvalidateCell nor InvalidateColumn

     foreach (DataGridViewRow curRow in trainDataGridView.Rows)
                {
                   
                    curRow.Cells[colIndex].Style = new DataGridViewCellStyle()
                    {
                        ForeColor = Color.Green,
                        BackColor = Color.Red
                       
                    };

    }


    Kenneth Zhang

    2019年6月11日 9:34