C# – AutoScaleMode problems with changed default font

cnetwinforms

I have some problems with the Form.AutoScaleMode property together with fixed size controls, when using a non-default font. I boiled it down to a simple test application (WinForms 2.0) with only one form, some fixed size controls and the following properties:

class Form1 : Form
{
    // ...
    private void InitializeComponent()
    {
        // ...
        this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
        this.Font = new System.Drawing.Font("Tahoma", 9.25F);
        // ...
    }
}

Under 96dpi, Windows XP, the form looks correctly like this 96 dpi example:

96 dpi WinForm

Under 120 dpi, Windows XP, the the Windows Forms autoscaling feature produces this 120 dpi example:

Previous WinForm scaled to 120 dpi

As you can see, groupboxes, buttons, list or tree views are scaled correctly, multiline text boxes get too big in the vertical axis, and a fixed size label does not scale correctly in both vertical and horizontal direction. Seems to be bug in the .NET framework?

EDIT: some hints: the Font change is only applied to the containing form, the controls inherit their font from the form. I would like to keep it this way, if possible.

Using the default font (Microsoft Sans Serif 8.25pt), this problem does not occur. Using AutoScaleMode = Font (with adequate AutoScaleDimensions, of course) either does not scale at all or scales exactly like seen above, depending on when the Font is set (before or after the change of AutoScaleMode). The problem is not specific to the "Tahoma" Font, it occurs also with Microsoft Sans Serif, 9.25pt.

And yes, i already read this SO post
high DPI problems
but it does not really help me.

Any suggestions how to come around this?

EDIT2: Some additional information about my intention: I have about 50 already working fixed size dialogs with several hundreds of properly placed, fixed size controls. They were migrated from an older C++ GUI framework to C#/Winforms, that's why they are all fixed-size. All of them look fine with 96 dpi using a 9.25pt font. Under the old framework, scaling to 120 dpi worked fine – all fixed size controls scaled equal in both dimensions. Last week, we detected this strange scaling behaviour under WinForms when switching to 120 dpi. You can imagine that most of our dialogs now look very bad under 120 dpi. I am looking for a solution that avoids a complete redesign all those dialogs.

EDIT3: To test this behaviour, IMHO it is a good idea to set up a virtual Windows XP environment with 120 dpi while the development environment resides under 96 dpi (at least, that's what I did). Changing between 96 and 120 dpi normally needs a reboot under Win XP, otherwise you don't see what really happens.

// As requested: the source code of Form1.cs 
namespace DpiChangeTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Font f = this.textBox1.Font;
        }
    }
}

 // here the source of Form1.Designer.cs:
namespace DpiChangeTest
{
    partial class Form1
    {
        private System.ComponentModel.IContainer components = null;

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

        #region Windows Forms Designer generated code

        private void InitializeComponent()
        {
            System.Windows.Forms.ListViewItem listViewItem2 = new System.Windows.Forms.ListViewItem("A list view control");
            System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("A TreeView control");
            this.button1 = new System.Windows.Forms.Button();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.label1 = new System.Windows.Forms.Label();
            this.listView1 = new System.Windows.Forms.ListView();
            this.treeView1 = new System.Windows.Forms.TreeView();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(12, 107);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(150, 70);
            this.button1.TabIndex = 0;
            this.button1.Text = "Just a button";
            this.button1.UseVisualStyleBackColor = true;
            // 
            // groupBox1
            // 
            this.groupBox1.Location = new System.Drawing.Point(12, 12);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(150, 70);
            this.groupBox1.TabIndex = 1;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "Just a groupbox";
            // 
            // textBox1
            // 
            this.textBox1.Location = new System.Drawing.Point(180, 12);
            this.textBox1.Multiline = true;
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(150, 70);
            this.textBox1.TabIndex = 2;
            this.textBox1.Text = "A multiline text box";
            // 
            // label1
            // 
            this.label1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.label1.Location = new System.Drawing.Point(179, 107);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(150, 70);
            this.label1.TabIndex = 3;
            this.label1.Text = "A label with AutoSize=False";
            // 
            // listView1
            // 
            this.listView1.Items.AddRange(new System.Windows.Forms.ListViewItem[] {
            listViewItem2});
            this.listView1.Location = new System.Drawing.Point(12, 201);
            this.listView1.Name = "listView1";
            this.listView1.Size = new System.Drawing.Size(150, 70);
            this.listView1.TabIndex = 4;
            this.listView1.UseCompatibleStateImageBehavior = false;
            // 
            // treeView1
            // 
            this.treeView1.Location = new System.Drawing.Point(179, 201);
            this.treeView1.Name = "treeView1";
            treeNode2.Name = "Knoten0";
            treeNode2.Text = "A TreeView control";
            this.treeView1.Nodes.AddRange(new System.Windows.Forms.TreeNode[] {
            treeNode2});
            this.treeView1.Size = new System.Drawing.Size(150, 70);
            this.treeView1.TabIndex = 5;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
            this.ClientSize = new System.Drawing.Size(343, 289);
            this.Controls.Add(this.treeView1);
            this.Controls.Add(this.listView1);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.textBox1);
            this.Controls.Add(this.button1);
            this.Controls.Add(this.groupBox1);
            this.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.25F);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.GroupBox groupBox1;
        private System.Windows.Forms.TextBox textBox1;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.ListView listView1;
        private System.Windows.Forms.TreeView treeView1;
    }
}

 // and Main.cs
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

Best Answer

I finally found an answer for my question. In short, the effect does not arise when one sets the font of each control individually instead of setting the font of the containing form. This way, the auto scaling feature works as as it should. Interestingly, setting the font of the controls changes the auto-scaling behaviour even if the AutoScaleMode property is set to AutoScaleMode.Dpi, not only when it is set to AutoScaleMode.Font.

As a pragmatic solution, we created a small command line program, which reads the designer.cs files, scans if all controls have an explicit font assignment, and if not, adds the assignment into a newly created copy of the designer code. We embedded this program into our automatic test suite, so whenever a form gets new controls, or a new form is added, and the dev forgets to add the explicit font assignment, the tests will fail. In between, we have this solution working from the time I asked this question first (4 years ago), and it saved us from scaling problems for several times since then.

Related Topic