Laden...

OwnerDrawn ListBox abgewählte Item flackert

Erstellt von KainPlan vor 12 Jahren Letzter Beitrag vor 12 Jahren 3.857 Views
K
KainPlan Themenstarter:in
133 Beiträge seit 2009
vor 12 Jahren
OwnerDrawn ListBox abgewählte Item flackert

Hallo,

ich hatte mich einige zeit zur Ruhe gesetzt und bin wieder ein bisschen am Programmieren 😉 zu meinem Problem:

jedesmal wenn ich in meiner ListBox ein Item abwähle, sprich wenn ich ein anderes Item neu Selektiere, flackert das abgewählte item. Ich hab echt alles versucht überall rum gegooglet aber ich habe keine Ahnung was da passiert und warum es flackert. 😦

Wen es interessiert hier mal ein Bld vom Projekt (und der ListBox): siehe Anhang

Hier mal der code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using DrawingEx;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace substx
{
    class DesignListBox : ListBox
    {
        public DesignListBox()
        {
            base.SetStyle(ControlStyles.OptimizedDoubleBuffer |
                          ControlStyles.ResizeRedraw |
                          ControlStyles.AllPaintingInWmPaint,
                          true);

            // DoubleBuffered = true; <-- nutzt auch nix WAH!!!
            base.DrawMode = DrawMode.OwnerDrawFixed;
        }

        protected override void OnDrawItem(DrawItemEventArgs e)
        {

            Rectangle bnd = e.Bounds;
            Graphics dc = e.Graphics;
            ColorTable ct = (ColorTable)Items[e.Index];
            int pad = 6;
            int pwh = bnd.Height - 2 * pad;
            Rectangle pi0 = new Rectangle(bnd.X + pad, bnd.Y + pad, pwh, pwh);
            Rectangle pi1 = new Rectangle(bnd.X + pi0.Right + pad, bnd.Y + pad, pwh, pwh);
            Rectangle pi2 = new Rectangle(bnd.X + pi1.Right + pad, bnd.Y + pad, pwh, pwh);
            Rectangle pi3 = new Rectangle(bnd.X + pi2.Right + pad, bnd.Y + pad, pwh, pwh);

            if (ct == null)
            {
                #region Error
                dc.FillRectangle(new SolidBrush(BackColor), bnd);
                StringFormat sf = new StringFormat();
                sf.LineAlignment = StringAlignment.Center;
                sf.Alignment = StringAlignment.Center;
                dc.DrawString("Error Item.", Font, new SolidBrush(Color.Red), bnd, sf);
                #endregion
            }
            else
            {
                #region Preview
                dc.SetColorTableWindowsVista(ct);
                dc.FillRectangle(new SolidBrush(ct.Background), bnd);
                dc.DrawVistaButtonBackground(pi0, 2, true, false, false);
                dc.DrawVistaButtonBackground(pi1, 2, true, true, false);
                dc.DrawVistaButtonBackground(pi2, 2, true, false, true);
                dc.DrawVistaButtonBackground(pi3, 2, true, true, true);

                Rectangle capt = bnd; capt.X += 8; capt.Width -= 8;
                StringFormat sf = new StringFormat();
                sf.LineAlignment = StringAlignment.Center;
                dc.DrawString(ct.Name + ((ct == Design.ColorTable) ? " (Aktiv)" : ""), Font, new SolidBrush(ct.Text), capt, sf);
                #endregion
            }

            if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
            {
                #region Selection
                Rectangle sel = bnd;
                Rectangle selhalf;
                Color selcl = Color.CornflowerBlue;

                sel.Inflate(-2, -2);
                using (GraphicsPath psel = RoundedRectangle.Create(sel, 2))
                {
                    using (Pen selouter = new Pen(Color.FromArgb(75, selcl)))
                    {
                        dc.DrawPath(selouter, psel);
                    }
                }
                sel.Inflate(-1, -1);
                selhalf = sel;
                selhalf.Height /= 2;
                using (GraphicsPath psel = RoundedRectangle.Create(selhalf, 2,
                    RoundedRectangle.RectangleCorners.TopLeft &
                    RoundedRectangle.RectangleCorners.TopRight))
                {
                    selhalf.Height++;
                    using (LinearGradientBrush lgb = new LinearGradientBrush(
                        selhalf, Color.FromArgb(150, selcl), Color.Transparent, 90f))
                    {
                        dc.FillPath(lgb, psel);
                    }
                }
                using (GraphicsPath psel = RoundedRectangle.Create(sel, 2))
                using (Pen selinner = new Pen(Color.FromArgb(150, selcl)))
                {
                    dc.DrawPath(selinner, psel);
                }
                #endregion
            }
        }
    }
}



49.485 Beiträge seit 2005
vor 12 Jahren
K
KainPlan Themenstarter:in
133 Beiträge seit 2009
vor 12 Jahren

Der Thread hat mich auch nicht weiter gebracht. Hab nun für die Items einen cache angelegt das verbessert das flackern ein wenig aber entfernt es auch nicht komplett.

5.742 Beiträge seit 2007
vor 12 Jahren

Hallo KainPlan,

evtl. kommt noch eine Zeichenroutine für den Hintergrund daziwschen.

Was eigentlich immer gegen Flackern hilft: How do I suspend painting for a control and its children? (ist dann allerdings die "Holzhammervariante").
Aber ein Tipp: Bei Darstellungsproblemen immer zunächst an der Stelle nach der Ursache suchen 😉

BTW: Du solltest ein wenig sorgfältiger mit Brushes etc. umgehen - diese bei jedem Aufruf von Paint neu zu erzeugen, ist jedenfalls keine gute Idee - cache sie besser in Membervariablen, z.B. nach folgendem Muster:


private Brush _myBrush;

private Brush MyBrush
{
  get
  {
    if (this._myBrush == null)
      this._myBrush = this.CreateMyBrush();

      return this._myBrush;
  }
}

//Bei Änderungen aufrufen
private void ResetMyBrush()
{
  if (this._myBrush != null)
    this._myBrush.Dispose();
  this._myBrush = null;
}
private Brush CreateMyBrush()
{
   return new SolidColorBrush(this.MyColor);
}

Evtl. löst du schon dadurch das Problem, weil das Zeichnen so extrem beschleunigt werden sollte.

K
KainPlan Themenstarter:in
133 Beiträge seit 2009
vor 12 Jahren

wie geschrieben; sind die items der listbox gecached im ondrawitem werden nurnoch 2 bilder (1 selection) gezeichnet..

49.485 Beiträge seit 2005
vor 12 Jahren

Hallo KainPlan,

welche Wirkung AllPaintingInWmPaint bei OwnerDraw hat, ist mir nicht ganz klar. Immerhin zeichnest du ja gar nicht im WmPaint, sondern im OnDrawItem. Davon abgesehen könnte es nötig sein, dort zuerst base.OnDrawItem auszurufen.

herbivore

5.742 Beiträge seit 2007
vor 12 Jahren

wie geschrieben; sind die items der listbox gecached im ondrawitem werden nurnoch 2 bilder (1 selection) gezeichnet..

Wie ist das jetzt aufzufassen?
Hast du dir den Link mal angeschaut?

K
KainPlan Themenstarter:in
133 Beiträge seit 2009
vor 12 Jahren

Die OnDrawItem methode Zeichnet ausschließlich zwischengespeicherte Bilder.

-->

if (selected)
    dc.DrawImage(selectedImages[idx])
else
    dc.DrawImage(itemImages[idx])

nichts anderes wird in der OnDrawItem methode getan. 😃

versteh auch nicht ganz was der link mir bringen soll sry ^^

5.742 Beiträge seit 2007
vor 12 Jahren

versteh auch nicht ganz was der link mir bringen soll

Damit kannst du das Zeichnen eines Controls kurzzeitig komplett unterbinden.
Wenn du das während der Selektion durchführst, kannst du so evtl. das Flackern verhindern.

K
KainPlan Themenstarter:in
133 Beiträge seit 2009
vor 12 Jahren

sry war auf ner tagung unterwegs hatte kaum zeit..
achso, ja gut jetzt hats klick gemacht... das werd ich mal versuchen, danke ^^