MVC 5 Dynamic Rows with Begincollectionitem

How to prevent rows in datagrid from flickering while application is running

Two suggestions:

  1. Try calling SuspendLayout() prior to the loop and ResumeLayout() after the loop. Most other controls call this BeginUpdate() and EndUpdate() (Listviews, Combobox's etc).
  2. Use VirtualMode on DataGridView if you're dealing with large amount of
    data.

Flickering during updates to Controls in WinForms (e.g. DataGridView)

Rather than adding the rows of the data grid one at a time, use the DataGridView.Rows.AddRange method to add all the rows at once. That should only update the display once. There's also a DataGridView.Columns.AddRange to do the same for the columns.

Scrolling in DataGridView causes overwritten text

Ok, I got It to work with a combination of TaW's anwser in the comment and adding

    e.CellStyle.BackColor = Color.White;
e.CellStyle.SelectionBackColor = Color.White;

to the beginning of the CellFormatting method.
Funny that the backgroundcolor gets set to black if you use the double buffer, but remains white (like I defined) if you I do not.

DataGridView scrolling behaviour

DataGridView was not designed that way.

It's completely impossible, unless you rewrite substantial portions of the control.

Most grid controls, including Excel, Access, and Outlook, as well as most if not all 3rd-party .Net grids, have the same limitation.

Problem while scrolling merged Header Cells of a DataGridView

A few modifications to the drawing procedure:

  • The custom Header drawing Rectangle is sized calculating the Width of all the Columns in the specified Range.
  • The position of the drawing area is calculated using the left-most Column's position, the RowHeadersWidth and the current DataGridView.HorizontalScrollingOffset, which defines the horizontal scroll position of the client rectangle.
  • To draw the custom Header, a clipping region is created - using Graphics.SetClip() - to exclude the Row Header from the drawing area.
  • The custom Header is only rendered when visible on screen.
  • I'm using TextRenderer.DrawText instead of Graphics.DrawString(), since this is the method used by this control to render its content.
  • Hence, I'm calculating the height of the text bounds using TextRenderer.MeasureText()
  • TextFormatFlags.PreserveGraphicsClipping is used to instruct TextRenderer not to draw the text outside the clipping region of the Graphics object.

Note 1: I've added Double-Buffering to the DataGridView, to avoid any flickering when clicking the Header Cells. It may have an impact when the grid needs to render a high number of Rows.

Note 2: You can remove all those InvalidateHeader() calls, not needed here.

► This new behavior allows to reset the range of Columns to include in the custom Header and the Header's Text at any time (as shown in the visual example).


This is how it looks now:

DataGridView Custom Merged Header



using System.Reflection;

TextFormatFlags centerTopflags =
TextFormatFlags.HorizontalCenter | TextFormatFlags.Top | TextFormatFlags.PreserveGraphicsClipping;
string mergedHeaderText = string.Empty;
int[] mergedColumns = null;

public void SomeForm()
{
this.InitializeComponent();
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
dgvTest.GetType().GetProperty("DoubleBuffered", flags).SetValue(dgvTest, true);
mergedColumns = new int[] { 20, 21 };
mergedHeaderText = "DOOR CLOSER"
}

private void dgv_db_door_Paint(object sender, PaintEventArgs e)
{
var dgv = sender as DataGridView;
var headerStyle = dgv.ColumnHeadersDefaultCellStyle;
int colsWidth = -1;
int colsLeft = 1;

// Absolute Width of the merged Column range
for (int i = 0; i < mergedColumns.Length; i++) {
var col = dgv.Columns[mergedColumns[i]];
colsWidth += col.Visible ? col.Width : 0;
}

// Absolute Left position of the first Column to merge
if (mergedColumns[0] > 0) {
colsLeft += dgv.Columns.OfType<DataGridViewColumn>()
.Where(c => c.Visible).Take(mergedColumns[0]).Sum(c => c.Width);
}

// Merged Headers raw drawing Rectangle
var r = new Rectangle(
dgv.RowHeadersWidth + colsLeft - dgv.HorizontalScrollingOffset, 2,
colsWidth, dgv.ColumnHeadersHeight);

// Measure the Height of the text to render - no wrapping
r.Height = TextRenderer.MeasureText(e.Graphics, mergedHeaderText, headerStyle.Font, r.Size, centerTopflags).Height;

// Draw the merged Headers only if visible on screen
if (r.Right > dgv.RowHeadersWidth || r.X < dgv.DisplayRectangle.Right) {
// Clip the drawing Region to exclude the Row Header
var clipRect = new Rectangle(
dgv.RowHeadersWidth + 1, 0,
dgv.DisplayRectangle.Width - dgv.RowHeadersWidth, dgv.ColumnHeadersHeight);
e.Graphics.SetClip(clipRect);

using (var brush = new SolidBrush(headerStyle.BackColor)) e.Graphics.FillRectangle(brush, r);
TextRenderer.DrawText(e.Graphics, mergedHeaderText, headerStyle.Font, r, headerStyle.ForeColor, centerTopflags);
e.Graphics.ResetClip();
}
}


Related Topics



Leave a reply



Submit