views:

64

answers:

1

Create a .net 2.0 Windows form app, add a splitContainer docked Fill, with this in its form constructor:

public Form1()
{
 InitializeComponent();

 for (int i = 1; i <= 300; i++)
 {
  FlowLayoutPanel f = new FlowLayoutPanel();
  f.Dock = DockStyle.Fill;
  Button b = new Button();
  f.Controls.Add(b);
  splitContainer1.Panel2.Controls.Add(f);
 }
}

Press F5. Grab the form by the lower right-hand-edge and drag quickly to expand the form. The form expands rather jerkily due to the work being done in all the controls.

I have an app with a form in it with some slow controls which has similarly become slow. The difference is that in my app, I get ugly black space appearing for a fraction of a second in the gaps as I drag out the form with my mouse. The window is not re-drawing properly. This ugly black space does not appear in the sample code above.

Any ideas what might cause black space to appear when expanding a slow form?

I have tried double-buffered but that makes no difference.

EDIT: I have dismantled the form down to its basics so that this can be reproduced. Start a new C# Windows Form application called WindowsFormsApplication_SampleFault. Paste the code below into the Form1.cs

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using System.Diagnostics;
using System.Security.Principal;
using System.Runtime.InteropServices;


namespace WindowsFormsApplication_SampleFault
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            for (int i = 1; i <= 200; i++)
            {
                Button b = new Button();
                b.Dock = DockStyle.Fill;
                this.Controls.Add(b);
            } 
        }
        }
}

then paste this into Form1.Designer.cs

namespace WindowsFormsApplication_SampleFault
{
    partial class Form1
    {
            /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        /// 

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.statusStrip1 = new System.Windows.Forms.StatusStrip();
            this.SuspendLayout();
            // 
            // statusStrip1
            // 
            this.statusStrip1.Location = new System.Drawing.Point(0, 472);
            this.statusStrip1.Name = "statusStrip1";
            this.statusStrip1.Size = new System.Drawing.Size(756, 22);
            this.statusStrip1.TabIndex = 6;
            this.statusStrip1.Text = "statusStrip1";
            // 
            // frmOptions
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(756, 494);
            this.Controls.Add(this.statusStrip1);
            this.DoubleBuffered = true;
            this.ImeMode = System.Windows.Forms.ImeMode.Off;
            this.MinimizeBox = false;
            this.MinimumSize = new System.Drawing.Size(750, 500);
            this.Name = "frmOptions";
            this.ShowIcon = false;
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.StatusStrip statusStrip1;

    }
}

Press F5 and attempt to drag-out the form. Note I am deliberately overloading the redraw mechanism to produce the black areas.

I believe that something is wrong with the form designer code but I am not sure what.

A: 

This particular case can be easily fixed by WS_EX_COMPOSITED.

const int WS_EX_COMPOSITED = 0x02000000;
protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= WS_EX_COMPOSITED;
        return cp;
    }
}

P.S. 200 buttons is too much for any GUI :)

IMHO

EDITED: here I post what I managed to do to fix black boxes on Win7. The code is a bit ugly but the idea is clear I hope.

public Form1()
{
    InitializeComponent();

    for (int i = 1; i <= 200; i++)
    {
        Button b = new Button();
        b.Dock = DockStyle.Fill;
        this.Controls.Add(b);
    }
    _layoutWorker.Tick += new EventHandler(LayoutWorker_Tick);

}

private void LayoutWorker_Tick(object sender, EventArgs e)
{
    _layoutWorker.Stop();
    this.PerformLayout();
}

protected override void OnResize(EventArgs e)
{
    this.SuspendLayout();
    base.OnResize(e);
    this.ResumeLayout(false);
    _layoutWorker.Start();
}

private Timer _layoutWorker = new Timer { Enabled = false, Interval = 1 };
Dmitry Karpezo
Hi I tried that but it doesn't cure the problem. I'm on Win7 Ultimate with the default UI settings which I believe is the aero
BillyG
I overrided CreateParams and the black boxes disappeared (Vista Home). There are white boxes instead of black boxes, which is much better :) I have no Win7 computer now, let me try later...
Dmitry Karpezo
I take it you managed to reproduce using the code above? I've cured it in the sample above by removing DoubleBuffered. That leaves white space. But in my production app, removing DoubleBuffered doesn't fix it.
BillyG
Yes, I took your code and just overrided CreateParams property of the form. Now I have white boxes instead of black ones, and I don't think there is a way to get rid of any kind of boxes completely, it's too many overlapped controls.
Dmitry Karpezo
In my sample (Win7 ultimate) the override with WS_EX_COMPOSITED makes no difference. As long as DoubleBuffered is on, I get black space. In my production code, nothing fixes it.
BillyG
Yes, I reproduced it on Win7. I think the only way to avoid boxes is to prevent from immediate layout processing.I overrided form's OnResize() this.SuspendLayout(); base.OnResize(e); this.ResumeLayout(false); and process layout in 10 msec after resize occured. Now I have smooth layout processing. I can post a complete code if you would like to.
Dmitry Karpezo