question

Arsium-4135 avatar image
0 Votes"
Arsium-4135 asked Arsium-4135 commented

Draw Non Column Area ListView

Hello,

This is my second question while dealing with custom ListView. I'm wondering how to draw in non column area ?

122828-capture-decran-654.png


dotnet-csharp
· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@Arsium-4135
Could you please show the code you have so that we can move on based on yours?

0 Votes 0 ·

You can draw in WM_ERASEBKGND
But I tested with Custom Draw, not Owner Draw :

122999-header-paintbackground.gif


0 Votes 0 ·

How did you do that ?

0 Votes 0 ·

1 Answer

Castorix31 avatar image
0 Votes"
Castorix31 answered Arsium-4135 commented

After some tests, WM_ERASEBKGND works in C++, but not in C#
But WM_PAINT works :
123272-header-paint.jpg


I added in your ListView class you posted in another thread :

 private int WindowSubClass(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam, IntPtr uIdSubclass, uint dwRefData)
 {
     switch (uMsg)
     { 
         case WM_PAINT:
             {
                 DefSubclassProc(hWnd, uMsg, wParam, lParam);
                 IntPtr hDC = GetDC(hWnd);
                 RECT rect = new RECT();
                 GetClientRect(hWnd, out rect);
                 int nItemCount = SendMessage(hWnd, HDM_GETITEMCOUNT, 0, IntPtr.Zero);
                 int nWidth = 0;
                 for (int i = 0; i < nItemCount; i++)
                 {
                     RECT itemRect = new RECT();
                     SendMessage(hWnd, HDM_GETITEMRECT, i, ref itemRect);
                     nWidth += (itemRect.right - itemRect.left);
                 }
                 using (Graphics g = Graphics.FromHdc(hDC))
                 {
                     System.Drawing.Rectangle rectRight = new System.Drawing.Rectangle(nWidth, rect.top, rect.right, rect.bottom);
                     g.FillRectangle(new SolidBrush(Color.Orange), rectRight);
                 } 
                 ReleaseDC(hWnd, hDC);
                 return 0;
             }                   
     }
     return DefSubclassProc(hWnd, uMsg, wParam, lParam);
 }
 public const int WM_PAINT = 0x000F;
 public const int LVM_FIRST = 0x1000;
 public const int LVM_GETHEADER = (LVM_FIRST + 31);
    
 public const int HDM_FIRST = 0x1200;
 public const int HDM_GETITEMCOUNT = (HDM_FIRST + 0);
 public const int HDM_GETITEMRECT = (HDM_FIRST + 7);
    
 [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
 public static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, IntPtr lParam);
    
 [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
 public static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, ref RECT lParam);
    
 [DllImport("User32.dll", SetLastError = true)]
 public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
    
 [DllImport("User32", ExactSpelling = true, CharSet = CharSet.Auto)]
 public static extern IntPtr GetDC(IntPtr hWnd);
    
 [DllImport("User32", ExactSpelling = true, CharSet = CharSet.Auto)]
 public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
    
 [StructLayout(LayoutKind.Sequential)]
 public struct RECT
 {
     public int left;
     public int top;
     public int right;
     public int bottom;
     public RECT(int Left, int Top, int Right, int Bottom)
     {
         left = Left;
         top = Top;
         right = Right;
         bottom = Bottom;
     }
 }
    
 public delegate int SUBCLASSPROC(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam, IntPtr uIdSubclass, uint dwRefData);
    
 [DllImport("Comctl32.dll", SetLastError = true)]
 public static extern bool SetWindowSubclass(IntPtr hWnd, SUBCLASSPROC pfnSubclass, uint uIdSubclass, uint dwRefData);
    
 [DllImport("Comctl32.dll", SetLastError = true)]
 public static extern int DefSubclassProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
    
 private SUBCLASSPROC SubClassDelegate = null;
    
    
 private IntPtr hWndHeader = IntPtr.Zero;
 protected override void OnCreateControl()
 {
     hWndHeader = (IntPtr)SendMessage(this.Handle, LVM_GETHEADER, 0, IntPtr.Zero);
     SubClassDelegate = WindowSubClass;
     if (SubClassDelegate != null)
         SetWindowSubclass(hWndHeader, SubClassDelegate, 0, 0);
 }





header-paint.jpg (20.4 KiB)
· 6
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I've tried the code and it works perfectly with my C# code !!!

0 Votes 0 ·

I don't understand the whole code but it works as expected !

0 Votes 0 ·

I just subclass the Header control to draw after its Paint event
I used a C++ way, but could be done with a class inherited from NativeWindow
I assumed the Header is displayed from left to right, which can be different (right to left or vertical) and the calculation of the rectangle for FillRectangle should change...

0 Votes 0 ·

Thx for explanation !

Also this :

         protected override void OnPaint(PaintEventArgs e)
         {
             base.OnPaint(e);
         }

is dead since we handle WM_Paint directly from WM !


0 Votes 0 ·
Show more comments