65.9K
CodeProject 正在变化。 阅读更多。
Home

在 .NET 和 XP 中实现无闪烁的 ListView

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (24投票s)

2003年1月27日

6分钟阅读

viewsIcon

360928

downloadIcon

4520

本文讨论了 .NET ListView 的问题并提供了修复这些问题的解决方案。

Sample Image - ListViewXP.gif

引言

本文的重点是扩展和改进 .NET ListView 控件。当前的 ListView 控件非常有用,但存在一个恼人的闪烁问题。我的目标是消除或显著减少这种闪烁。本文提供的解决方案仅适用于带有关联清单文件的 Windows XP。这是我为改进 ListView 控件编写的三篇文章中的第一篇。其他文章不需要 XP。此外,我在本文中讨论的其他内容也不需要 XP。

它会闪烁

您会遇到闪烁的两种情况。

  • 动态添加项目

    如果您尝试在使用具有多个图标的 ImageList 时添加多个项目(在 forforeach 循环中),并且希望这些项目在添加时显示,您需要使用 Refresh()Update()(您可以使用其他方法,如 Application.DoEvents())。上述任何一种方法都会导致恼人的闪烁。要避免闪烁,请不要将 Refresh()Update() 等放在 for 循环内。这将导致 ListView 在所有项目添加完成之前保持空白。有时,这是最佳方法,但如果这样做需要大量时间,则不是一个好主意,因为用户会认为程序已锁定。

  • 调整带有停靠的 ListView 的主窗体大小

    ListView 停靠时,如同在 Windows 资源管理器中一样(并且您有大量项目),调整主窗体大小时会导致所有项目闪烁。

更新:我最初有三个。第三个是更新/更改项目,但您只需使用 Update() 而不是 Refresh() 即可解决此问题。

为什么会闪烁?

当您向 ListView 添加新项目时,控件会自行失效。这会导致背景被擦除,所有项目都会重新绘制。它应该只使新项目的边界失效,只绘制项目,但事实并非如此。这意味着调用 Refresh()Update() 会产生相同的结果,而您期望 Update()更新新项目或更改的项目。在我的下一篇文章中,我将讨论几种技术,允许只重绘新添加的项目。

它闪烁的另一个原因是它不是真正双缓冲的。您可以扩展 ListView 类,并添加 SetStyle(ControlStyles.DoubleBuffer, true),但这不起作用。此处描述的技术向您展示了如何对 ListView 进行双缓冲。

ListView 的双缓冲

如果您熟悉仅使用 Win32 API 或 MFC 编程 ListView(或 CListCtrl),您会注意到您可以为 ListView 设置特定样式。其中大多数样式已在 .NET ListView 中设置,并且是可自定义的(例如,ViewModes,图标如何对齐...是否自动排列等)。

此外,还有 ListView 的“扩展”样式。这些样式添加了一些额外功能,例如使用单击激活和热跟踪(类似于 Windows 98 资源管理器以 Web 模式浏览,单击项目一次即可启动该项目,“进入”该项目时会选中该项目等)。还有一个扩展样式允许在详细信息/报告模式下围绕项目绘制网格线(这在 .NET 中已实现,当您选择详细信息视图并显示网格线时)。

在 Windows XP 中,有一个名为 LVS_EX_DOUBLEBUFFER 的扩展样式。这就是我们想要的。不幸的是,它仅适用于通用控件版本 6,这意味着我们需要 Windows XP 以及清单文件(或嵌入式资源)。此外,还有一个名为 LVS_EX_BORDERSELECT 的样式,它告诉 ListView(在大图标模式下)突出显示图标的边框,而不是覆盖它(这在通用控件版本 4.71 中可用,因此无需 XP 即可工作)。

因此,我们的目标是实际利用这些扩展样式。如果您熟悉 SendMessage Windows 函数,这会很容易。我们从 user32.dll 导入此函数,并使用它来检索和设置扩展样式。代码如下:

public void SetExStyles()
{
    LVS_EX styles = (LVS_EX)SendMessage(this.Handle, 
        (int) LVM.LVM_GETEXTENDEDLISTVIEWSTYLE, 0,0);
    styles |= LVS_EX.LVS_EX_DOUBLEBUFFER | LVS_EX.LVS_EX_BORDERSELECT;
    SendMessage(this.Handle, 
        (int) LVM.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, (int) styles);
}

我们首先检索任何现有的扩展样式。然后添加 DOUBLEBUFFERBORDERSELECT,并使用 SendMessage 将这些额外样式添加到当前 ListView。此方法应在 ListView 的句柄创建之后调用。否则,它将不起作用,因为 Handle 尚未定义。换句话说,不要在主窗体的构造函数中调用此方法;它应该在整个窗体加载完成后发生。

注意:LVS_EX 是 int 的枚举类型。其中的每个常量都定义了正确的 ExtendedStyleLVM 也是代表 ListView 消息的枚举类型。

一旦调用了此方法,您就可以使用类似这样的循环将项目添加到此 ListView 中:

for (int i=0; i < 500; i++)
{
   listviewXp.Items.Add("item name", iconIndex);
   listviewXp.Update();
}

现在您将能够看到正在绘制的项目,并且不再遇到恼人的闪烁。此外,如果您的 ListView 已停靠,您可以调整窗体大小而不会出现闪烁问题。您也可以在对现有项目进行更改后调用 listview.Refresh()listview.Update(),并且更改将无闪烁地完成。

运行和使用示例

  • 使用演示示例

    请确保您使用的是 Windows XP,并将 exe 和清单文件放在同一个目录中。运行它,然后按按钮以观看项目无闪烁地出现。如果您没有使用 XP,您仍然会看到闪烁,但您将能够看到 BorderSelect 模式。

  • 编译示例应用程序

    打开 Visual Studio .NET 并进行编译。在运行之前,将清单文件复制到 exe 所在的 DebugRelease 目录。

  • 在您自己的应用程序中使用 ListViewXP

    只需复制 ListViewXP.cs 文件并将其添加到您的应用程序中。请注意,如果您想要双缓冲效果,必须提供清单文件。您可以复制我提供的文件,并将其重命名为 YourAppName.exe.manifest。您可以自由使用和分发此类,但如果您这样做,请包含一个注释,其中包含我的姓名和本文的链接。另外,如果您使用它,请告诉我它的效果如何。

结论

使用来自 user32.dllSendMessage 函数,我们可以扩展 .NET ListView,以便在 XP 中添加双缓冲支持以消除闪烁。此外,我们可以使用此函数添加其他扩展的 ListView 样式,并且此技术也可以应用于其他控件。希望您喜欢这篇文章。

无闪烁的 ListView 在 .NET 和 XP 中 - CodeProject - 代码之家
© . All rights reserved.