Подтвердить что ты не робот

Мерцание в элементе управления ListView (OwnerDraw, Virtual)

Этот вопрос можно считать продолжением Мерцание в listview с помощью ownerdraw и virtualmode.

У меня есть элемент управления ListView в Virtual mode, и я пытаюсь выполнить пользовательский чертеж. Выделение позиции выполняется с помощью следующего метода переопределения:

protected override void OnDrawItem(DrawListViewItemEventArgs eventArgs) 

Как упоминалось в упомянутом вопросе, пользовательский чертеж вводит мерцание мыши над событиями. Отладчик говорит мне, что это происходит из-за чрезмерного количества пользовательских событий рисования, которые увольняются.


Теперь - принятый ответ на указанный вопрос говорит нам:

Это ошибка в .NET ListView, и вы не можете обойти ее двойная буферизация.

  • Итак, насколько надежна эта информация? Неужели это ошибка? Или, может быть, мы просто пытаемся отрезать часть сообщений и надеемся, что это не изменит видимого поведения?

  • Является ли это правдой, что если у меня есть моя процедура рисования владельца для ListView в Virtual Mode,, я могу подавить эти события Custom Draw и выполнить только мой рисунок в WM_PAINT или, может быть, это неверно для некоторых случаев?

  • Каковы предпосылки для элемента управления System.Windows.Forms, чтобы он мог выполнять всю картину в WM_PAINT без изменения ее начального поведения?

4b9b3361

Ответ 1

Я видел эту мерцающую проблему с элементом управления ListView в любых обработчиках обработчиков обработчиков (DrawItem, DrawSubItem). Я попробовал BeginUpdate()/EndUpdate() и двойную буферизацию без успеха. Я думаю, что .NET запускает дополнительный WM_PAINT ко всем столбцам до справа от настраиваемого столбца.

Однако я нашел это обходное решение для отдельного персонализированного столбца ListView. Он отлично работает!

  • В редакторе headheader установите столбец с пользовательским рисунком как последний столбец
  • Измените "DisplayIndex" позиции, которую вы хотите.

Это должно решить мерцание при наведении указателя мыши или рендеринг времени выполнения.

Ответ 2

По крайней мере, для двойной буферизации для OnDrawItem неверно, что есть ошибка, но это немного глупо: есть защищенный атрибут, который вы можете установить, но вам нужно переопределить ListView. Я создал такой класс:

public class MyListView : ListView
{
    public MyListView()
        : base()
    {
        DoubleBuffered = true;
    }
}

И затем в моем файле MyForm.Designer.cs я изменяю экземпляр ListView со следующей строкой:

private ListView myListView;

this.myListView = new MyListView();

И OnDrawItem будет работать как шарм!

Ответ 3

Как Этот ответ здесь, хотя и не уверен, но

Я думаю, что ListView.BeginUpdate() и ListView.EndUpdate() решают проблему.

Сообщение MSDN об этом

Возможно, на этом пути:

protected override void OnDrawItem(DrawListViewItemEventArgs eventArgs)
{
    ListView.BeginUpdate();
    //Do Works Here
    ListView.EndUpdate();
}

Обновление

Другая альтернатива может использовать новый поток в BackgroundWorker для обновления ListView... Я реализовал это вместе с BeginUpdate()/EndUpDate() в своем приложении и нашел его относительно быстрее, чем только BeginUpdate()/EndUpDate()..

Обновление

Я нашел другое рабочее решение в SO, класс помощника, предоставляемый Brian Gillespie:

public enum ListViewExtendedStyles
{
    /// <summary>
    /// LVS_EX_GRIDLINES
    /// </summary>
    GridLines = 0x00000001,
    /// <summary>
    /// LVS_EX_SUBITEMIMAGES
    /// </summary>
    SubItemImages = 0x00000002,
    /// <summary>
    /// LVS_EX_CHECKBOXES
    /// </summary>
    CheckBoxes = 0x00000004,
    /// <summary>
    /// LVS_EX_TRACKSELECT
    /// </summary>
    TrackSelect = 0x00000008,
    /// <summary>
    /// LVS_EX_HEADERDRAGDROP
    /// </summary>
    HeaderDragDrop = 0x00000010,
    /// <summary>
    /// LVS_EX_FULLROWSELECT
    /// </summary>
    FullRowSelect = 0x00000020,
    /// <summary>
    /// LVS_EX_ONECLICKACTIVATE
    /// </summary>
    OneClickActivate = 0x00000040,
    /// <summary>
    /// LVS_EX_TWOCLICKACTIVATE
    /// </summary>
    TwoClickActivate = 0x00000080,
    /// <summary>
    /// LVS_EX_FLATSB
    /// </summary>
    FlatsB = 0x00000100,
    /// <summary>
    /// LVS_EX_REGIONAL
    /// </summary>
    Regional = 0x00000200,
    /// <summary>
    /// LVS_EX_INFOTIP
    /// </summary>
    InfoTip = 0x00000400,
    /// <summary>
    /// LVS_EX_UNDERLINEHOT
    /// </summary>
    UnderlineHot = 0x00000800,
    /// <summary>
    /// LVS_EX_UNDERLINECOLD
    /// </summary>
    UnderlineCold = 0x00001000,
    /// <summary>
    /// LVS_EX_MULTIWORKAREAS
    /// </summary>
    MultilWorkAreas = 0x00002000,
    /// <summary>
    /// LVS_EX_LABELTIP
    /// </summary>
    LabelTip = 0x00004000,
    /// <summary>
    /// LVS_EX_BORDERSELECT
    /// </summary>
    BorderSelect = 0x00008000,
    /// <summary>
    /// LVS_EX_DOUBLEBUFFER
    /// </summary>
    DoubleBuffer = 0x00010000,
    /// <summary>
    /// LVS_EX_HIDELABELS
    /// </summary>
    HideLabels = 0x00020000,
    /// <summary>
    /// LVS_EX_SINGLEROW
    /// </summary>
    SingleRow = 0x00040000,
    /// <summary>
    /// LVS_EX_SNAPTOGRID
    /// </summary>
    SnapToGrid = 0x00080000,
    /// <summary>
    /// LVS_EX_SIMPLESELECT
    /// </summary>
    SimpleSelect = 0x00100000
}

public enum ListViewMessages
{
    First = 0x1000,
    SetExtendedStyle = (First + 54),
    GetExtendedStyle = (First + 55),
}

/// <summary>
/// Contains helper methods to change extended styles on ListView, including enabling double buffering.
/// Based on Giovanni Montrone article on <see cref="http://www.codeproject.com/KB/list/listviewxp.aspx"/>
/// </summary>
public class ListViewHelper
{
    private ListViewHelper()
    {
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern int SendMessage(IntPtr handle, int messg, int wparam, int lparam);

    public static void SetExtendedStyle(Control control, ListViewExtendedStyles exStyle)
    {
        ListViewExtendedStyles styles;
        styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
        styles |= exStyle;
        SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
    }

    public static void EnableDoubleBuffer(Control control)
    {
        ListViewExtendedStyles styles;
        // read current style
        styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
        // enable double buffer and border select
        styles |= ListViewExtendedStyles.DoubleBuffer | ListViewExtendedStyles.BorderSelect;
        // write new style
        SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
    }
    public static void DisableDoubleBuffer(Control control)
    {
        ListViewExtendedStyles styles;
        // read current style
        styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
        // disable double buffer and border select
        styles -= styles & ListViewExtendedStyles.DoubleBuffer;
        styles -= styles & ListViewExtendedStyles.BorderSelect;
        // write new style
        SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
    }
}