排序时ListView闪烁

alb*_*ert 0 listview winforms

我有一个继承的列表视图,当我点击列标题时有明显的闪烁.列表在详细信息视图中.

    public ListViewEx()
    {
        this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
        this.DoubleBuffered = true;
    }

    int sortColumn = -1;
    protected override void OnColumnClick(ColumnClickEventArgs e)
    {
        if(e.Column != sortColumn)
        {
            sortColumn = e.Column;
            this.Sorting = SortOrder.Ascending;
        }
        else
        {
            if(this.Sorting == SortOrder.Ascending)
                this.Sorting = SortOrder.Descending;
            else
                this.Sorting = SortOrder.Ascending;
        }
        this.Sort();
    }
Run Code Online (Sandbox Code Playgroud)

填充列表时没有闪烁.

        for(int i = 0; i < 10; i++)
        {
            ListViewItem lvi = new ListViewItem("this is column 1 " +i);
            lvi.SubItems.Add("...
            lvi.SubItems.Add("...
            lvi.SubItems.Add("...
            lvi.SubItems.Add("...
            lvi.SubItems.Add("...

            listViewEx1.Items .Add (lvi);
        }
Run Code Online (Sandbox Code Playgroud)

编辑WM_ERASEBKGND并没有解决我的问题.
我在托管列表视图的表单中添加了此代码,闪烁消失了

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
            return cp;
        }
    }
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 5

通过将此代码添加到您的类中,您可以看到这里出了什么问题:

protected override void OnHandleCreated(EventArgs e) {
    Console.WriteLine("Listview window created");
    base.OnHandleCreated(e);
}
Run Code Online (Sandbox Code Playgroud)

运行程序并单击列标题,注意"输出"窗口.您会看到每次单击时,都会显示"已创建Listview窗口"消息.或者换句话说,每次排序时都会重新创建 ListView窗口.无论你使用什么双缓冲,它总会闪烁.

这是由您的代码分配ListView.Sorting属性引起的.它的底层本机实现是样式标志,它只能在创建窗口时指定.因此,当您更改它时,Winforms将被强制重新创建窗口.闪烁是不可避免的副作用.

有一种更好的方法,您还可以使用其ListViewItemSorter属性为控件实现自定义排序方法.您所要做的就是提供一个实现IComparable接口的类.也可能有ListView本身实现它.让您的代码看起来像这样,排序将如丝般顺利:

using System;
using System.Windows.Forms;

class ListViewEx : ListView, System.Collections.IComparer {
    public ListViewEx() {
        this.DoubleBuffered = true;
        this.ListViewItemSorter = this;
    }

    public int Compare(object x, object y) {
        var item1 = (ListViewItem)x;
        var item2 = (ListViewItem)y;
        int compare = String.Compare(item1.SubItems[this.sortColumn].Text, item2.SubItems[this.sortColumn].Text);
        if (sortOrder == SortOrder.Descending) compare = -compare;
        return compare;
    }

    protected override void OnColumnClick(ColumnClickEventArgs e) {
        if (e.Column != sortColumn) {
            sortColumn = e.Column;
            this.sortOrder = SortOrder.Ascending;
        }
        else {
            if (this.sortOrder == SortOrder.Ascending)
                this.sortOrder = SortOrder.Descending;
            else
                this.sortOrder = SortOrder.Ascending;
        }
        this.Sort();
    }

    private int sortColumn = 0;
    private SortOrder sortOrder = SortOrder.Ascending;
}
Run Code Online (Sandbox Code Playgroud)