c# - 添加新项目时防止 ListView 自动水平滚动

标签 c# .net winforms listview scroll

我正在使用 ListView在详细信息 View 中将 VirtualMode 设置为 true 进行控制,我发现每当添加新项目时,水平滚动条都会设置到最左边的位置。如果 ListView 不处于虚拟模式,则不会发生这种情况。 更新:如果您不启用视觉样式,也不会发生这种情况。

您可以通过在详细信息模式下创建一个包含 2 列的简单 ListView 并添加如下内容来查看这一点:

Timer timer = new Timer();

public Form1()
{
    this.InitializeComponent();

    this.listView1.VirtualMode = true;
    this.listView1.RetrieveVirtualItem += new RetrieveVirtualItemEventHandler(listView1_RetrieveVirtualItem);
    this.listView1.VirtualListSize = 10;

    timer.Interval = 250;
    timer.Tick += new EventHandler(t_Tick);
    timer.Start();
}

void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
    e.Item = new ListViewItem(new string[] {"Test", ""});
}

void t_Tick(object sender, EventArgs e)
{
    this.listView1.VirtualListSize += 1;
}

向右滚动 ListView 即可查看此效果。

我怎样才能阻止这种情况发生?我有一个应用程序,其中的项目不断添加到 ListView 中,因此这种行为非常分散注意力。

最佳答案

这似乎是一个已知错误:ListView in virtual mode scrolls incorrectly

Microsoft 对 Connect 报告的最后评论是:

This is an issue with the underlying Win32 control. We will not be able to fix this, the OS team will need to address this.

当然那是 2005 年的事了,所以也许它在 Win 8 中得到了修复?


与此同时,解决方法似乎是:

新建一个继承ListView的类,编写如下代码:

private static FieldInfo _internalVirtualListSizeField;

static FlickerFreeListView()
{
    _internalVirtualListSizeField = typeof(ListView).GetField("virtualListSize", System.Reflection.BindingFlags.NonPublic | BindingFlags.Instance);
}

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, int lParam);

private IntPtr SendMessage(int msg, int wparam, int lparam)
{
    return SendMessage(new HandleRef(this, this.Handle), msg, wparam, lparam);
}

public void SetVirtualListSize(int size)
{
    if (size < 0)
    {
        throw new ArgumentException("ListViewVirtualListSizeInvalidArgument");
    }

    _internalVirtualListSizeField.SetValue(this, size);
    if ((base.IsHandleCreated && this.VirtualMode) && !base.DesignMode)
    {
        SendMessage(0x102f, size, 2);
    }
}

现在更新您的代码以使用 SetVirtualListSize 方法而不是原始 VirtualListSize 属性。

0x102f = LVM_SETITEMCOUNT
2 = LVSICF_NOSCROLL

引用: http://msdn.microsoft.com/en-us/library/bb761188%28VS.85%29.aspx

关于c# - 添加新项目时防止 ListView 自动水平滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9841589/

相关文章:

c# - 如何在win窗体中设置垂直滚动条

c# - 如何在 XML 标记中获取具有特殊字符的 XElement

c# - 应该使用 Application.UseWaitCursor 吗?

winforms - 使用反射来确定对象是否需要在 GUI 线程上调用其成员

c# - 根据窗体大小在窗体上定位控件

c# - 我有一个现有的接口(interface)(带有属性)什么是隔离读写的最佳方法

c# - 新 TcpListener 实例的 AcceptTcpClientAsync() 上出现 ObjectDisposeException

c# - 如何将任何对象序列化为字符串?

c# - 删除 XmlDocument 中的自关闭标签(例如/>)

c# - 在 c#.net winforms 中保存变量的值