当所选项目不可见时,VirtualMode中的C#ListView会闪烁

And*_*scu 4 c# listview flicker virtualmode

我知道复制听起来很复杂,但请关注我:

你有一个ListView VirtualMode = true.

选择一个项目,向下滚动以使所选项目超出可视区域,然后尝试将另一个项目添加到ListView.

你会看到它瞬间表现异常,看到一些闪烁.如果你升级情况并试图快速添加很多项目(我每秒增加约20次),你会发现小问题变得非常大.它是周围闪烁和无效项目的组合.

我已经调查了这个问题,似乎ListView RetrieveVirtualItem为所选项目生成了很多事件(即使它显然不可见).

看起来当我添加一个新项目(增加VirtualListSize)时,ListView首先尝试关注所选项目,然后返回到之前的位置.

有没有人遇到同样的问题?

DxC*_*xCK 5

这里有一个派生类,解决了这个问题.

使用SetVirtualListSize()方法代替常规方法VirtualListSize.

public class FlickerFreeListView : ListView
{
    #region Static Functionality

    private static FieldInfo _internalVirtualListSizeField;

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

        if (_internalVirtualListSizeField == null)
        {
            string msg = "Private field virtualListSize in type System.Windows.Forms.ListView is not found. Workaround is incompatible with installed .NET Framework version, running without workaround.";
            Trace.WriteLine(msg);
        }
    }

    #endregion


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

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

    public void SetVirtualListSize(int size)
    {
        // if workaround incompatible with current framework version (usually MONO)
        if (_internalVirtualListSizeField == null)
        {
            VirtualListSize = size;
        }
        else
        {
            if (size < 0)
            {
                throw new ArgumentException("ListViewVirtualListSizeInvalidArgument");
            }

            _internalVirtualListSizeField.SetValue(this, size);
            if ((base.IsHandleCreated && this.VirtualMode) && !base.DesignMode)
            {
                SendMessage(0x102f, new IntPtr(size), new IntPtr(2));
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)