none
[.NET 2.0 WinForms] Langsames Resize bei dynamischem Layout (Tablelayoutpanel / FlowLayoutPanel) RRS feed

  • Frage

  • Hi,

    ich habe folgendes Problem:
    Wenn ich in einem Windows Form ein dynamisches Layout mit transparenten Inhalen und mehreren Controls habe, dann dauert der Resizevorgang ewig und es flackert wie wild.

    Ich habe es schon mit Suspend/Resumelayout() versucht, aber das unterbindet nur das Flackern und Ruckeln wärend des Resizevorgangs.

    Doublebuffering bringt auch nichts.

    Ich habe das Problem mal in einer Versuchsanwendung nachgestellt.

    http://www.file-upload.net/download-1873367/wurst.zip.html << da ist die beispielanwendung

    mfg Otis
    Montag, 7. September 2009 13:54

Antworten

  • Hallo Otis,

    Transparenz mit BackgroundImage und komplexen Layouts verträgt sich unter Windows Forms nicht besonders gut.

    Ein grober Ansatz wie es - zumindest für Dein Beispiellayout - schneller funktionieren kann:
    Verzicht auf die Transaparenz-Einstellung und zeichnen des Images im Panel selbst.
    Dazu muß man sich eine abgeleitetes FlowLayoutPanel erstellen:

    using System.Drawing;
    using System.Windows.Forms;
    
    namespace tranparenz
    {
        /// <summary>
        /// FlowLayoutPanel das den Hintergrund direkt zeichnet.
        /// </summary>
        public class FlowLayoutBackgroundPanel : System.Windows.Forms.FlowLayoutPanel
        {
            public FlowLayoutBackgroundPanel()
            {
                this.SetStyle(ControlStyles.ResizeRedraw, true);
            }
    
            protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e)
            {
                if (this.BackgroundImage == null)
                    base.OnPaintBackground(e);
            }
    
            protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
            {
                if (this.BackgroundImage != null)
                {
                    e.Graphics.DrawImage(this.BackgroundImage, this.Bounds);
                }
                base.OnPaint(e); 
            }
        }
    }
    
    Und die dazu angepasste Form als Form2:
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace tranparenz
    {
        public partial class Form2 : Form
        {
            public Form2()
            {
                // Standard (Ohne weitere Vorgaben)
                InitializeComponent();
                this.Load += new System.EventHandler(this.Form_Load);
                this.ResizeBegin += new System.EventHandler(this.Form_ResizeBegin);
                this.ResizeEnd += new System.EventHandler(this.Form_ResizeEnd);
            }
    
            private void Form_Load(object sender, EventArgs e)
            {
                // FlowLayoutPanel pnl = new FlowLayoutPanel();
                
                FlowLayoutPanel pnl = new FlowLayoutBackgroundPanel();
                pnl.SuspendLayout();
                pnl.Dock = DockStyle.Fill;
                
                // Nicht Transparent, dafür mit BackgroundImage
                pnl.BackgroundImage = Properties.Resources.frankfurt10;
                
                for (int i = 0; i < 80; i++)
                {
                    Button b = new Button();
                    b.BackColor = Color.Pink;
                    b.Text = i.ToString();
                    pnl.Controls.Add(b);
                }
                Controls.Add(pnl);
                pnl.ResumeLayout();
            }
    
            private void Form_ResizeBegin(object sender, EventArgs e)
            {
                //SuspendLayout();
            }
    
            private void Form_ResizeEnd(object sender, EventArgs e)
            {
                //ResumeLayout();
            }
        }
    }
    Ich habe jetzt nicht alle Randbedingungen durchgespielt, aber zumindest auf
    meinem  (zugegeben nicht ganz langsamen) Rechner lief es deutlich ruckelfreier.

    Mit einem BufferedGraphics Kontext könnte man je nach reeller Umgebung
    evtl. noch einiges mehr rausholen.

    Gruß Elmar

    Montag, 7. September 2009 17:30
    Beantworter

Alle Antworten

  • Hallo Otis,

    Transparenz mit BackgroundImage und komplexen Layouts verträgt sich unter Windows Forms nicht besonders gut.

    Ein grober Ansatz wie es - zumindest für Dein Beispiellayout - schneller funktionieren kann:
    Verzicht auf die Transaparenz-Einstellung und zeichnen des Images im Panel selbst.
    Dazu muß man sich eine abgeleitetes FlowLayoutPanel erstellen:

    using System.Drawing;
    using System.Windows.Forms;
    
    namespace tranparenz
    {
        /// <summary>
        /// FlowLayoutPanel das den Hintergrund direkt zeichnet.
        /// </summary>
        public class FlowLayoutBackgroundPanel : System.Windows.Forms.FlowLayoutPanel
        {
            public FlowLayoutBackgroundPanel()
            {
                this.SetStyle(ControlStyles.ResizeRedraw, true);
            }
    
            protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e)
            {
                if (this.BackgroundImage == null)
                    base.OnPaintBackground(e);
            }
    
            protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
            {
                if (this.BackgroundImage != null)
                {
                    e.Graphics.DrawImage(this.BackgroundImage, this.Bounds);
                }
                base.OnPaint(e); 
            }
        }
    }
    
    Und die dazu angepasste Form als Form2:
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace tranparenz
    {
        public partial class Form2 : Form
        {
            public Form2()
            {
                // Standard (Ohne weitere Vorgaben)
                InitializeComponent();
                this.Load += new System.EventHandler(this.Form_Load);
                this.ResizeBegin += new System.EventHandler(this.Form_ResizeBegin);
                this.ResizeEnd += new System.EventHandler(this.Form_ResizeEnd);
            }
    
            private void Form_Load(object sender, EventArgs e)
            {
                // FlowLayoutPanel pnl = new FlowLayoutPanel();
                
                FlowLayoutPanel pnl = new FlowLayoutBackgroundPanel();
                pnl.SuspendLayout();
                pnl.Dock = DockStyle.Fill;
                
                // Nicht Transparent, dafür mit BackgroundImage
                pnl.BackgroundImage = Properties.Resources.frankfurt10;
                
                for (int i = 0; i < 80; i++)
                {
                    Button b = new Button();
                    b.BackColor = Color.Pink;
                    b.Text = i.ToString();
                    pnl.Controls.Add(b);
                }
                Controls.Add(pnl);
                pnl.ResumeLayout();
            }
    
            private void Form_ResizeBegin(object sender, EventArgs e)
            {
                //SuspendLayout();
            }
    
            private void Form_ResizeEnd(object sender, EventArgs e)
            {
                //ResumeLayout();
            }
        }
    }
    Ich habe jetzt nicht alle Randbedingungen durchgespielt, aber zumindest auf
    meinem  (zugegeben nicht ganz langsamen) Rechner lief es deutlich ruckelfreier.

    Mit einem BufferedGraphics Kontext könnte man je nach reeller Umgebung
    evtl. noch einiges mehr rausholen.

    Gruß Elmar

    Montag, 7. September 2009 17:30
    Beantworter
  • Hey,

    vielen Dank für deine Mühe.

    Deine Tipps haben mir weitergeholfen :)

    Nun muss ich mal sehen welche von meinen (+deinen) vielen Lösungen gewünscht ist.

    Danke,


    mfg Otis
    Dienstag, 8. September 2009 13:43