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.

You need the following components to complete this walkthrough:

  • Visual Studio 2010.

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>
    

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.

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.

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.

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.

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
    
  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.

By default, visible WindowsFormsHost elements are always drawn on top of other WPF elements, and they are unaffected by z-order. To enable z-ordering, set the IsRedirected property of the WindowsFormsHost to true and the CompositionMode property to Full or OutputOnly.

To see the default z-order behavior

  1. Copy the following XAML into the Grid element.

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

To see the z-order behavior when IsRedirected is true

  • Replace the previous z-order example with the following XAML.

    <!-- Z-order demonstration. -->
    <Canvas Grid.Row="1" Grid.Column="1">
      <WindowsFormsHost IsRedirected="True" CompositionMode="Full" Canvas.Top="20" Canvas.Left="20" Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
      <Label Content="A WPF label" FontSize="24"/>
    </Canvas>
    

    Press F5 to build and run the application. The label element is painted over the WindowsFormsHost element.

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.

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
    
  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.

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.

Unlike WPF elements, most Windows Forms controls are not continuously scalable. By default, the WindowsFormsHost element scales its hosted control when possible. To enable full-fledged scaling, set the IsRedirected property of the WindowsFormsHost to true and the CompositionMode property to Full or OutputOnly.

To scale a hosted control by using the default behavior

  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.

To scale a hosted control by setting IsRedirected to true

  1. Replace the previous scaling example with the following XAML.

    <!-- 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" IsRedirected="True" CompositionMode="Full">
        <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, its surrounding elements, and the hosted control's font are scaled by a factor of 0.5.

Unlike WPF elements, Windows Forms controls do not support rotation. By default, 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 enable rotating to any angle, set the IsRedirected property of the WindowsFormsHost to true and the CompositionMode property to Full or OutputOnly.

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.

To see the effect of rotation in a hybrid application when IsRedirected is true

  1. Replace the previous rotation example with the following XAML.

    <!-- 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" IsRedirected="True" CompositionMode="Full">
        <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 rotated. Note that the Angle property can be set to any value. You may have to resize the window to see the elements.

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.

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
    
  3. Add a call to the InitializeFlowLayoutPanel method in the constructor.

    Public Sub New()
        InitializeComponent()
    
        Me.InitializeFlowLayoutPanel()
    
    End Sub
    
  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.

Was this page helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft