c# – 为什么ListView渲染对某些字符来说这么慢?

更新1:我已经写了一个MFC-C实现和一个老式的Win32应用程序,并录制了一个视频,展示了问题的严重程度:

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

由于老式的Win32应用程序没有出现这个问题,这让我相信C#和MFC都使用相同的渲染API,必须导致这个问题(基本上让我怀疑问题可能出在OS /图形驱动程序级别) ).

原帖:

虽然必须在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并更改新的BufferedListView();到新的ListViewWithLessSuck();你可以看到变化.

点赞