影响 ListView 标头的 Windows 主题
Posted
技术标签:
【中文标题】影响 ListView 标头的 Windows 主题【英文标题】:Windows theme affecting ListView header 【发布时间】:2012-04-23 14:53:34 【问题描述】:我用一个包含 ListView 的简单表单创建了新的 Windows 窗体应用程序 (C#)。然后我将 View Property 更改为 Details 并增加了此 ListView 中使用的字体大小,结果如下:
这是在带有 Windows Classic 主题的 Windows XP 上的外观:
这是 Windows XP 主题的结果:
我可以通过删除 Application.EnableVisualStyles()
调用或更改
Application.VisualStyleState
:
尽管此更改使 ListView 具有所需的外观,但它也会影响其他控件的外观。我希望我的 ListView 成为唯一不受视觉样式影响的控件。
我也发现了类似的问题试图解决它: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?
很遗憾,上述解决方案均无效。 看起来标题本身将由一些受视觉样式影响的控件组成,即使 ListView 控件的视觉样式被禁用。
任何可以防止视觉样式影响 ListView 标头外观的 C# 解决方案都将受到赞赏。
【问题讨论】:
【参考方案1】:经过深入研究,我发现了它。问题是当你打电话时
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);
【讨论】:
由于它基于 Kamil Lach 建议的解决方案,因此我将用我提供的赏金奖励他的答案。【参考方案2】:这里是如何使 ListView 标题具有您想要的高度:
C# - Listview colum header height (Windows Form)
【讨论】:
【参考方案3】:正如Botz3000 在他的回答中提到的那样,在 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
,并且不受列表视图字体的影响。 Check MSDN 了解更多详情。
【讨论】:
不行,OwnerDraw 不是办法,不能用它来影响 ListView header 的高度。 @LihO 它对标题的高度没有任何作用,因为它在 XP 中是不可能的。请仔细阅读我的回答,我们的想法是让标题文本更小,以便它适合标题。 但我的问题是如何“使 ListView 标题具有正确的高度”,而不是如何使标题文本更小... 我发现了为什么 SetWindowTheme 以前不起作用。它现在有效,请查看我的答案;)【参考方案4】:看起来这是一个known bug,没有简单的解决方法。根据那里的答案:
在对这个问题进行了大量研究后,我们发现这是一个 Windows 操作系统错误,ComCtl6.0 标头控件忘记应用该错误 字体信息到绘图 DC。
但是您可以自己绘制列标题。有关如何操作的详细信息,请参阅this article on MSDN,另请参阅listView1_DrawColumnHeader
。
【讨论】:
自己绘制根本没有帮助,因为您只能更改正在绘制的内容,而不是标题的大小。【参考方案5】:禁用视觉样式怎么样?
使用此代码,您可以禁用一个控件的样式(只需使用 ListViewConstrol 而不是 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);
【讨论】:
+1 指出视觉样式导致了这种变化,尽管这个解决方案根本不起作用。 我发现了为什么 SetWindowTheme 以前不起作用。它现在有效,请查看我的答案;) 恭喜卡米尔获得赏金 :)以上是关于影响 ListView 标头的 Windows 主题的主要内容,如果未能解决你的问题,请参考以下文章
listView.setOnItemClickListener 标头项禁用
来自 QAbstractListmodel headerData() 的 QML Listview 标头