views:

424

answers:

2

I know it sounds complicated to reproduce but please follow me:

You have a ListView in VirtualMode = true.

Select an item, scroll down so that the item selected gets outside the visual area and then try to add another item to the ListView.

You will see that for a split second it behaves abnormally and see somekind of flicker. If you escalate the situation and try to add a lot of items really fast (I add around 20 times per second) you will see that the small problem becomes very big. It's a combination of flickering and invalid items around there.

I have investigated the problem and it seems that the ListView generates a lot of RetrieveVirtualItem events for the selected item (even though it's clearly not visible).

It seems like when I add a new item (increase VirtualListSize) the ListView first tries to focus on the selected item and then go back to the previous location.

Did anybody experience the same problem?

A: 

Various controls have a protected DoubleBuffered property. You could try deriving your own DBListView from ListView, and in its constructor set its DoubleBuffered property to true.

Tim Gradwell
Since there's been a while since i've posted the question I'll try and find that project and give your solution a try. Thanks
Andrei Stanescu
+1  A: 

Here a derived class with workaround this problem.

Use SetVirtualListSize() method instead of the regular 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));
            }
        }
    }
}
DxCK