更新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();你可以看到变化.