10

I've created new Windows Forms Application (C#) with one simple form containing ListView. Then I have changed the View Property to Details and increased the size of the font used in this ListView and here's the result:

This is how it looks on Windows XP with Windows Classic theme:
enter image description here

and here's the result with Windows XP theme:
enter image description here

I can prevent the appearance of my application to be affected by Visual Styles either by removing Application.EnableVisualStyles() call or by changing the Application.VisualStyleState: enter image description here
Although this change makes the ListView to have the desired appearance, it also affects the appearance of other controls. I'd like my ListView to be the only control that is not affected by Visual Styles.

I've also found similar questions that try to deal with it:
Can you turn off visual styles/theming for just a single windows control?
How do I disable visual styles for just one control, and not its children?

Unfortunately, none of mentioned solutions works. It looks like the header itself would be made up of some controls that are affected by visual styles even when visual styles for ListView control are disabled.

Any C# solution that would prevent visual styles from affecting the appearance of the ListView header would be appreciated.

Community
  • 1
  • 1
LihO
  • 41,190
  • 11
  • 99
  • 167

5 Answers5

3

Looks like this is a known bug for which there is no easy workaround. According to the answer there:

After doing a lot of research with this issue, we find that this is a windows OS bug, which the ComCtl6.0 header control forgets to apply the font information to the drawing DC.

However you could draw the column header yourself. See this article on MSDN for details on how to do it and also look at listView1_DrawColumnHeader.

Botz3000
  • 39,020
  • 8
  • 103
  • 127
  • Drawing it myself won't help at all since you are able to change only the content that is being drawn, not the size of the header. – LihO Apr 16 '12 at 09:58
3

After exhausting research, I found it out. The thing is that when you call

SetWindowTheme(this.Handle, "", "");

within custom ListView class, it prevents visual styles from affecting the appearence of the ListView control but not the ListView header control (SysHeader32 window), which is child window of ListView. So when calling the SetWindowTheme function, we need to provide the handle of the header window instead of the handle of the ListView:

[DllImportAttribute("uxtheme.dll")]
private static extern int SetWindowTheme(IntPtr hWnd, string appname, string idlist);

[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);

// Callback method to be used when enumerating windows:
private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
    GCHandle gch = GCHandle.FromIntPtr(pointer);
    List<IntPtr> list = gch.Target as List<IntPtr>;
    if (list == null)
        throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
    list.Add(handle);
    return true;
}

// delegate for the EnumChildWindows method:
private delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);

// get first child:
private static void DisableVisualStylesForFirstChild(IntPtr parent)
{
    List<IntPtr> children = new List<IntPtr>();
    GCHandle listHandle = GCHandle.Alloc(children);
    try
    {
        EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
        EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
        if (children.Count > 0)
            SetWindowTheme(children[0], "", "");
    }
    finally
    {
        if (listHandle.IsAllocated)
            listHandle.Free();
    }
}

protected override void OnHandleCreated(EventArgs e)
{
    DisableVisualStylesForFirstChild(this.Handle);
    base.OnHandleCreated(e);
}
LihO
  • 41,190
  • 11
  • 99
  • 167
  • Since it's based on the solution suggested by Kamil Lach, I'm awarding his answer with bounty I offered. – LihO Apr 17 '12 at 14:12
2

What about disable visual styles ?

with this code you could disable style for one control (just use ListViewConstrol instead of ListView):

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class ListViewControl : ListView {
  [DllImportAttribute("uxtheme.dll")]
  private static extern int SetWindowTheme(IntPtr hWnd, string appname, string idlist);

  protected override void OnHandleCreated(EventArgs e) {
    SetWindowTheme(this.Handle, "", "");
    base.OnHandleCreated(e);
  }
}
Kamil Lach
  • 4,519
  • 2
  • 19
  • 20
0

As Botz3000 mentioned in his answer that its a well known problem with ListView in Windows XP. Another workaround is to register ListView.DrawColumnHeader event and reset the header font in it. You must set ListView.OwnerDraw property to true. MSDN code is as follows;

// Draws column headers.
private void listView1_DrawColumnHeader(object sender,
    DrawListViewColumnHeaderEventArgs e)
{
    using (StringFormat sf = new StringFormat())
    {
        // Store the column text alignment, letting it default
        // to Left if it has not been set to Center or Right.
        switch (e.Header.TextAlign)
        {
            case HorizontalAlignment.Center:
                sf.Alignment = StringAlignment.Center;
                break;
            case HorizontalAlignment.Right:
                sf.Alignment = StringAlignment.Far;
                break;
        }

        // Draw the standard header background.
        e.DrawBackground();

        // Draw the header text.
        using (Font headerFont =
                    new Font("Helvetica", 10, FontStyle.Bold))
        {
            e.Graphics.DrawString(e.Header.Text, headerFont,
                Brushes.Black, e.Bounds, sf);
        }
    }
    return;
}

In this case the header font will always be "Helvetica", 10, FontStyle.Bold and will not be effected by listview font. Check MSDN for further details.

Community
  • 1
  • 1
ABH
  • 3,391
  • 23
  • 26
  • No, OwnerDraw is not the way, it's not possible to affect the height of ListView header with it. – LihO Apr 16 '12 at 09:59
  • @LihO It's not doing anything with the height of the header as it's not possible in XP. Please read my answer carefully, the idea is to keep the header text smaller so that it fits within the header. – ABH Apr 16 '12 at 11:23
  • But my question is how to "make the ListView header have the correct height", not how to make the header text smaller... – LihO Apr 16 '12 at 12:24
  • I found out why SetWindowTheme didn't work before. It works now, check out my answer ;) – LihO Apr 17 '12 at 14:08
0

Here's how to make the ListView header have the height you want:

C# - Listview colum header height (Windows Form)

Community
  • 1
  • 1
Pedery
  • 3,632
  • 1
  • 27
  • 39