演练:在 Windows Presentation Foundation 中排列 Windows 窗体控件

更新:2007 年 11 月

本演练演示如何使用 WPF 布局功能在混合应用程序中排列 Windows 窗体控件。

本演练涉及以下任务:

  • 创建项目。

  • 使用默认布局设置。

  • 根据内容调整大小。

  • 使用绝对定位。

  • 显式指定大小。

  • 设置布局属性。

  • 了解 Z 顺序限制。

  • 停靠。

  • 设置可见性。

  • 承载不拉伸的控件。

  • 缩放。

  • 旋转。

  • 设置空白和边距。

  • 使用动态布局容器。

有关本演练中演示的任务的完整代码清单,请参见在 Windows Presentation Foundation 中排列 Windows 窗体控件的示例

在完成本演练后,您将对基于 WPF 的应用程序中的 Windows 窗体布局功能有一定了解。

说明:

显示的对话框和菜单命令可能会与“帮助”中的描述有所不同,具体取决于您现用的设置或版本。若要更改设置,请在“工具”菜单上选择“导入和导出设置”。有关更多信息,请参见 Visual Studio 设置

先决条件

您需要以下组件来完成本演练:

  • Visual Studio 2008.

创建项目

创建和设置项目

  1. 创建一个名为 WpfLayoutHostingWf 的 WPF 应用程序项目。

  2. 在解决方案资源管理器中,添加一个对名为 WindowsFormsIntegration.dll 的 WindowsFormsIntegration 程序集的引用。

  3. 在解决方案资源管理器中,添加一个对名为 System.Windows.Forms.dll 的 System.Windows.Forms 程序集的引用。还添加一个对名为 System.Drawing.dll 的 System.Drawing 程序集的引用。

  4. 双击 Window1.xaml 将它在 XAML 视图中打开。

  5. 在文件的开头,用下面的代码映射 Windows 窗体命名空间。

    <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"
        >
    
    <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"
        >
    
  6. 通过创建五行和三列设置默认 Grid 元素。

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

使用默认布局设置

默认情况下,WindowsFormsHost 元素处理所承载的 Windows 窗体控件的布局。

使用默认布局设置

  1. 将下面的代码复制到 Grid 元素中。

    <!-- 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. 按 F5 生成并运行该应用程序。此时 Windows 窗体System.Windows.Forms.Button 控件将出现在 Canvas 中。所承载的控件根据其内容调整大小,并且 WindowsFormsHost 元素也会根据所承载的控件调整大小。

根据内容调整大小

WindowsFormsHost 元素确保调整所承载的控件的大小,以正确地显示其内容。

根据内容调整大小

  1. 将下面的代码复制到 Grid 元素中前面的代码示例的后面。

    <!-- 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. 按 F5 生成并运行该应用程序。两个新按钮控件会调整大小以正确地显示较长的文本字符串和较大的字号,并且 WindowsFormsHost 元素也会根据所承载的控件调整大小。

使用绝对定位

您可以使用绝对定位将 WindowsFormsHost 元素放在用户界面 (UI) 中的任意位置。

使用绝对定位

  1. 将下面的代码复制到 Grid 元素中前面的代码示例的后面。

    <!-- 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. 按 F5 生成并运行该应用程序。WindowsFormsHost 元素置于网格单元格中距离顶部 20 像素、距离左侧 20 像素的位置。

显式指定大小

可以使用 WidthHeight 属性指定 WindowsFormsHost 元素的大小。

显式指定大小

  1. 将下面的代码复制到 Grid 元素中前面的代码示例的后面。

    <!-- 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. 按 F5 生成并运行该应用程序。WindowsFormsHost 元素的大小设置为 50 像素宽、70 像素高,这比默认布局设置小。Windows 窗体控件的内容相应地重新排列。

设置布局属性

应始终使用 WindowsFormsHost 元素的属性对所承载的控件设置与布局有关的属性。直接对所承载的控件设置布局属性会产生意外的结果。

以 XAML 对所承载的控件设置与布局有关的属性无效。

查看对所承载的控件设置属性的效果

  1. 将下面的代码复制到 Grid 元素中前面的代码示例的后面。

    <!-- 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. 在解决方案资源管理器中,双击 Window1.xaml.cs 将它在代码编辑器中打开。

  3. 将下面的代码复制到 Window1 类定义中 Window1() 构造函数的后面。

    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
    
    private void button1Click(object sender, EventArgs e )
    {
        System.Windows.Forms.Button b = sender as System.Windows.Forms.Button;
    
        b.Top = 20;
        b.Left = 20;
    }
    
  4. 按 F5 生成并运行该应用程序。

  5. 单击“Click me”(单击这里)按钮。button1Click 事件处理程序设置所承载的控件的 TopLeft 属性。这导致所承载的控件在 WindowsFormsHost 元素中重新定位。宿主占据相同的屏幕区域,但所承载的控件被剪辑。所承载的控件应总是填充 WindowsFormsHost 元素。

了解 Z 顺序限制

可见的 WindowsFormsHost 元素始终绘制在其他 WPF 元素的上面,它们不受 Z 顺序的影响。

查看 Z 顺序限制

  1. 在 Window1.xaml 文件中,将下面的代码复制到 Grid 元素中前面的代码示例的后面。

    <!-- 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. 按 F5 生成并运行该应用程序。WindowsFormsHost 元素绘制在标签元素的上面。

停靠

WindowsFormsHost 元素支持 WPF 停靠。设置 Dock 附加属性,以便将所承载的控件停靠在 DockPanel 元素中。

停靠所承载的控件

  1. 将下面的代码复制到 Grid 元素中前面的代码示例的后面。

    <!-- 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. 按 F5 生成并运行该应用程序。WindowsFormsHost 元素停靠在 DockPanel 元素的右侧。

设置可见性

通过在 WindowsFormsHost 元素上设置 Visibility 属性,可以使 Windows 窗体控件不可见或将它折叠。当控件不可见时,它不会显示,但会占据布局空间。当控件折叠时,它不会显示,也不会占据布局控件。

设置所承载控件的可见性

  1. 将下面的代码复制到 Grid 元素中前面的代码示例的后面。

    <!-- 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. 在解决方案资源管理器中,双击 Window1.xaml.cs 将它在代码编辑器中打开。

  3. 将下面的代码复制到 Window1 类定义中。

    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
    
    private void button2Click(object sender, EventArgs e)
    {
        this.host1.Visibility = Visibility.Hidden;
    }
    
    private void button3Click(object sender, EventArgs e)
    {
        this.host1.Visibility = Visibility.Collapsed;
    }
    
  4. 按 F5 生成并运行该应用程序。

  5. 单击“Click to make invisible”(单击隐藏)按钮使 WindowsFormsHost 元素不可见。

  6. 单击“Click to collapse”(单击折叠)按钮使 WindowsFormsHost 元素完全从布局中隐藏。当 Windows 窗体控件折叠时,周围的元素会重新排列以占据它的空间。

承载不拉伸的控件

一些 Windows 窗体控件具有固定的大小,不会拉伸以填满布局中的可用空间。例如,MonthCalendar 控件在固定的空间中显示月份。

承载不拉伸的控件

  1. 将下面的代码复制到 Grid 元素中前面的代码示例的后面。

    <!-- 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. 按 F5 生成并运行该应用程序。WindowsFormsHost 元素在网格行中居中,但它不会拉伸以填满可用空间。如果窗口足够大,您可能会看到所承载的 MonthCalendar 控件显示两个或更多个月份,但这些月份在一行中居中。WPF 布局引擎使不能调整大小以填满可用空间的元素居中。

缩放

与 WPF 元素不同,大多数 Windows 窗体控件都不是可连续缩放的。如果可能,WindowsFormsHost 元素会对它所承载的控件进行缩放。

对所承载的控件进行缩放

  1. 将下面的代码复制到 Grid 元素中前面的代码示例的后面。

    <!-- 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. 按 F5 生成并运行该应用程序。所承载的控件及其周围元素按 0.5 的比例进行缩放。但是,所承载控件的字体不缩放。

旋转

与 WPF 元素不同,Windows 窗体控件不支持旋转。当应用旋转变换时,WindowsFormsHost 元素不随其他 WPF 元素一起旋转。180 度以外的任何旋转值都会引发 LayoutError 事件。

查看混合应用程序中的旋转效果

  1. 将下面的代码复制到 Grid 元素中前面的代码示例的后面。

    <!-- 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. 按 F5 生成并运行该应用程序。所承载的控件不旋转,但是它周围的元素旋转 180 度。

设置空白和边距

WPF 布局中的空白和边距与 Windows 窗体中的空白和边距类似。只需在 WindowsFormsHost 元素上设置 PaddingMargin 属性。

为承载的控件设置空白和边距

  1. 将下面的代码复制到 Grid 元素中前面的代码示例的后面。

    <!-- 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>
    
    <!-- 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. 按 F5 生成并运行该应用程序。空白和边距设置应用于承载的 Windows 窗体控件,就像在 Windows 窗体中应用一样。

使用动态布局容器

Windows 窗体提供两个动态布局容器,即 FlowLayoutPanelTableLayoutPanel。您还可以在 WPF 布局中使用这些容器。

使用动态布局容器

  1. 将下面的代码复制到 Grid 元素中前面的代码示例的后面。

    <!-- 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. 在解决方案资源管理器中,双击 Window1.xaml.cs 将它在代码编辑器中打开。

  3. 将下面的代码复制到 Window1 类定义中。

    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);
        }
    }
    
  4. 在构造函数中添加对 InitializeFlowLayoutPanel 方法的调用。

    Public Sub New()
        InitializeComponent()
    
        Me.InitializeFlowLayoutPanel()
    
    End Sub
    
    public Window1()
    {
        InitializeComponent();
    
        this.InitializeFlowLayoutPanel();
    }
    
  5. 按 F5 生成并运行该应用程序。WindowsFormsHost 元素填充 DockPanelFlowLayoutPanel 按默认 FlowDirection 排列它的子控件。

请参见

任务

在 Windows Presentation Foundation 中排列 Windows 窗体控件的示例

概念

WindowsFormsHost 元素的布局注意事项

演练:在 Windows Presentation Foundation 中承载 Windows 窗体复合控件

演练:在 Windows 窗体中承载 Windows Presentation Foundation 控件

参考

ElementHost

WindowsFormsHost

其他资源

WPF 设计器

迁移和互操作性帮助主题