2013-05-27 2 views
0

У меня есть унаследованное listview, и при щелчке заголовков столбцов происходит значительное мерцание. Список находится в подробном представлении.ListView мерцает, когда сортировка

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(); 
    } 

Когда я заполняю список, мерцание мерцает.

 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); 
     } 

Редактировать WM_ERASEBKGND не решить мою проблему.
Я добавил этот код в виде хостинг ListView и мерцание исчезает

protected override CreateParams CreateParams 
    { 
     get 
     { 
      CreateParams cp = base.CreateParams; 
      cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED 
      return cp; 
     } 
    } 

ответ

5

Вы можете увидеть, что происходит не так здесь, добавив этот код в ваш класс:

protected override void OnHandleCreated(EventArgs e) { 
    Console.WriteLine("Listview window created"); 
    base.OnHandleCreated(e); 
} 

Запустите программу и щелкните заголовки столбцов, обратите внимание на окно вывода. Вы увидите, что каждый раз, когда вы нажимаете, вы увидите сообщение «Создано окно списка». Или, другими словами, окно 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; 
} 
1
class ListViewNF : System.Windows.Forms.ListView 
{ 
    public ListViewNF() 
    { 
     //Activate double buffering 
     this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); 

     //Enable the OnNotifyMessage event so we get a chance to filter out 
     // Windows messages before they get to the form's WndProc 
     this.SetStyle(ControlStyles.EnableNotifyMessage, true); 
    } 

    protected override void OnNotifyMessage(Message m) 
    { 
     //Filter out the WM_ERASEBKGND message 
     if(m.Msg != 0x14) 
     { 
      base.OnNotifyMessage(m); 
     } 
    } 
} 

Это source

+0

Если вы оказываетесь копирования и вставки из ответа на другой вопрос о переполнении стека, вопрос, вероятно, является дубликатом. Для указания этого используйте ссылку «флаг» под тегами вопроса. –

+0

@CodyGray: Хорошо! – matzone

Смежные вопросы