c# - 为什么 ListView 对某些字符的渲染速度如此之慢?

标签 c# .net winforms listview rendering

更新 1:我已经编写了一个 MFC-C++ 实现和一个老式的 Win32 应用程序,并录制了一段视频来展示这个问题到底有多严重:

https://www.youtube.com/watch?v=f0CQhQ3GgAM

由于老式的 Win32 应用程序没有出现这个问题,这让我相信 C# 和 MFC 都使用相同的渲染 API,这一定会导致这个问题(基本上消除了我对问题可能出在操作系统/图形驱动程序级别)。


原帖:

当必须在 ListView 中显示一些 REST 数据时,我遇到了一个非常特殊的问题:

对于某些输入,ListView 呈现在水平滚动时会慢得像爬行一样。

在我的系统和带有“OptimizedDoubleBuffer”的典型子类 ListView 中,ListView 中只有 6 个项目会在滚动到我可以看到标题“游动”的点时减慢渲染速度,即项目的渲染和滚动不匹配期间的标题。

对于具有 10 个项目的常规非子类 ListView,我可以在滚动时真正看到每个项目被单独绘制(重新绘制大约需要 1-2 秒)。

这是示例代码(是的,我知道这些看起来像熊和蝴蝶表情;毕竟这个问题是从用户提供的数据中发现的):

using System;
using System.Windows.Forms;

namespace SlowLVRendering
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.Load += new System.EventHandler(this.Form1_Load);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            const string slow = "ヽ(  ´。㉨°)ノ Ƹ̴Ӂ̴Ʒ~ ღ ( ヽ(  ´。㉨°)ノ  ༼ つ´º㉨º ༽つ ) (」゚ペ)」ヽ(  ´。㉨°)ノ Ƹ̴Ӂ̴Ʒ~ ღ ( ヽ(  ´。㉨°)ノ  ༼ つ´º㉨º ༽つ ) (」゚ペ)」";
            ListView lv = new ListView();
            lv.Dock = DockStyle.Fill;
            lv.View= View.Details;
            for (int i = 0; i < 2; i++) lv.Columns.Add("Title "+i, 500);
            for (int i = 0; i < 10; i++)
            {
                var lvi = lv.Items.Add(slow);
                lvi.SubItems.Add(slow);
            }
            Controls.Add(lv);
        }
    }
}

谁能解释一下问题是什么,以及如何解决?

最佳答案

在尝试了几种不同的方法后,这是我找到的最快的解决方案。仍然有一点犹豫,但与您的原始解决方案相去甚远。在 Microsoft 决定使用比 GDI+ 更好的东西之前,它不会变得更好,除非你使用 .NET 4 及更高版本的 WPF。好吧。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SlowLVRendering
{
    [System.Runtime.InteropServices.DllImport("user32")]
    private static extern bool SendMessage(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);

    private uint LVM_SETTEXTBKCOLOR = 0x1026;

    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();
            this.Load += new System.EventHandler(this.Form1_Load);

        }
        private void Form1_Load(object sender, EventArgs e)
        {
            const string slow = "ヽ(  ´。㉨°)ノ Ƹ̴Ӂ̴Ʒ~ ღ ( ヽ(  ´。㉨°)ノ  ༼ つ´º㉨º ༽つ ) (」゚ペ)」ヽ(  ´。㉨°)ノ Ƹ̴Ӂ̴Ʒ~ ღ ( ヽ(  ´。㉨°)ノ  ༼ つ´º㉨º ༽つ ) (」゚ペ)」";
            ListView lv = new BufferedListView();
            // new ListView();
            //new ListViewWithLessSuck();

            lv.Dock = DockStyle.Fill;
            lv.View = View.Details;
            for (int i = 0; i < 2; i++) lv.Columns.Add("Title " + i, 500);
            for (int i = 0; i < 10; i++)
            {
                var lvi = lv.Items.Add(slow);
                lvi.SubItems.Add(slow);
            }
            Controls.Add(lv);
        //SendMessage(lv.Handle, LVM_SETTEXTBKCOLOR, IntPtr.Zero, unchecked((IntPtr)(int)0xFFFFFF));

        }

    }
    public class BufferedListView : ListView
    {
        public BufferedListView()
            : base()
        {
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        }
    }
class ListViewWithLessSuck : ListView
{
    [StructLayout(LayoutKind.Sequential)]
    private struct NMHDR
    {
        public IntPtr hwndFrom;
        public uint idFrom;
        public uint code;
    }

    private const uint NM_CUSTOMDRAW = unchecked((uint)-12);

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0x204E)
        {
            NMHDR hdr = (NMHDR)m.GetLParam(typeof(NMHDR));
            if (hdr.code == NM_CUSTOMDRAW)
            {
                m.Result = (IntPtr)0;
                return;
            }
        }

        base.WndProc(ref m);
    }

}

您可以亲眼看到其中的区别。如果您取消注释 SendMessage 并将 new BufferedListView(); 更改为 new ListViewWithLessSuck(); 您可以看到更改。

关于c# - 为什么 ListView 对某些字符的渲染速度如此之慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30956440/

相关文章:

c# - 如何在 C# 中向 winforms 程序添加功能?

.net - 如何更改网络图表上的图例符号?

.net - Sonar & Gallio : Gallio won't execute as there are no test projects

c# - 按钮 KeyPress 不适用于输入键

c# - 如何使用 Winforms 或 WPF 构建表单完成/文档合并应用程序?

c# - Winforms 文本框每页行数

c# - 在 ASP.NET Core 3.1 中使用多个身份验证方案?

c# - 如何获取线程执行完成事件

c# - 使用 FUNC 方法(选择器)返回我列表的 "light version"

.net - 使用 wasm 构建 Web 时,uno-platform 是否将 xaml 转换为 html 或 c#?