it-swarm-eu.dev

Jak zabránit blikání v ListView při aktualizaci jednoho textu ListViewItem?

Vše, co chci, je aktualizovat text ListViewItem, aniž by viděl blikání.

Toto je můj kód pro aktualizaci (několikrát zavolano):

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

Viděli jsme některá řešení, která zahrnují přepsání WndProc():

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

Říká se, že ten problém vyřeší, ale v mém případě to nebylo . Věřím, že je to proto, že používám ikony na každé položce.

46
Jonas

Chcete-li ukončit tuto otázku, zde je třída pomocníka, která by měla být volána při načítání formuláře pro každý ListView nebo jiné ovládací prvek ListView odvozené ve formuláři. Díky "Brian Gillespie" za poskytnutí řešení.

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's 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);
    }
}
51
Jonas

Přijatá odpověď funguje, ale je poměrně zdlouhavá a odvozená z kontroly (jako je uvedeno v dalších odpovědích), která umožňuje dvojité ukládání do vyrovnávací paměti, je také trochu přehnaná. Ale naštěstí máme odraz a můžeme také volat vnitřní metody, pokud chceme (ale být si jisti, co děláte!).

Zapojte tento přístup do metody rozšíření, dostaneme poměrně krátkou třídu:

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

Který lze snadno volat v rámci našeho kódu:

InitializeComponent();

myListView.DoubleBuffering(true); //after the InitializeComponent();

A všechny blikání je pryč.

Aktualizace

Klopýtla jsem na tato otázka a díky této skutečnosti by měla být metoda rozšíření (možná) lepší:

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

ListView v CommonControls 6 (XP nebo novější) podporuje dvojité ukládání do vyrovnávací paměti. .NET naštěstí zařadí nejnovější systém CommonControls do systému. Chcete-li povolit dvojité ukládání do vyrovnávací paměti, odešlete příslušnou zprávu systému Windows ovládacímu prvku ListView.

Zde jsou podrobnosti: http://www.codeproject.com/KB/list/listviewxp.aspx

11
Brian Gillespie

V aplikaci .NET Winforms 2.0 existuje chráněná vlastnost nazvaná DoubleBuffered.

Zděděním z ListView pak můžete tuto chráněnou vlastnost nastavit na true. To umožní dvojité ukládání do vyrovnávací paměti bez nutnosti volání funkce SendMessage.

Nastavení vlastnosti DoubleBuffered je stejné jako nastavení následujícího stylu:

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

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

10
Rolf Kristensen

Vím, že tato otázka je dost stará, ale protože se jedná o jeden z prvních výsledků vyhledávání na Googlu, chtěl jsem sdílet svou opravu.

Jediný způsob, jak bych mohl odstranit blikání 100%, bylo kombinovat odpověď od Olivera (třída rozšíření s dvojitou vyrovnávací pamětí) a pomocí metod BeignUpdate() a EndUpdate().

Žádný z těch, kdo by byli sami, by na mě nemohl blikat.

2
T4cC0re

to pomůže:

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

Pokud chcete text pouze aktualizovat, jednoduše upravte změněný text SubItem přímo namísto aktualizace celého ListViewItem (neřekli jste, jak provádíte aktualizace).

Přepíše vás show je ekvivalentní jednoduše přepsat OnPaintBackground, což by bylo "správnější" způsob, jak to udělat, a to nebude pomáhat pro jednu položku.

Pokud stále máte problémy, budeme potřebovat objasnění toho, co jste vlastně zkoušeli.

0
ctacke

To je výstřel ve tmě, ale můžete zkusit dvojité ukládání do vyrovnávací paměti.

SetStyle(
  ControlStyles.AllPaintingInWmPaint |
  ControlStyles.UserPaint |
  ControlStyles.DoubleBuffer, true)
0
Ed S.

Volání metody BeginUpdate () na ListView před nastavením některého z položek zobrazení seznamu a potom volání EndUpdate () po všechny položky byly přidány.

To zastaví blikání.

0
Mike

Jednoduché řešení je toto:

yourlistview.BeginUpdate ()

// Proveďte aktualizaci přidávání a odebírání položek ze seznamu

yourlistview.EndUpdate ()

0
jaiveeru