Patrick Sears

Well, the subject line about sums it all up. I have a custom control that I am hosting in a DataGridView. I have created a DataGridView column and cell type to match my control, using the article How to: Host Controls in Windows Forms DataGridView Cells for guidance.

Let me give you a little more detail about the control.

The control I am hosting is intended to hold a user-configurable number of buttons (the control is aptly named MultiButtonControl). It consists of a UserControl, which holds a FlowLayoutPanel with Dock=Fill, AutoSize = True, AutoSizeMode = GrowAndShrink.

I add buttons to the control and the flow layout panel lays them out and expands for me. This works just fine and works beautifully as a normal Windows Forms control.

However, when I wrap this control in a class called MultiButtonEditingControl, which inherits from my MultiButtonControl and implements the IDataGridViewEditingControl interface, each time the control is activated in the DataGridView it flickers horribly. I have tried setting DoubleBuffer = True on the control itself, to no avail.

One last piece of information - the DataGridViewCell type I'm inheriting my data grid view cell from is DataGridViewImageCell. This means that for my FormattedValue property, I return a blank bitmap; and I override the Paint method and paint a MultiButtonControl for the cells which are not actively being edited.

So, any ideas as to why this is happening Is there some way to double buffer a data grid view cell

If I haven't been sufficiently clear about something, let me know.

Edit:
I should have added, I am using the following piece of code to automatically activate the button cells when the mouse passes over them.  This is to avoid the annoying double-click necessary to cause editing controls to become available.

   24     Private Sub DataGridView1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles DataGridView1.MouseMove
   25         Dim ht As DataGridView.HitTestInfo = DataGridView1.HitTest(e.X, e.Y)
   26 
   27         ' Can use this to auto-activate the control
   28         If Not ht Is DataGridView.HitTestInfo.Nowhere Then
   29             If ht.ColumnIndex >= 0 AndAlso ht.ColumnIndex < DataGridView1.Columns.Count Then
   30                 Dim col As DataGridViewColumn = DataGridView1.Columns(ht.ColumnIndex)
   31 
   32                 If TypeOf (col) Is DataGridViewMultiButtonColumn Then
   33                     If Not ht.RowIndex = DataGridView1.NewRowIndex AndAlso ht.RowIndex >= 0 _
   34                     AndAlso ht.RowIndex < DataGridView1.RowCount Then
   35                         'Console.WriteLine("Blah Blah Activating")
   36                         DataGridView1.CurrentCell = DataGridView1.Rows(ht.RowIndex).Cells(ht.ColumnIndex)
   37                         DataGridView1.BeginEdit(True)
   38                     Else
   39                         'Console.WriteLine("Blah blah")
   40                     End If
   41                 Else
   42                     'Console.WriteLine("Nope nope")
   43                 End If
   44             End If
   45         End If
   46     End Sub

Upon further inspection, the cells are flickering not when the mouse enters, the cell, but when it exits - when the DataGridView replaces the editing control with the image representing it.

I have tried deriving from DataGridView and enabling double buffering, but it doesn't help.

Any ideas



Re: Windows Forms General Custom control, custom DataGridViewColumn and Cell - horrible flicker.

theblueeyz

On a whim, I tried replacing returning an image of the control for the FormattedValue property, rather than a blank bitmap, and getting rid of the Paint() override.

This seemed to helped a little, but it still blinks terribly.

As a test, I took a look at some other activated editing control cells, and they all display this behavior, although not as bad.

Is this seriously something nobody has ever thought to fix





Re: Windows Forms General Custom control, custom DataGridViewColumn and Cell - horrible flicker.

theblueeyz

Ok. I found a way to sidestep the whole issue. After a great deal of analyzing, I have come to realize that the built-in DataGridView controls display the exact same flickering - it was just more noticeable in my case because my control is more colorful.

So I began thinking to myself.. Ok, this thing is simply displaying a row of buttons, side by side, with images on them. What if instead of having an embedded control, I simply add several DataGridViewButtonColumns and put images on the buttons

That seemed like a good idea. So I added the button columns.

And promptly discovered you can't place images on the buttons.

So I thought to myself, "That's got to be easy to fix." And sure enough, it was.

What follows is a VERY simple template for replacing the DataGridViewButtonColumn and extending the DataGridViewButtonCell to paint an image.

You're probably going to want to fill out the column with the rest of the normal DataGridViewButtonColumn's properties (like button text and FlatStyle etc), but I will leave that as an exercise to the reader.

For the C# purists, apologies, I didn't have a choice of language for this project..

Without further ado..

   43 Public Class ImageColumn
   44     Inherits DataGridViewColumn
   45 
   46     Public Sub New()
   47        MyBase.New(New ImageButtonCell())
   48 
   49        Dim style1 As DataGridViewCellStyle = New DataGridViewCellStyle()
   50        style1.Alignment = DataGridViewContentAlignment.MiddleCenter
   51        Me.DefaultCellStyle = style1
   52     End Sub
   53 
   54     Public Overrides Property CellTemplate() As DataGridViewCell
   55        Get
   56            Return MyBase.CellTemplate
   57        End Get
   58        Set(ByVal value As DataGridViewCell)
   59 
   60            ' Ensure that the cell used for the template is a ImageButtonCell.
   61            If (value IsNot Nothing) AndAlso _
   62               Not value.GetType().IsAssignableFrom(GetType(ImageButtonCell)) Then
   63               Throw New InvalidCastException("Must be an ImageButtonCell")
   64            End If
   65 
   66            MyBase.CellTemplate = value
   67        End Set
   68     End Property
   69 
   70     Public Overrides Property DefaultCellStyle() As DataGridViewCellStyle
   71        Get
   72            Return MyBase.DefaultCellStyle
   73        End Get
   74        Set(ByVal value As DataGridViewCellStyle)
   75            MyBase.DefaultCellStyle = value
   76        End Set
   77     End Property
   78 End Class
   79 
   80 Public Class ImageButtonCell
   81     Inherits DataGridViewButtonCell
   82 
   83     Protected Overrides Sub Paint(ByVal graphics As System.Drawing.Graphics, _
   84                               ByVal clipBounds As System.Drawing.Rectangle, _
   85                               ByVal cellBounds As System.Drawing.Rectangle, _
   86                               ByVal rowIndex As Integer, _
   87                               ByVal elementState As DataGridViewElementStates, _
   88                               ByVal value As Object, _
   89                               ByVal formattedValue As Object, _
   90                               ByVal errorText As String, _
   91                               ByVal cellStyle As DataGridViewCellStyle, _
   92                               ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle, _
   93                               ByVal paintParts As DataGridViewPaintParts)
   94        MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, _
   95                   value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)
   96 
   97        ' We want to draw the image scaled and centered on the button. 
   98        'First get the destination rectangle.
   99        Dim destRect As Rectangle = cellBounds
  100        destRect.Inflate(-4, -4)
  101        Dim srcRect As Rectangle = New Rectangle(New Point(0, 0), My.Resources.red_deletexs.Size)
  102 
  103        graphics.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
  104        graphics.DrawImage(My.Resources.red_deletexs, destRect, srcRect, GraphicsUnit.Pixel)
  105     End Sub
  106 End Class