1

I need to add controls programmatically to a custom control and position them in a certain layout. I thought it would be easy enough create a replica at design time inside a panel and then use the generated code to build them in another panel at runtime.

The dimensions such as widths, height & size are not working as expected between runtime vs design time. Why is this?

Eg below has 2 design time panels. The panel on the left contains design time controls and the one on the right runtime controls. this.dateTimePicker1.Size = new System.Drawing.Size(219, 26); sets the width = 219

However, at runtime dtp2.Size = new System.Drawing.Size(219, 26); is too long and I have to use dtp1.Width = 150; instead. Why 150 and not 219?

enter image description here

RunTime Control Code:

    private void BuildControls()
    {

        // 
        // dateTimePicker1
        // 
        DateTimePicker dtp1 = new DateTimePicker();
        dtp1.Location = new System.Drawing.Point(21, 35);
        dtp1.Name = "dateTimePicker1";
        //dtp1.Size = new System.Drawing.Size(219, 26);
        dtp1.Width = 150; //Not 219 as expected?
        dtp1.TabIndex = 1;
        panel2.Controls.Add(dtp1);

        // dateTimePicker2
        // 
        DateTimePicker dtp2 = new DateTimePicker();
        dtp2.Location = new System.Drawing.Point(21, 108);
        dtp2.Name = "dateTimePicker2"; 
        dtp2.Size = new System.Drawing.Size(219, 26); //Copying design time is too wide
        //dtp1.Width = 150;
        dtp2.TabIndex = 2;
        panel2.Controls.Add(dtp2);
    }

DesignTime Control Code:

    private void InitializeComponent()
    {
        this.panel1 = new System.Windows.Forms.Panel();
        this.label1 = new System.Windows.Forms.Label();
        this.dateTimePicker1 = new System.Windows.Forms.DateTimePicker();
        this.dateTimePicker2 = new System.Windows.Forms.DateTimePicker();
        this.label2 = new System.Windows.Forms.Label();
        this.panel2 = new System.Windows.Forms.Panel();
        this.panel1.SuspendLayout();
        this.SuspendLayout();
        // 
        // panel1
        // 
        this.panel1.Controls.Add(this.dateTimePicker2);
        this.panel1.Controls.Add(this.label2);
        this.panel1.Controls.Add(this.dateTimePicker1);
        this.panel1.Controls.Add(this.label1);
        this.panel1.Location = new System.Drawing.Point(26, 36);
        this.panel1.Name = "panel1";
        this.panel1.Size = new System.Drawing.Size(288, 514);
        this.panel1.TabIndex = 0;
        // 
        // label1
        // 
        this.label1.AutoSize = true;
        this.label1.Location = new System.Drawing.Point(17, 21);
        this.label1.Name = "label1";
        this.label1.Size = new System.Drawing.Size(87, 20);
        this.label1.TabIndex = 0;
        this.label1.Text = "Start Date:";
        // 
        // dateTimePicker1
        // 
        this.dateTimePicker1.Location = new System.Drawing.Point(21, 44);
        this.dateTimePicker1.Name = "dateTimePicker1";
        this.dateTimePicker1.Size = new System.Drawing.Size(219, 26);
        this.dateTimePicker1.TabIndex = 1;
        // 
        // dateTimePicker2
        // 
        this.dateTimePicker2.Location = new System.Drawing.Point(21, 108);
        this.dateTimePicker2.Name = "dateTimePicker2";
        this.dateTimePicker2.Size = new System.Drawing.Size(219, 26);
        this.dateTimePicker2.TabIndex = 3;
        // 
        // label2
        // 
        this.label2.AutoSize = true;
        this.label2.Location = new System.Drawing.Point(17, 85);
        this.label2.Name = "label2";
        this.label2.Size = new System.Drawing.Size(81, 20);
        this.label2.TabIndex = 2;
        this.label2.Text = "End Date:";
        // 
        // panel2
        // 
        this.panel2.Location = new System.Drawing.Point(450, 260);
        this.panel2.Name = "panel2";
        this.panel2.Size = new System.Drawing.Size(288, 290);
        this.panel2.TabIndex = 1;
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(850, 710);
        this.Controls.Add(this.panel2);
        this.Controls.Add(this.panel1);
        this.Name = "Form1";
        this.Text = "Form1";
        this.panel1.ResumeLayout(false);
        this.panel1.PerformLayout();
        this.ResumeLayout(false);

    }
  • 1
    Your original form was created on a machine that operates at 144 dpi (150% in the Display applet). But your program is not [dpiAware](http://stackoverflow.com/a/13228495/17034) or is running on a 96 dpi machine so the sizes you use are 150% too large. – Hans Passant Mar 15 '15 at 19:35

2 Answers2

2

Your problem is with Autoscaling.

This code:

this.dateTimePicker1.Size = new System.Drawing.Size(219, 26);

May not imply that this.dateTimePicker1.Size is really 219 x 26. Why? Because of this line here, from .designer.cs:

this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);

After that line an in-memory scaling is performed. This scaling is executed on all child controls right after this line:

this.groupBox1.PerformLayout();

After that, this.dateTimePicker1.Size will change to something closer to 150 in width. You may also notice that designer code does not match what's displayed in the properties pane when control is selected.

Solution, Part 1

Add something to the form to cause a change in the designer file and save it. This will at cause .designer.cs code to match the screen DPI and you won't see any inconsistencies any more. It seems that your DPI setting is higher than the one used when creating the form - if this is accidental, correct your Windows DPI setting to 96 or 100%.

Solution, Part 2

Once your form designer matches your screen DPI, you will see that all the size and location properties have been changed and that there is a new value set on AutoScaleDimensions, write down this value because this is the dimension that matches your screen DPI.

Now, whenever you want your controls' locations and sizes to respect the screen DPI you have to place your control logic in something like this:

// Your referential DPI setting (96DPI in this case)
this.AutoScaleDimensions = new SizeF(6F, 13F); 

// TODO: Place your code here

// Setting of your users
this.AutoScaleDimensions = this.CurrentAutoscaleDimensions; 

This would cause whatever controls placed in between to be scaled to whatever DPI is currently on the screen.

Note that 6F, 13F are values most people have for 96 DPI setting (default 100% zoom in Windows). This is why I asked to write down your value so you can use that instead.

If you still don't find this obnoxious you can also read up this question which has extra info: Creating a DPI-Aware Application.

Important Note I forgot to mention something - if you work in a team with source control software, take extra care because whenever you save something in designer it's going to alter every Size and Location to match your own setting (as explained above). This shouldn't cause problems but you should be always aware of this.

Community
  • 1
  • 1
bokibeg
  • 2,081
  • 16
  • 23
  • Solution, Part 2 doesn't work. In particular, setting `AutoScaleDimensions` seems to have no effect unless you first call `SuspendLayout`. Looks like the correct operation is: `SuspendLayout`, set the `AutoScaleDimensions` to the design-time dimensions, edit the control positions/sizes, then `ResumeLayout`. – Mark May 18 '16 at 10:42
0

try changing

this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

to

this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
Abdul Saleem
  • 10,098
  • 5
  • 45
  • 45