Changing Layout Dynamically in Windows Forms

Introduction

If you are a long-time Windows developer, at some point in time you must have faced the difficulty in adjusting your forms and dialogs for multiple screen resolutions. In the past, developers used various techniques to avoid such problems, including resizing controls at runtime by handling certain event handlers. However, the task was certainly not an easy one. Fortunately, the .NET Framework 2.0 provides some handy techniques that allow you to provide dynamic layout to your forms. In this article, I am going to illustrate some of these techniques with examples.

Why Dynamic Layout?

There are many scenarios wherein you need dynamic layouts. Some of the common ones are as follows:

  • You developed your application under one screen resolution and want to run it on machines having different (and possibly unknown) screen resolutions.
  • You are setting the text of controls such as Label and Button via code and don’t know the length of the text at design time.
  • You are developing a multilingual application and don’t know the width of controls under different language settings.
  • Your application adds controls dynamically on the forms.

In all such cases, being able to change the layout of your form dynamically becomes essential.

The Solution

Luckily, the .NET Framework 2.0 comes with several options to solve the problem of dynamic layout. In this article, I am going to cover the following options:

  • Auto sizing forms and controls
  • Docking
  • Anchoring
  • Flow layout panel
  • Table layout panel

Auto sizing forms and controls

In this example, you will learn to resize Windows Forms controls and forms automatically so that they fit their content. Before going any further, let me illustrate why such auto sizing is necessary.

Create a new Windows Application using Visual Studio and C# as the programming language. Design the default form as shown below:

The form consists of a textbox and three buttons. Clicking on the “Change Text” button changes Text property of the remaining two buttons to a value entered in the textbox. Write the following code in the Click event handler of “Change Text” button.

private void button3_Click(object sender, EventArgs e)
{
   button1.Text = textBox1.Text;
   button2.Text = textBox1.Text;
}

The code simply sets the Text property of button1 and button2 to a string entered in textBox1. After writing the code, run the form. Enter some big string value in the textbox and click the “Change Text” button. The following figure shows a sample run of the form.

Can you see the problem? The button controls do not display the complete text. Now, set the AutoSize property of both buttons to true. The AutoSize property governs whether a control should automatically adjust its width to accommodate its contents. Also, set the AutoSizeMode property of the first button to GrowOnly and that of the second button to GrowAndShrink. The AutoSizeMode property governs how a control should behave to adjust its contents. The value of GrowOnly indicates that the control can only expand to accommodate its content. The value of GrowAndShrink indicates that the control can expand or shrink to fit its content. Run the form again. This time, you will observe that the buttons adjust their width as per the text entered. Notice the behavior of the second button. It expands as well as shrinks according to the length of the text value.

Now, enter a very long string and check the behavior. You will find that the buttons adjust themselves as per the text but the form remains the same. As a result, buttons expand beyond the form boundaries.

This can be easily corrected by setting Form’s AutoSize property to true.

Docking

Suppose that you want to develop a form as shown below:

The form has a Label control at the bottom that displays some status message to the user. Try resizing the form. You will find that, as the form is resized, the Label doesn’t change its position and size. This is certainly undesirable (see below).

The expected behavior would be that the Label always remains attached with the bottom edge on the form. This is where the docking feature comes into picture. Windows Forms controls have a property called Dock that can dock that control to left, right, top, or bottom edge of the form. You can also make the control fill the available area of the form. To see this property in action, set the Dock property of the Label control to Bottom and run the form again. This time, as the form is resized, the Label is also resized and always remains attached to the bottom of the form.

Anchoring

Assume that you are developing a resizable dialog box that has two buttons, OK and Cancel (see below).

If you resize the form at runtime, you will find that the buttons assume a fixed location.

You would expect them to maintain the same distance from the right and bottom edges of the form. Thanks to the Anchor property, that makes this possible. The Anchor property anchors a control at some fixed place with respect to form borders. By default, controls are anchored at a fixed point from the top and left edges. To see the Anchor property in action, set the Anchor property of the OK and Cancel buttons to Bottom-Right and run the form. This time, you will observe that, even if you resize the form, the controls maintain a fixed distance from the bottom and right border of the form.

Flow layout panel control

In some applications, you need to add controls dynamically to the form depending on some condition. In such cases, you need to place the newly added control at an appropriate location via code. However, this means that you need to carefully calculate their left and top coordinates depending on surrounding controls. This can get tricky and tedious at times. To make the problem clear, develop a form that adds a few buttons dynamically to a GroupBox control. Add a new form to the project and drag and drop a GroupBox control to it. The GroupBox control is a container control and can house other controls inside it. Now, add the following code in the Load event of the form.

private void FlowLayoutDemo_Load(object sender, EventArgs e)
{
   for (int i = 0; i < 5; i++)
   {
      Button b = new Button();
      b.Text = "Button " + i.ToString();
      groupBox1.Controls.Add(b);
   }
}

The code above runs a for loop. With each iteration, a new Button is created and added to the Controls collection of the GroupBox. If you run this form, you will see something like this:

As you can see, all the dynamically added buttons assume the same left and top coordinates and as a result overlap each other. To arrange all of them, you need to write code. The FlowLayoutPanel control makes your job easy. See how.

Drag and drop a FlowLayoutPanel control on the same form and add the following code to the Load event of the form.

private void FlowLayoutDemo_Load(object sender, EventArgs e)
{
   for (int i = 0; i < 5; i++)
   {
      Button b = new Button();
      b.Text = "Button " + i.ToString();
      groupBox1.Controls.Add(b);
   }

   for (int i = 0; i < 5; i++)
   {
      Button b = new Button();
      b.Text = "Button " + i.ToString();
      flowLayoutPanel1.Controls.Add(b);
   }

}

The code adds another for loop. This time, the new for loop adds buttons to FlowLayoutPanel control. If you run the form, you will observe that buttons added to FlowLayoutPanel automatically get arranged one after the other (see below).

The FlowLayoutPanel control has a property called FlowDirection that governs the direction in which the child controls are arranged. The FlowDirection property has four possible values: LeftToRight, TopDown, RightToLeft, and BottomUp. The WrapContents boolean property governs whether the contents of FlowLayoutPanel will be wrapped or clipped depending on the FlowLayoutPanel width.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read