4

再現するのが複雑に聞こえることは承知していますが、フォローしてください:

あなたはListViewを持っていますVirtualMode = true.

項目を選択し、下にスクロールして、選択した項目が視覚領域の外に出てから、別の項目を ListView に追加してみます。

ほんの一瞬、異常な動作をし、何らかのちらつきが見られることがわかります。状況をエスカレートさせて、非常に高速に多くの項目を追加しようとすると (私は 1 秒あたり約 20 回追加します)、小さな問題が非常に大きくなることがわかります。ちらつきと無効なアイテムの組み合わせです。

問題を調査したところ、ListViewRetrieveVirtualItemが選択した項目に対して多くのイベントを生成しているようです (明らかに表示されていません)。

新しいアイテムを追加する (VirtualListSize を増やす) と、ListView は最初に選択したアイテムに焦点を合わせてから、前の場所に戻ろうとするようです。

誰かが同じ問題を経験しましたか?

4

2 に答える 2

5

この問題を回避する派生クラスを次に示します。

SetVirtualListSize()通常の の代わりに method を使用し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));
            }
        }
    }
}
于 2010-09-30T11:57:38.557 に答える
1

さまざまなコントロールには、保護されたDoubleBufferedプロパティがあります。ListViewから独自のDBListViewを派生させて、そのコンストラクターでDoubleBufferedプロパティをtrueに設定してみてください。

于 2010-08-06T11:55:00.273 に答える