Friday, 24 October 2008

Using RowPrePaint event of a DataGridView control

To draw a row in a DataGridView control in a different style depending on a certain condition, you can use the RowPrePaint event to interrupt the painting of the rows in the grid.

You then have a choice of which parts of the row to be painted automatically and which parts to paint yourself via the PaintParts event property.

In the code below, I paint a row with a custom brush, depending on the value of a column that is named 'Error'.

   1:  /// <summary>
   2:  /// Handles the drawing of each DataGridView row depending on set log error state.
   3:  /// </summary>
   4:  /// <param name="sender"></param>
   5:  /// <param name="e"></param>
   6:  private void setLogDataGridView_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
   7:  {
   8:      // Paint all parts of row except SelectionBackground and the Focus box.
   9:      e.PaintParts = DataGridViewPaintParts.All & ~(DataGridViewPaintParts.SelectionBackground | DataGridViewPaintParts.Focus);
  10:   
  11:      // Get the value of the error column of the current row
  12:      string val = this.setLogDataGridView.Rows[e.RowIndex].Cells["Error"].Value.ToString();
  13:   
  14:      if (val != "0")
  15:      {
  16:           // Get rectangle of area to paint with custom brush.
  17:            Rectangle rowBounds = new Rectangle(
  18:             this.setLogDataGridView.RowHeadersWidth, e.RowBounds.Top,
  19:             this.setLogDataGridView.Columns.GetColumnsWidth(
  20:             DataGridViewElementStates.Visible) -
  21:             this.setLogDataGridView.HorizontalScrollingOffset + 1,
  22:             e.RowBounds.Height);
  23:   
  24:      // Disable normal painting of backgrounds.
  25:      e.PaintParts &= ~(DataGridViewPaintParts.Background | DataGridViewPaintParts.ContentBackground);
  26:   
  27:      e.PaintHeader(false);
  28:   
  29:      // Paint the custom background.
  30:      using (Brush lgb = new LinearGradientBrush(rowBounds, Color.Red,
  31:             Color.DarkRed, LinearGradientMode.Vertical))
  32:      {
  33:          e.Graphics.FillRectangle(lgb, rowBounds);
  34:      }
  35:   
  36:      // Set the text colour.
  37:      this.setLogDataGridView.Rows[e.RowIndex].DefaultCellStyle.ForeColor = Color.Yellow;
  38:      this.setLogDataGridView.Rows[e.RowIndex].DefaultCellStyle.SelectionForeColor =      Color.Yellow;
  39:      }
  40:  }

Create a User business object

To create a business object that represents a 'User' of my Datalog application, I have used the code shown below, and it works well for my purposes. I decided to make it a Struct instead of a Class as it is a small and lightweight object. If any readers think that it should preferably be a Class, then please leave a comment. I'm still learning this stuff, so any tips welcome!

   1:  using System;
   2:   
   3:  namespace KAS.Datalog
   4:  {
   5:      /// <summary>
   6:      /// Represents a user of the application.
   7:      /// </summary>
   8:      public struct User
   9:      {
  10:          #region Fields
  11:   
  12:          private string _strName;
  13:          private UserLevel _userLevel;
  14:   
  15:          #endregion
  16:   
  17:          #region Properties
  18:   
  19:          /// <summary>
  20:          /// Gets or sets the user name.
  21:          /// </summary>
  22:          public string Name
  23:          {
  24:              get { return this._strName; }
  25:              set { this._strName = value; }
  26:          }
  27:   
  28:          /// <summary>
  29:          /// Gets or sets the user level.
  30:          /// </summary>
  31:          public UserLevel Level
  32:          {
  33:              get { return this._userLevel; }
  34:              set { this._userLevel = value; }
  35:          }
  36:   
  37:          #endregion
  38:   
  39:          #region Constructor
  40:   
  41:          /// <summary>
  42:          /// Constructor
  43:          /// </summary>
  44:          /// <param name="name">Name of the user</param>
  45:          /// <param name="level">Secutirty level</param>
  46:          public User(string name, UserLevel level)
  47:          {
  48:              if (name != "") { this._strName = name; }
  49:              else { this._strName = "Unknown"; }
  50:   
  51:              this._userLevel = level;
  52:          }
  53:   
  54:          #endregion
  55:   
  56:          #region Overridden methods
  57:   
  58:          public override string ToString()
  59:          {
  60:              return this._strName + "," + this._userLevel.ToString();
  61:          }
  62:   
  63:          #endregion
  64:      }
  65:  }