Wednesday, February 10, 2010

A nasty case with AutoScaleMode

Yesterday we tackled a strange problem at work. Some of our application forms that were displayed correctly on our development machine and on most of our test machine, failed to load on a machine with a Japanese Windows OS. A NullReferneceException was thrown during their load.

For those of you who don’t know what is AutoScaleMode let me explain shortly. This is a property of ContainerControl that specifies how to perform automatic scaling of the control and its’ children. Automatic scaling is a feature that lets you develop a form or control on one screen resolution or font settings and use it on a machine with other settings. The form and its’ children will intelligently resize if you use it correctly. If you want more information about Automatic Scaling try this article Automatic Scaling in Windows Forms.

Now we are ready to show the  problem. Let’s look at an example.

There is a BaseControl class that is defined as follows:

   1: public class BaseControl : UserControl



   2: {



   3:     public BaseControl()



   4:     {



   5:         InitializeComponent();



   6:     }



   7:  



   8:     private void InitializeComponent()



   9:     {



  10:         this.SuspendLayout();



  11:         // 



  12:         // BaseControl



  13:         // 



  14:         this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);



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



  16:         this.Name = "BaseControl";



  17:         this.ResumeLayout(false);



  18:  



  19:     }



  20: }




And here is the code for some DerivedControl class:







   1: public class DerivedControl : BaseControl



   2: {



   3:     private string someString;



   4:  



   5:     public DerivedControl()



   6:     {



   7:         InitializeComponent();



   8:         //initialize someString here.



   9:     }



  10:  



  11:     protected override void OnResize(EventArgs e)



  12:     {



  13:         base.OnResize(e);



  14:         //use someString here.



  15:     }



  16: }






Since we developed our application on a machine with English settings and most of our test machine were in the same settings as the development machines, the code was executing perfectly.



When the code was running on a Japanese machine something different happened. While creating an instance of DerivedControl the BaseControl constructor was called. BaseControl constructor called its’ InitializeComponents method and as a result the OnResize method of DerivedControl was called. The OnResize method was called due to lines 14 and 15 of  BaseControl since the screen resolution or font settings were different from the development machine settings. Since someString was not initialized yet, a NullReferenceException has been thrown.



To fix this problem we simply set the AutoScaleMode property to AutoScaleMode.None since we don’t need Automatic Scaling support. Of course it took us a while before we understood this problem and therefore I decided to share our experience.



Conclusions:




  • Beware from the AutoScaleMode property.


  • Test your WinForms application on different screen resolutions, DPI settings and Font setting.

2 comments:

  1. The fat portions of code are to emphasize what is going when you use AutoScaleMode incorrectly. :). This is a bug with the code snippet editor I used to create this blog. Hope you enjoy the post anyway.

    ReplyDelete
  2. You need to find a better way to post code, the code snippet you are currently using isn't any good.

    Anyway, it's 2010 , give us some WPF bla-bla instead of WinForms quirks :)

    Hope to see you sometime soon

    ReplyDelete