Flackern der ListBox verhindern

  • C#

Es gibt 22 Antworten in diesem Thema. Der letzte Beitrag () ist von LaMiy.

    Flackern der ListBox verhindern

    Guten Tag

    Ich habe momentan ein Problem mit einer modifizierten ListBox. Ich zeichne die Items in OnDrawItem selber mit dem VisualStyleRenderer. Diese modifizierte ListBox nutze ich fuer meinen Downloader, das heisst, ich muss immer, wenn ein Byte-Paket angekommen ist, das jeweilige Item updaten und dann die ListBox updaten(invalidaten). Das Problem dabei ist leider nur, dass diese dann heftig flackert. Gibt es einen Weg, das zu verhindern?

    Vielen Dank im Voraus

    Jonas Jelonek

    Jonas Jelonek schrieb:

    das zu verhindern
    Zuerst invalidisieren, dann updaten.
    Invalidisiere dur das Item, dass tatsächlich neu gezeichnet werden muss, nicht die an deren, die sich nicht verändert haben.
    Dafür hat Invalidate(...) eine Reihe von Überladungen, wo Du die betreffende Region sehr genau bescheiben kannst.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Nein, habe aber gerade bemerkt, dass es die Methode GetItemRectangle gibt, dadurch hat sich meine Frage jetzt eruebrigt.

    EDIT: Habe es jetzt ausprobiert, leider aktualisiert er nicht immer richtig und das Flackern ist auch nicht verschwunden.

    Jonas Jelonek schrieb:

    leider aktualisiert er nicht immer richtig
    Poste bitte mal den Code.
    -------------
    Klar, wenn Du ein Item aufklappst, wird es größer und alle darunter liegenden müssen ebenfalls aktualisiert werden.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    C#-Quellcode

    1. private void dwnld_DownloadProgressChanged(DownloadProgressChangedEventArgs e)
    2. {
    3. int index = 0;
    4. for (int i = 0; i <= downloads.Count - 1; i++)
    5. {
    6. if (downloads[i] == dwnld) { index = i; }
    7. }
    8. ActionListItem itm = (ActionListItem)actionList1.Items[index];
    9. itm.Progress = dwnld.Percentage;
    10. string bRec = Math.Round(dwnld.BytesReceived, 1) + " B";
    11. if (dwnld.BytesReceived > 1024.0)
    12. { bRec = Math.Round((dwnld.BytesReceived / 1024.0), 1) + " KiB"; }
    13. if ((dwnld.BytesReceived / 1024.0) > 1024.0)
    14. { bRec = Math.Round(((dwnld.BytesReceived / 1024.0) / 1024.0), 1) + " MiB"; }
    15. if (((dwnld.BytesReceived / 1024.0) / 1024.0) > 1024.0)
    16. { bRec = Math.Round((((dwnld.BytesReceived / 1024.0) / 1024.0) / 1024.0), 1) + " GiB"; }
    17. string tBytes = Math.Round(dwnld.TotalBytes, 1) + " B";
    18. if (dwnld.TotalBytes >= 1024.0)
    19. { tBytes = Math.Round((dwnld.TotalBytes / 1024.0),1) + " KiB"; }
    20. if ((dwnld.TotalBytes / 1024.0) >= 1024.0)
    21. { tBytes = Math.Round(((dwnld.TotalBytes / 1024.0) / 1024.0), 1) + " MiB"; }
    22. if (((dwnld.TotalBytes / 1024.0) / 1024.0) >= 1024.0)
    23. { tBytes = Math.Round((((dwnld.TotalBytes / 1024.0) / 1024.0) / 1024.0), 1) + " GiB"; }
    24. string rTime = Math.Round(dwnld.RemainingTime, 0) + " seconds";
    25. if (dwnld.RemainingTime >= 60)
    26. { rTime = Math.Round((dwnld.RemainingTime / 60), 0) + " minutes"; }
    27. if ((dwnld.RemainingTime / 60) >= 60)
    28. { rTime = Math.Round((dwnld.RemainingTime / 3600), 1) + " hours"; }
    29. if ((dwnld.RemainingTime / 3600) >= 24)
    30. { rTime = Math.Round((dwnld.RemainingTime / 86400), 1) + " days"; }
    31. string speed = dwnld.DownloadSpeed + " B/s";
    32. if (dwnld.DownloadSpeed >= 1024)
    33. { speed = (dwnld.DownloadSpeed / 1024) + " KiB/s"; }
    34. if ((dwnld.DownloadSpeed / 1024) >= 1024)
    35. { speed = ((dwnld.DownloadSpeed / 1024) / 1024) + " MiB/s"; }
    36. if (((dwnld.DownloadSpeed / 1024) / 1024) >= 1024)
    37. { speed = (((dwnld.DownloadSpeed / 1024) / 1024) / 1024) + " GiB/s"; }
    38. itm.ProgressInfo = rTime + " remaining - " + bRec + " of " + tBytes + " (" + speed + ")";
    39. this.Invoke(new MethodInvoker(delegate { actionList1.Invalidate(actionList1.GetItemRectangle(index)); }));
    40. index = 0;
    41. }

    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „Jonas Jelonek“ ()

    C#-Quellcode

    1. protected override void OnDrawItem(DrawItemEventArgs e)
    2. {
    3. base.OnDrawItem(e);
    4. e.Graphics.Clip = new Region(e.Bounds);
    5. e.Graphics.Clear(Color.White);
    6. if (e.State.HasFlag(DrawItemState.Selected))
    7. { ren = new VisualStyleRenderer(VisualStyleElement.CreateElement("LISTVIEW", (int)ListViewParts.LVP_GROUPHEADER, (int)GroupHeaderStates.LVGH_OPENSELECTEDNOTFOCUSEDHOT)); }
    8. else
    9. { ren = new VisualStyleRenderer(VisualStyleElement.CreateElement("LISTVIEW", (int)ListViewParts.LVP_GROUPHEADER, (int)GroupHeaderStates.LVGH_OPEN)); }
    10. ren.DrawBackground(e.Graphics, e.Bounds);
    11. if (this.Items.Count != 0)
    12. {
    13. ActionListItem itm = null;
    14. itm = ActionListItem.TryParse(this.Items[e.Index]);
    15. if (itm != null)
    16. {
    17. e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
    18. e.Graphics.DrawString(itm.HeaderText, this.Font, new SolidBrush(this.ForeColor), 20, e.Bounds.Y + 10);
    19. if (!itm.Completed)
    20. {
    21. if (itm.Progressbar)
    22. {
    23. Rectangle backRect = new Rectangle(20, e.Bounds.Y + 30, this.Width - 80, 10);
    24. e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(232, 232, 232)), backRect);
    25. int width = (this.Width - 80) * itm.Progress / 100;
    26. Rectangle progressRect = new Rectangle(20, e.Bounds.Y + 30, width, 10);
    27. e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(18, 128, 35)), progressRect);
    28. e.Graphics.DrawRectangle(SystemPens.ControlDark, backRect);
    29. }
    30. e.Graphics.DrawString(itm.ProgressInfo, this.Font, new SolidBrush(this.ForeColor), 20, e.Bounds.Y + 43);
    31. }
    32. else
    33. {
    34. e.Graphics.DrawString(itm.StartTime + " - " + itm.EndTime, this.Font, new SolidBrush(this.ForeColor), 20, e.Bounds.Y + 35);
    35. }
    36. }
    37. else
    38. { this.Items.RemoveAt(e.Index); }
    39. }
    40. }
    Meines Wissens nach haut das mit einer ListView nicht so hin und von WPF(in der Praxis) bin ich kein wirklicher Freund.

    EDIT: Habe nochmal nachgeschaut, die ListView hat kein DrawItem-Event, deshalb haut das nicht hin.
    @LaMiy Grundsätzlich hast Du ja recht, aber wenn jetzt einer schon nen Projekt mit WinForms gemacht hat, das weit ist, macht es halt keinen großen Sinn. Zudem müsste man sich erst richtig einarbeiten.
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

    C#-Quellcode

    1. private VisualStyleRenderer ren;

    C#-Quellcode

    1. public class ActionListItem
    2. {
    3. public string HeaderText { get; set; }
    4. public string Path { get; set; }
    5. public bool Progressbar { get; set; }
    6. public int Progress { get; set; }
    7. public string ProgressInfo { get; set; }
    8. public bool Completed { get; set; }
    9. public string StartTime { get; set; }
    10. public string EndTime { get; set; }
    11. public static ActionListItem TryParse(object source)
    12. {
    13. ActionListItem dest = null;
    14. try { dest = (ActionListItem)source; }
    15. catch { }
    16. return dest;
    17. }
    18. public static ActionListItem Parse(object source)
    19. {
    20. ActionListItem dest = (ActionListItem)source;
    21. return dest;
    22. }
    23. }
    ActionListItem ist die Klasse, mit der ich meine ganzen Werte als Element darstelle.

    Jonas Jelonek schrieb:

    Habe nochmal nachgeschaut, die ListView hat kein DrawItem-Event, deshalb haut das nicht hin.

    Vielleicht nicht mit diesem Namen, aber ein Event bzw. eine überschreibbare Funktion um einzelne List-Einträge zu zeichnen, ist definitiv vorhanden, schließlich braucht man die, wenn man den ListView auf "OwnerDrawn" umstellt.
    Habs selbst schon gemacht, den Code aber grad nicht parat, da noch unterwegs.
    Weltherrschaft erlangen: 1%
    Ist dein Problem erledigt? -> Dann markiere das Thema bitte entsprechend.
    Waren Beiträge dieser Diskussion dabei hilfreich? -> Dann klick dort jeweils auf den Hilfreich-Button.
    Danke.
    Anscheinend ist Microsoft zu faul die Beitraege auf MSDN zu ueberarbeiten bzw. sie ueberhaupt korrekt zu praesentieren. Hier gibt es kein OwnerDraw und auch keine Events fuer die Items, jedoch gibt es diese in der Klasse in VS. Ich wuesste aber nicht warum das mit der ListView entspannter gehen sollte.