Walkthrough: Arranging Windows Forms Controls in WPF

This walkthrough shows you how to use WPF layout features to arrange Windows Forms controls in a hybrid application.

Tasks illustrated in this walkthrough include:

  • Creating the project.

  • Using default layout settings.

  • Sizing to content.

  • Using absolute positioning.

  • Specifying size explicitly.

  • Setting layout properties.

  • Understanding z-order limitations.

  • Docking.

  • Setting visibility.

  • Hosting a control that does not stretch.

  • Scaling.

  • Rotating.

  • Setting padding and margins.

  • Using dynamic layout containers.

For a complete code listing of the tasks illustrated in this walkthrough, see Arranging Windows Forms Controls in WPF Sample.

When you are finished, you will have an understanding of Windows Forms layout features in WPF-based applications.

Prerequisites

You need the following components to complete this walkthrough:

  • Visual Studio 2010.

Creating the Project

To create and set up the project

  1. Create a WPF Application project named WpfLayoutHostingWf.

  2. In Solution Explorer, add references to the following assemblies.

    • WindowsFormsIntegration

    • System.Windows.Forms

    • System.Drawing

  3. Double-click MainWindow.xaml to open it in XAML view.

  4. In the Window element, add the following Windows Forms namespace mapping.

    xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
    
  5. In the Grid element set the ShowGridLines property to true and define five rows and three columns.

    <Grid ShowGridLines="true">
      <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
      </Grid.RowDefinitions>
    
      <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
      </Grid.ColumnDefinitions>
    

Using Default Layout Settings

By default, the WindowsFormsHost element handles the layout for the hosted Windows Forms control.

To use default layout settings

  1. Copy the following XAML into the Grid element.

    <!-- Default layout. -->
    <Canvas Grid.Row="0" Grid.Column="0">
      <WindowsFormsHost Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Canvas>
    
  2. Press F5 to build and run the application. The Windows Forms System.Windows.Forms.Button control appears in the Canvas. The hosted control is sized based on its content, and the WindowsFormsHost element is sized to accommodate the hosted control.

Sizing to Content

The WindowsFormsHost element ensures that the hosted control is sized to display its content properly.

To size to content

  1. Copy the following XAML into the Grid element.

    <!-- Sizing to content. -->
    <Canvas Grid.Row="1" Grid.Column="0">
      <WindowsFormsHost Background="Orange">
        <wf:Button Text="Windows Forms control with more content" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Canvas>
    
    <Canvas Grid.Row="2" Grid.Column="0">
      <WindowsFormsHost FontSize="24" Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Canvas>
    
  2. Press F5 to build and run the application. The two new button controls are sized to display the longer text string and larger font size properly, and the WindowsFormsHost elements are resized to accommodate the hosted controls.

Using Absolute Positioning

You can use absolute positioning to place the WindowsFormsHost element anywhere in the user interface (UI).

To use absolute positioning

  1. Copy the following XAML into the Grid element.

    <!-- Absolute positioning. -->
    <Canvas Grid.Row="3" Grid.Column="0">
      <WindowsFormsHost Canvas.Top="20" Canvas.Left="20" Background="Yellow">
        <wf:Button Text="Windows Forms control with absolute positioning" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Canvas>
    
  2. Press F5 to build and run the application. The WindowsFormsHost element is placed 20 pixels from the top side of the grid cell and 20 pixels from the left.

Specifying Size Explicitly

You can specify the size of the WindowsFormsHost element using the Width and Height properties.

To specify size explicitly

  1. Copy the following XAML into the Grid element.

    <!-- Explicit sizing. -->
    <Canvas Grid.Row="4" Grid.Column="0">
      <WindowsFormsHost Width="50" Height="70" Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Canvas>
    
  2. Press F5 to build and run the application. The WindowsFormsHost element is set to a size of 50 pixels wide by 70 pixels high, which is smaller than the default layout settings. The content of the Windows Forms control is rearranged accordingly.

Setting Layout Properties

Always set layout-related properties on the hosted control by using the properties of the WindowsFormsHost element. Setting layout properties directly on the hosted control will yield unintended results.

Setting layout-related properties on the hosted control in XAML has no effect.

To see the effects of setting properties on the hosted control

  1. Copy the following XAML into the Grid element.

    <!-- Setting hosted control properties directly. -->
    <Canvas Grid.Row="0" Grid.Column="1">
      <WindowsFormsHost Width="160" Height="50" Background="Yellow">
        <wf:Button Name="button1" Click="button1_Click" Text="Click me" FlatStyle="Flat" BackColor="Green"/>
      </WindowsFormsHost>
    </Canvas>
    
  2. In Solution Explorer, double-click MainWindow.xaml. vb or MainWindow.xaml.cs to open it in the Code Editor.

  3. Copy the following code into the MainWindow class definition.

    Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs)
        Dim b As System.Windows.Forms.Button = sender
    
        b.Top = 20
        b.Left = 20
    
    End Sub
    
    private void button1_Click(object sender, EventArgs e )
    {
        System.Windows.Forms.Button b = sender as System.Windows.Forms.Button;
    
        b.Top = 20;
        b.Left = 20;
    }
    
  4. Press F5 to build and run the application.

  5. Click the Click me button. The button1_Click event handler sets the Top and Left properties on the hosted control. This causes the hosted control to be repositioned within the WindowsFormsHost element. The host maintains the same screen area, but the hosted control is clipped. Instead, the hosted control should always fill the WindowsFormsHost element.

Understanding Z-Order Limitations

Visible WindowsFormsHost elements are always drawn on top of other WPF elements, and they are unaffected by z-order.

To see z-order limitations

  1. Copy the following XAML into the Grid element.

    <!-- Z-order demonstration. -->
    <Canvas Grid.Row="1" Grid.Column="1">
      <Label Content="A WPF label" FontSize="24"/>
      <WindowsFormsHost Canvas.Top="20" Canvas.Left="20" Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Canvas>
    
  2. Press F5 to build and run the application. The WindowsFormsHost element is painted over the label element.

Docking

WindowsFormsHost element supports WPF docking. Set the Dock attached property to dock the hosted control in a DockPanel element.

To dock a hosted control

  1. Copy the following XAML into the Grid element.

    <!-- Docking a WindowsFormsHost element. -->
    <DockPanel LastChildFill="false"  Grid.Row="2" Grid.Column="1">
      <WindowsFormsHost DockPanel.Dock="Right"  Canvas.Top="20" Canvas.Left="20" Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </DockPanel>
    
  2. Press F5 to build and run the application. The WindowsFormsHost element is docked to the right side of the DockPanel element.

Setting Visibility

You can make your Windows Forms control invisible or collapse it by setting the Visibility property on the WindowsFormsHost element. When a control is invisible, it is not displayed, but it occupies layout space. When a control is collapsed, it is not displayed, nor does it occupy layout space.

To set the visibility of a hosted control

  1. Copy the following XAML into the Grid element.

    <!-- Setting Visibility to hidden and collapsed. -->
    <StackPanel Grid.Row="3" Grid.Column="1">
      <Button Name="button2" Click="button2_Click" Content="Click to make invisible" Background="OrangeRed"/>
      <WindowsFormsHost Name="host1"  Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
      <Button Name="button3" Click="button3_Click" Content="Click to collapse" Background="OrangeRed"/>
    </StackPanel>
    
  2. In MainWindow.xaml.vb or MainWindow.xaml.cs, copy the following code into the class definition.

    Private Sub button2_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Me.host1.Visibility = Windows.Visibility.Hidden
    End Sub
    
    
    Private Sub button3_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Me.host1.Visibility = Windows.Visibility.Collapsed
    End Sub
    
    private void button2_Click(object sender, EventArgs e)
    {
        this.host1.Visibility = Visibility.Hidden;
    }
    
    private void button3_Click(object sender, EventArgs e)
    {
        this.host1.Visibility = Visibility.Collapsed;
    }
    
  3. Press F5 to build and run the application.

  4. Click the Click to make invisible button to make the WindowsFormsHost element invisible.

  5. Click the Click to collapse button to hide the WindowsFormsHost element from the layout entirely. When the Windows Forms control is collapsed, the surrounding elements are rearranged to occupy its space.

Hosting a Control That Does Not Stretch

Some Windows Forms controls have a fixed size and do not stretch to fill available space in the layout. For example, the MonthCalendar control displays a month in a fixed space.

To host a control that does not stretch

  1. Copy the following XAML into the Grid element.

    <!-- Hosting a control that does not stretch. -->
    <!-- The MonthCalendar has a discrete size. -->
    <StackPanel Grid.Row="4" Grid.Column="1">
      <Label Content="A WPF element" Background="OrangeRed"/>
      <WindowsFormsHost Background="Yellow">
        <wf:MonthCalendar/>
      </WindowsFormsHost>
      <Label Content="Another WPF element" Background="OrangeRed"/>
    </StackPanel>
    
  2. Press F5 to build and run the application. The WindowsFormsHost element is centered in the grid row, but it is not stretched to fill the available space. If the window is large enough, you may see two or more months displayed by the hosted MonthCalendar control, but these are centered in the row. The WPF layout engine centers elements that cannot be sized to fill the available space.

Scaling

Unlike WPF elements, most Windows Forms controls are not continuously scalable. The WindowsFormsHost element scales its hosted control when possible.

To scale a hosted control

  1. Copy the following XAML into the Grid element.

    <!-- Scaling transformation. -->
    <StackPanel Grid.Row="0" Grid.Column="2">
    
      <StackPanel.RenderTransform>
        <ScaleTransform CenterX="0" CenterY="0" ScaleX="0.5" ScaleY="0.5" />
      </StackPanel.RenderTransform>
    
      <Label Content="A WPF UIElement" Background="OrangeRed"/>
    
      <WindowsFormsHost Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
    
      <Label Content="Another WPF UIElement" Background="OrangeRed"/>
    
    </StackPanel>
    
  2. Press F5 to build and run the application. The hosted control and its surrounding elements are scaled by a factor of 0.5. However, the hosted control's font is not scaled.

Rotating

Unlike WPF elements, Windows Forms controls do not support rotation. The WindowsFormsHost element does not rotate with other WPF elements when a rotation transformation is applied. Any rotation value other than 180 degrees raises the LayoutError event.

To see the effect of rotation in a hybrid application

  1. Copy the following XAML into the Grid element.

    <!-- Rotation transformation. -->
    <StackPanel Grid.Row="1" Grid.Column="2">
    
      <StackPanel.RenderTransform>
        <RotateTransform CenterX="200" CenterY="50" Angle="180" />
      </StackPanel.RenderTransform>
    
      <Label Content="A WPF element" Background="OrangeRed"/>
    
      <WindowsFormsHost Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
    
      <Label Content="Another WPF element" Background="OrangeRed"/>
    
    </StackPanel>
    
  2. Press F5 to build and run the application. The hosted control is not rotated, but its surrounding elements are rotated by an angle of 180 degrees. You may have to resize the window to see the elements.

Setting Padding and Margins

Padding and margins in WPF layout are similar to padding and margins in Windows Forms. Simply set the Padding and Margin properties on the WindowsFormsHost element.

To set padding and margins for a hosted control

  1. Copy the following XAML into the Grid element.

    <!-- Padding. -->
    <Canvas Grid.Row="2" Grid.Column="2">
      <WindowsFormsHost Padding="0, 20, 0, 0" Background="Yellow">
        <wf:Button Text="Windows Forms control with padding" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Canvas>
    
    
    ...
    
    
    <!-- Margin. -->
    <Canvas Grid.Row="3" Grid.Column="2">
      <WindowsFormsHost Margin="20, 20, 0, 0" Background="Yellow">
        <wf:Button Text="Windows Forms control with margin" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Canvas>
    
  2. Press F5 to build and run the application. The padding and margin settings are applied to the hosted Windows Forms controls in the same way they would be applied in Windows Forms.

Using Dynamic Layout Containers

Windows Forms provides two dynamic layout containers, FlowLayoutPanel and TableLayoutPanel. You can also use these containers in WPF layouts.

To use a dynamic layout container

  1. Copy the following XAML into the Grid element.

    <!-- Flow layout. -->
    <DockPanel Grid.Row="4" Grid.Column="2">
      <WindowsFormsHost Name="flowLayoutHost" Background="Yellow">
        <wf:FlowLayoutPanel/>
      </WindowsFormsHost>
    </DockPanel>
    
  2. In MainWindow.xaml.vb or MainWindow.xaml.cs copy the following code into the class definition.

    Private Sub InitializeFlowLayoutPanel()
        Dim flp As System.Windows.Forms.FlowLayoutPanel = Me.flowLayoutHost.Child
    
        flp.WrapContents = True
    
        Const numButtons As Integer = 6
    
        Dim i As Integer
        For i = 0 To numButtons
            Dim b As New System.Windows.Forms.Button()
            b.Text = "Button"
            b.BackColor = System.Drawing.Color.AliceBlue
            b.FlatStyle = System.Windows.Forms.FlatStyle.Flat
    
            flp.Controls.Add(b)
        Next i
    
    End Sub
    
    private void InitializeFlowLayoutPanel()
    {
        System.Windows.Forms.FlowLayoutPanel flp =
            this.flowLayoutHost.Child as System.Windows.Forms.FlowLayoutPanel;
    
        flp.WrapContents = true;
    
        const int numButtons = 6;
    
        for (int i = 0; i < numButtons; i++)
        {
            System.Windows.Forms.Button b = new System.Windows.Forms.Button();
            b.Text = "Button";
            b.BackColor = System.Drawing.Color.AliceBlue;
            b.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
    
            flp.Controls.Add(b);
        }
    }
    
  3. Add a call to the InitializeFlowLayoutPanel method in the constructor.

    Public Sub New()
        InitializeComponent()
    
        Me.InitializeFlowLayoutPanel()
    
    End Sub
    
    public MainWindow()
    {
        InitializeComponent();
    
        this.InitializeFlowLayoutPanel();
    }
    
  4. Press F5 to build and run the application. The WindowsFormsHost element fills the DockPanel, and FlowLayoutPanel arranges its child controls in the default FlowDirection.

See Also

Reference

ElementHost

WindowsFormsHost

Concepts

Layout Considerations for the WindowsFormsHost Element

Walkthrough: Hosting a Windows Forms Composite Control in WPF

Walkthrough: Hosting a WPF Composite Control in Windows Forms

Other Resources

WPF Designer

Arranging Windows Forms Controls in WPF Sample