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

Как предотвратить мерцание в ListView при обновлении одного текста ListViewItem?

Все, что я хочу, это обновить текст ListViewItem без видимых мерцаний.

Это мой код для обновления (называемый несколько раз):

listView.BeginUpdate();
listViewItem.SubItems[0].Text = state.ToString();    // update the state
listViewItem.SubItems[1].Text = progress.ToString(); // update the progress
listView.EndUpdate();

Я видел некоторые решения, которые включают переопределение компонента WndProc():

protected override void WndProc(ref Message m)
{
    if (m.Msg == (int)WM.WM_ERASEBKGND)
    {
        m.Msg = (int)IntPtr.Zero;
    }
    base.WndProc(ref m);
}

Говорят, что это решает проблему, но в моем случае это не. Я считаю, что это потому, что я использую значки для каждого элемента.

4b9b3361

Ответ 1

Чтобы закончить этот вопрос, вот вспомогательный класс, который следует вызывать, когда форма загружается для каждого ListView или любого другого элемента управления ListView в вашей форме. Спасибо "Брайан Гиллеспи" за предоставление решения.

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

Ответ 2

Принятый ответ работает, но довольно длинный, и, исходя из управления (как упоминалось в других ответах), просто для включения двойной буферизации также немного переборщить. Но, к счастью, мы имеем отражение и можем также называть внутренние методы, если нам нравится (но не забудьте, что вы делаете!).

Инкапсулируя этот подход в метод расширения, мы получим довольно короткий класс:

public static class ControlExtensions
{
    public static void DoubleBuffering(this Control control, bool enable)
    {
        var method = typeof(Control).GetMethod("SetStyle", BindingFlags.Instance | BindingFlags.NonPublic);
        method.Invoke(control, new object[] { ControlStyles.OptimizedDoubleBuffer, enable });
    }
}

Что можно легко вызвать в нашем коде:

myListView.DoubleBuffering(true);

И все мерцание исчезло.

Update

Я наткнулся на этот вопрос, и из-за этого метод расширения должен (возможно) быть лучше:

public static void DoubleBuffered(this Control control, bool enable)
{
    var doubleBufferPropertyInfo = control.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
    doubleBufferPropertyInfo.SetValue(control, enable, null);
}

Ответ 3

ListView в CommonControls 6 (XP или новее) поддерживает двойную буферизацию. К счастью,.NET обматывает новейшие CommonControls в системе. Чтобы включить двойную буферизацию, отправьте соответствующее сообщение Windows в элемент управления ListView.

Вот подробности: http://www.codeproject.com/KB/list/listviewxp.aspx

Ответ 4

В .NET Winforms 2.0 существует защищенное свойство DoubleBuffered.

Наследуя ListView, можно установить для этого защищенного свойства значение true. Это позволит использовать двойную буферизацию без необходимости вызова SendMessage.

Установка свойства DoubleBuffered аналогична установке следующего стиля:

listview.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94096

Ответ 5

Я знаю, что этот вопрос довольно старый, но поскольку это один из первых результатов поиска в Google, я хотел поделиться своим исправлением.

Единственный способ удалить мерцание на 100% состоял в том, чтобы объединить ответ с Оливером (класс расширения с двойной буферизацией) и использовать методы BeignUpdate() и EndUpdate().

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

Ответ 6

это поможет:

class DoubleBufferedListView : System.Windows.Forms.ListView
{
    public DoubleBufferedListView()
        :base()
    {
        this.DoubleBuffered = true;
    }
}

Ответ 7

Если вы хотите только обновить текст, просто установите измененный текст SubItem напрямую, а не обновите весь ListViewItem (вы не сказали, как вы делаете свои обновления).

Переопределение, которое вы показываете, эквивалентно просто переопределению OnPaintBackground, что было бы "более правильным" способом для выполнения этой задачи, и это не поможет ни для одного элемента.

Если у вас все еще есть проблемы, нам нужно уточнить, что вы на самом деле пробовали.

Ответ 8

Это выстрел в темноте, но вы можете попробовать выполнить двойную буферизацию элемента управления.

SetStyle(
  ControlStyles.AllPaintingInWmPaint |
  ControlStyles.UserPaint |
  ControlStyles.DoubleBuffer, true)

Ответ 9

Вызвать метод BeginUpdate() в ListView перед настройкой любого из элементов списка, а затем вызвать EndUpdate() после того, как все элементы были добавлены.

Это остановит мерцание.

Ответ 10

Простым решением является следующее:

yourlistview.BeginUpdate()

//Сделайте свое обновление добавления и удаления элемента из списка

yourlistview.EndUpdate()