C# 影响ListView标题的Windows主题

C# 影响ListView标题的Windows主题,c#,winforms,visual-c++,listview,windows-xp,C#,Winforms,Visual C++,Listview,Windows Xp,我用一个包含ListView的简单表单创建了新的Windows窗体应用程序(C#)。然后我将更改为“详细信息”,并增加了此ListView中使用的字体大小,结果如下: 这是Windows XP上Windows经典主题的外观: 下面是Windows XP主题的结果: 我可以通过删除调用或更改 : 尽管此更改使ListView具有所需的外观,但也会影响其他控件的外观。我希望我的ListView成为不受视觉样式影响的唯一控件 我还发现了类似的问题,试图解决它: 不幸的是,上述解决方案都不起作

我用一个包含ListView的简单表单创建了新的Windows窗体应用程序(C#)。然后我将更改为“详细信息”,并增加了此ListView中使用的字体大小,结果如下:

这是Windows XP上Windows经典主题的外观:

下面是Windows XP主题的结果:

我可以通过删除调用或更改 :
尽管此更改使ListView具有所需的外观,但也会影响其他控件的外观。我希望我的ListView成为不受视觉样式影响的唯一控件

我还发现了类似的问题,试图解决它:

不幸的是,上述解决方案都不起作用标题本身似乎由一些受视觉样式影响的控件组成,即使在禁用ListView控件的视觉样式时也是如此。


任何可以防止视觉样式影响ListView标题外观的C#解决方案都将受到欢迎。

禁用视觉样式怎么样

使用此代码,您可以禁用一个控件的样式(只需使用ListViewControl而不是ListView):

看起来这是一个很难解决的问题。根据那里的答案:

在对这个问题做了大量研究之后,我们发现这是一个 windows操作系统错误,ComCtl6.0标头控件忘记应用该错误 将字体信息发送到图形DC

但是,您可以自己绘制列标题。有关如何执行此操作的详细信息,请参阅,并查看
listView1\u DrawColumnHeader

,正如他在回答中提到的,这是Windows XP中的
ListView
的一个众所周知的问题。另一个解决方法是注册
ListView.DrawColumnHeader
事件并重置其中的标题字体。您必须将
ListView.OwnerDraw
属性设置为
true
。MSDN代码如下所示

// 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;
}

在这种情况下,标题字体将始终为
“Helvetica”,10,FontStyle.Bold
,并且不受listview字体的影响。有关更多详细信息。

以下是如何使ListView标题具有所需的高度:


经过详尽的研究,我发现了这一点。问题是当你打电话的时候

SetWindowTheme(this.Handle, "", "");
在自定义
ListView
类中,它防止视觉样式影响
ListView
控件的外观,但不影响
ListView
头控件(
SysHeader32
窗口),后者是
ListView
的子窗口因此,在调用
SetWindowTheme
函数时,我们需要提供标题窗口的句柄,而不是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);
}
[DllImportAttribute(“uxtheme.dll”)]
私有静态extern int SetWindowTheme(IntPtr hWnd、string appname、string idlist);
[DllImport(“user32”)]
[返回:Marshallas(UnmanagedType.Bool)]
私有静态外部bool EnumChildWindows(IntPtr窗口、EnumWindowProc回调、IntPtr i);
//枚举窗口时要使用的回调方法:
私有静态布尔枚举窗口(IntPtr句柄、IntPtr指针)
{
GCHandle gch=GCHandle.FromIntPtr(指针);
列表=gch。目标为列表;
if(list==null)
抛出新的InvalidCastException(“GCHandle目标无法强制转换为列表”);
列表。添加(句柄);
返回true;
}
//EnumChildWindows方法的委托:
私有委托bool EnumWindowProc(IntPtr hWnd,IntPtr参数);
//获得第一个孩子:
私有静态无效禁用VisualStylesforFirstChild(IntPtr父级)
{
列表子项=新列表();
GCHandle listHandle=GCHandle.Alloc(儿童);
尝试
{
EnumWindowProc childProc=新的EnumWindowProc(EnumWindow);
EnumChildWindows(父、childProc、GCHandle.ToIntPtr(listHandle));
如果(children.Count>0)
SetWindowTheme(子对象[0],“”,“”);
}
最后
{
if(listHandle.IsAllocated)
Free();
}
}
已创建受保护的重写无效OnHandleCreated(EventArgs e)
{
DisableVisualStylesForFirstChild(this.Handle);
碱基。根据HandleCreated(e);
}

+1指出视觉样式导致了这种变化,尽管这种解决方案根本不起作用。我找到了SetWindowTheme以前不起作用的原因。现在可以了,看看我的答案;)祝贺Kamil获得赏金:)我自己绘制它不会有任何帮助,因为你只能更改正在绘制的内容,而不能更改标题的大小。不,OwnerDraw不是这样,它不可能影响ListView标题的高度。@LihO它不会对标题的高度做任何事情,因为在XP中这是不可能的。请仔细阅读我的回答,我的想法是让标题文本变小,以便与标题相符。但我的问题是如何“使ListView标题具有正确的高度”,而不是如何使标题文本变小…我找到了SetWindowTheme以前不起作用的原因。现在可以了,看看我的答案;)因为这是基于卡米勒·拉赫建议的解决方案,所以我将以我提供的赏金奖励他的答案。
[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);
}