Partager via


Walkthrough: Arranging Windows Forms Controls in Windows Presentation Foundation

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 Windows Presentation Foundation Sample.

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

NoteNote:

The dialog boxes and menu commands you see might differ from those described in Help, depending on your active settings or edition. To change your settings, choose Import and Export Settings on the Tools menu.

Prerequisites

To complete this walkthrough you will need:

Creating the Project

To create and set up the project

  1. Create a Windows Application (WPF) project named WpfLayoutHostingWf.

  2. In Solution Explorer, add a reference to the WindowsFormsIntegration assembly, which is named WindowsFormsIntegration.dll.

    The default location for this file is %programfiles%\Reference Assemblies\Microsoft\Framework\v3.0\WindowsFormsIntegration.dll.

  3. In Solution Explorer, add a reference to the System.Windows.Forms assembly, which is named System.Windows.Forms.dll. Also add a reference to the System.Drawing assembly, which is named System.Drawing.dll.

  4. Double-click Window1.xaml to open it in the Code Editor.

  5. At the start of the file, map the Windows Forms namespace with the following code.

    <Window x:Class="WpfLayoutHostingWfWithXaml.Window1"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"  
        Title="Layout Demo for Interoperability"
        >
    
    <Window x:Class="Window1"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"  
        Title="Layout Demo for Interoperability"
        >
    
  6. Set up the default Grid element by creating five rows and three columns.

    <Grid ShowGridLines="true">
      <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
      </Grid.RowDefinitions>
    
      <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
      </Grid.ColumnDefinitions>
    
    <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 code 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>
    
    <!-- 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 code into the Grid element, after the previous code example.

    <!-- 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>
    
    <!-- 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 code into the Grid element, after the previous code example.

    <!-- 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>
    
    <!-- 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 code into the Grid element, after the previous code example.

    <!-- 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>
    
    <!-- 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 code into the Grid element, after the previous code example.

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

  3. Copy the following code into the Window1 class definition, after the Window1() constructor.

    private void button1Click(object sender, EventArgs e )
    {
        System.Windows.Forms.Button b = sender as System.Windows.Forms.Button;
    
        b.Top = 20;
        b.Left = 20;
    }
    
    Private Sub button1Click(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 button1Click 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. In the Window1.xaml file, copy the following code into the Grid element, after the previous code example.

    <!-- 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>
    
    <!-- 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 code into the Grid element, after the previous code example.

    <!-- 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>
    
    <!-- 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 code into the Grid element, after the previous code example.

    <!-- Setting Visibility to hidden and collapsed. -->
    <StackPanel Grid.Row="3" Grid.Column="1">
      <Button Name="button2" Click="button2Click" 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="button3Click" Content="Click to collapse" Background="OrangeRed"/>
    </StackPanel>
    
    <!-- Setting Visibility to hidden and collapsed. -->
    <StackPanel Grid.Row="3" Grid.Column="1">
      <Button Name="button2" Click="button2Click" 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="button3Click" Content="Click to collapse" Background="OrangeRed"/>
    </StackPanel>
    
  2. In Solution Explorer, double-click Window1.xaml.cs to open it in the Code Editor.

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

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

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

  6. 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 code into the Grid element, after the previous code example.

    <!-- 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>
    
    <!-- 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 code into the Grid element, after the previous code example.

    <!-- 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>
    
    <!-- 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 code into the Grid element, after the previous code example.

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

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 code into the Grid element, after the previous code example.

    <!-- 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>
    
    ...
    
    <!-- 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>
    
    ...
    
    <!-- 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 code into the Grid element, after the previous code example.

    <!-- Flow layout. -->
    <DockPanel Grid.Row="4" Grid.Column="2">
      <WindowsFormsHost Name="flowLayoutHost" Background="Yellow">
        <wf:FlowLayoutPanel/>
      </WindowsFormsHost>
    </DockPanel>
    
    <!-- Flow layout. -->
    <DockPanel Grid.Row="4" Grid.Column="2">
      <WindowsFormsHost Name="flowLayoutHost" Background="Yellow">
        <wf:FlowLayoutPanel/>
      </WindowsFormsHost>
    </DockPanel>
    
  2. In Solution Explorer, double-click Window1.xaml.cs to open it in the Code Editor.

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

    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);
        }
    }
    
    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
    
  4. Add a call to the InitializeFlowLayoutPanel method in the constructor.

    public Window1()
    {
        InitializeComponent();
    
        this.InitializeFlowLayoutPanel();
    }
    
    Public Sub New()
        InitializeComponent()
    
        Me.InitializeFlowLayoutPanel()
    
    End Sub
    
  5. 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 Windows Presentation Foundation
Walkthrough: Hosting a Windows Presentation Foundation Control in Windows Forms

Other Resources

Arranging Windows Forms Controls in Windows Presentation Foundation Sample
Migration and Interoperability How-to Topics