5

Does anybody know a way of disabling the line that appears when resizing datagridview rows and columns. This line flickers a lot, so I'd rather draw my own solid line myself and disable the default one.

enter image description here

I was hoping by drawing my own thick line (which I've done) it would draw over the top of the default flickering one, but unfortunately both lines then appear, the flickering one usually appears slightly to the right or left of my solid one. I don't think it's relevant, but code for drawing the line below.

Private Sub DataGridView1_Paint(sender As Object, e As PaintEventArgs) Handles DataGridView1.Paint

    If resizingColumns = True Then

        Dim penRed As Pen
        penRed = New Pen(color.Red, 3)

        Dim cursorPosition As Integer = Me.DataGridView1.PointToClient(New Point(Cursor.Position.X, Cursor.Position.Y)).X

        e.Graphics.DrawLine(penRed, cursorPosition, 0, cursorPosition, Me.DataGridView1.Size.Height)

    End If

End Sub

The only other alternative that I can think of (which I don't really want to do) is set AllowUserToResizeColumns to false (which would also hide the column resizing line) and then using the mouse events to resize the columns programmatically.

Any help or direction would be greatly appreciated.

Jarron
  • 1,049
  • 2
  • 13
  • 29
  • There's no control over that line. I think your thick line is not perfectly overlapping the flickering one because you are using the mouse pointer X coordinate and not the X coordinate of the actual separator between the cells (but I'm quite sure it will flicker anyway). I'm not even sure it's worth to manage the mouse events on your own in this case, it would take a lot of tweaking code (aka a lot of unexpected bugs). What about a 3d party control without that feature? – FandangoOnCore May 10 '20 at 16:15
  • Hi FandangoOnCore, yep you're right, the line isn't perfectly overlapping and the flickering line appears regardless. What do you mean by 3rd party control? – Jarron May 21 '20 at 22:31
  • I mean some other grid control from other companies. Maybe some of their grids don't have that moving line or at least it's customizable. You can refer to the answers on this [https://stackoverflow.com/questions/6008226/are-there-any-good-and-free-devexpress-data-grid-alternatives-for-winforms] to get some links to some of these 3d part grid controls (sorry I made a type in the previous answer). – FandangoOnCore May 22 '20 at 07:51

2 Answers2

1

I noticed that if you create a derived DataGridView and enable its DoubleBuffered property that the resizing indicator line does not appear. Using that information, I created the following proof-of-concept control that can be used in place of the base DataGridView control.

Public Class MyDGV : Inherits DataGridView
  Private resizePen As New Pen(Color.Red, 3)

  Public Sub New()
    MyBase.New
    DoubleBuffered = True
  End Sub

  Protected Overrides Sub Dispose(disposing As Boolean)
    MyBase.Dispose(disposing)
    If resizePen IsNot Nothing Then
      resizePen.Dispose()
      resizePen = Nothing
    End If
  End Sub

  Private ReadOnly Property InColumnResize As Boolean
    Get
      Return (MouseButtons = MouseButtons.Left) AndAlso (Cursor = Cursors.SizeWE)
    End Get
  End Property

  Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
    MyBase.OnMouseMove(e)
    If InColumnResize Then Invalidate()
  End Sub

  Protected Overrides Sub OnPaint(e As PaintEventArgs)
    MyBase.OnPaint(e)
    If InColumnResize Then
      Dim cursorPosition As Integer = Me.PointToClient(New Point(Cursor.Position.X, Cursor.Position.Y)).X
      e.Graphics.DrawLine(resizePen, cursorPosition, 0, cursorPosition, Me.Size.Height)
    End If
  End Sub

End Class

I needed to Invalidate the control during a resizing to remove the previously draw line. Perhaps just invalidating the area where the previous line would be better.

The property InColumnResize is admittedly a complete hack job; perhaps the logic you use to set resizingColumns is better.

TnTinMn
  • 11,522
  • 3
  • 18
  • 39
1

First of all, I apologise that I will post my samples in C#, please use Telerik's Converter to convert the code to VB.NET

Recently, I've been dealing a lot with this problem. I've researched and documented the whole framework just to see if there is any good way of achieving it, there was none.

When I saw your question, I have decided to take an hour, focus and to dig up some more and found a very messy way of achieving it, prior to the other messy way I've been using all along. For the interested programmers, what I did up until now was activate Double Buffering to DataGridView control, either through reflection or inheritance, mixing with WS_EX_COMPOSITED activation.

Which worked like this:

public class DataGridViewV2 : DataGridView
{

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle = cp.ExStyle | 0x02000000;
            return cp;
        }
    }

    public DataGridViewV2()
    {
        SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        SetStyle(ControlStyles.AllPaintingInWmPaint, true);
        SetStyle(ControlStyles.UserPaint, true);
        SetStyle(ControlStyles.DoubleBuffer, true);
    }
}

This greatly reduced the vertical splitter showing up. And it would suffice in most cases unless it really bothers the inconsistency of your design or you are a perfectionist.

Okay, now going to the current method I've just found:

This is the main method that draws our ugly problem, it is a private one we can do nothing to manipulate what it does. I've been jumping from code to code, and have found that it relies on a private variable called currentColSplitBar whether it will be drawn or not. Jackpot! All we have to do is use reflection, to edit the variable to always stick to -1 value to against the condition from drawing it on the PaintGrid method and it will never show up.

The drawing of the splitter starts once we click a cell's resizable divider and it lasts until we release the click, so naturally, we want to edit the variable on MouseDown event and MouseMove event. So all we have to do is reuse the previous method, while also, assign new handlers to these events.

 public class DataGridViewV2 : DataGridView
{

    public DataGridViewV2()
    {
        SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        SetStyle(ControlStyles.AllPaintingInWmPaint, true);
        SetStyle(ControlStyles.UserPaint, true);
        SetStyle(ControlStyles.DoubleBuffer, true);

        MouseDown += (sender, e) => PreventXOR_Region();
        MouseMove += (sender, e) => PreventXOR_Region();
    }

    private void PreventXOR_Region()
    {
        FieldInfo field = typeof(DataGridView).GetField("currentColSplitBar", BindingFlags.Instance | BindingFlags.NonPublic);
        field.SetValue(this, -1);
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle = cp.ExStyle | 0x02000000;
            return cp;
        }
    }
}

Messy, but it works!

Dezv
  • 156
  • 1
  • 8