演练:在 WPF 中排列 Windows Forms 控件

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

本演练涉及以下任务:

  • 创建项目。
  • 使用默认布局设置。
  • 根据内容调整大小。
  • 使用绝对定位。
  • 显式指定大小。
  • 设置布局属性。
  • 了解 Z 顺序限制。
  • 停靠。
  • 设置可见性。
  • 承载不拉伸的控件。
  • 缩放。
  • 旋转。
  • 设置填充和边距。
  • 使用动态布局容器。

有关本演练中介绍的任务的完整代码列表,请参阅有关在 WPF 中排列 Windows 窗体控件的示例

完成后,你将了解基于 WPF 的应用程序中的 Windows 窗体布局功能。

先决条件

需要 Visual Studio 才能完成本演练。

创建项目

若要创建和设置项目,请执行以下步骤:

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

  2. 在解决方案资源管理器中,添加对以下程序集的引用:

    • WindowsFormsIntegration
    • System.Windows.Forms
    • System.Drawing
  3. 双击 MainWindow.xaml 以在 XAML 视图中打开它。

  4. Window 元素中,添加以下 Windows 窗体命名空间映射。

    xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
    
  5. Grid 元素中,将 ShowGridLines 属性设置为 true 并定义五行和三列。

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

使用默认布局设置

默认情况下,WindowsFormsHost 元素负责承载的 Windows Forms 控件的布局。

若要使用默认布局设置,请执行以下步骤:

  1. 将以下 XAML 复制到 Grid 元素中:

    <!-- 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. 将以下 XAML 复制到 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>
    
  2. F5 生成和运行应用程序。 这两个新增按钮控件的尺寸经过调整,以能够适当显示较长的文本字符串和较大的字体大小,WindowsFormsHost 元素的尺寸也经过相应调整,以容纳托管控件。

使用绝对定位

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

若要使用绝对定位,请执行以下步骤:

  1. 将以下 XAML 复制到 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>
    
  2. F5 生成和运行应用程序。 WindowsFormsHost 元素置于网格单元格中距顶部 20 个像素、距左侧 20 个像素的位置。

显式指定大小

可以使用 WindowsFormsHostWidth 属性指定 Height 元素的大小。

若要显式指定大小,请执行以下步骤:

  1. 将以下 XAML 复制到 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>
    
  2. F5 生成和运行应用程序。 WindowsFormsHost 元素的大小设置为 50 像素宽,70 像素高,比默认布局设置的尺寸小。 将相应重新排列 Windows 窗体控件的内容。

设置布局属性

应始终使用 WindowsFormsHost 元素的属性在托管控件上设置与布局相关的属性。 直接在托管控件上设置布局属性将产生意外的结果。

在 XAML 中设置托管控件的布局相关属性没有效果。

若要查看在托管控件上设置属性的效果,请执行以下步骤:

  1. 将以下 XAML 复制到 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="button1_Click" Text="Click me" FlatStyle="Flat" BackColor="Green"/>
      </WindowsFormsHost>
    </Canvas>
    
  2. 解决方案资源管理器中,双击 MainWindow.xaml.vbMainWindow.xaml.cs 在代码编辑器中打开它。

  3. 将以下代码复制到 MainWindow 类定义中:

    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;
    }
    
    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. F5 生成和运行应用程序。

  5. 单击“单击我”按钮button1_Click 事件处理程序设置托管控件上的 TopLeft 属性。 这会导致托管控件在 WindowsFormsHost 元素中重新定位。 宿主保持相同的屏幕区域,但承载控件被剪裁。 相反,托管控件应始终填充 WindowsFormsHost 元素。

了解 Z 顺序限制

可见 WindowsFormsHost 元素始终绘制在其他 WPF 元素之上,并且不受 z 顺序的影响。 若要查看此 z 顺序行为,请执行以下操作:

  1. 将以下 XAML 复制到 Grid 元素中:

    <!-- 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. F5 生成和运行应用程序。 WindowsFormsHost 元素绘于标签元素上方。

停靠

WindowsFormsHost 元素支持 WPF 停靠。 设置 Dock 附加属性以停靠 DockPanel 元素中的托管控件。

若要停靠托管控件,请执行以下步骤:

  1. 将以下 XAML 复制到 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>
    
  2. F5 生成和运行应用程序。 WindowsFormsHost 元素停靠在 DockPanel 元素的右侧。

设置可见性

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

若要设置托管控件的可见性,请执行以下步骤:

  1. 将以下 XAML 复制到 Grid 元素中:

    <!-- 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. MainWindow.xaml.vbMainWindow.xaml.cs中,将以下代码复制到类定义中:

    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;
    }
    
    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. F5 生成和运行应用程序。

  4. 点击按钮以使按钮不可见,并使WindowsFormsHost元素不可见。

  5. 单击“单击以折叠”按钮使 元素在布局中完全隐藏WindowsFormsHost。 当 Windows 窗体控件折叠时,其周围的元素将重新排列以填补空出的空间。

承载不拉伸的控件

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

若要托管不拉伸的控件,请执行以下步骤:

  1. 将以下 XAML 复制到 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>
    
  2. F5 生成和运行应用程序。 WindowsFormsHost 元素处于网格行正中,但不会拉伸以填充可用空间。 如果窗口足够大,可能会看到托管 MonthCalendar 控件显示两个或更多个月份,但这些月份会在一行中居中显示。 WPF 布局引擎使不能通过调整大小来填充可用空间的元素居中显示。

规模化

与 WPF 元素不同,大多数 Windows 窗体控件不可持续缩放。 若要提供自定义缩放,请重写 WindowsFormsHost.ScaleChild 方法。

若要使用默认行为缩放托管控件,请执行以下步骤:

  1. 将以下 XAML 复制到 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>
    
  2. F5 生成和运行应用程序。 承载控件及其周围元素按 0.5 的比例进行缩放。 但是,承载控件的字体不缩放。

旋转

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

若要查看混合应用程序中轮换的效果,请执行以下步骤:

  1. 将以下 XAML 复制到 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>
    
  2. F5 生成和运行应用程序。 托管控件未旋转,但其周围元素以 180 度的角度旋转。 可能需要调整窗口的大小才能查看元素。

设置填充和边距

WPF 布局中的填充和边距类似于 Windows 窗体中的填充和边距。 只需在 Padding 元素上设置 MarginWindowsFormsHost 属性。

若要为托管控件设置填充和边距,请执行以下步骤:

  1. 将以下 XAML 复制到 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>
    
  2. F5 生成和运行应用程序。 填充和边距设置应用于托管的 Windows 窗体控件的方式与 Windows 窗体中的应用方式相同。

使用动态布局容器

Windows Forms 提供两个动态布局容器,FlowLayoutPanelTableLayoutPanel。 也可以在 WPF 布局中使用这些容器。

若要使用动态布局容器,请执行以下步骤:

  1. 将以下 XAML 复制到 Grid 元素中:

    <!-- Flow layout. -->
    <DockPanel Grid.Row="4" Grid.Column="2">
      <WindowsFormsHost Name="flowLayoutHost" Background="Yellow">
        <wf:FlowLayoutPanel/>
      </WindowsFormsHost>
    </DockPanel>
    
  2. MainWindow.xaml.vbMainWindow.xaml.cs中,将以下代码复制到类定义中:

    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
    
  3. 在构造函数中添加对 InitializeFlowLayoutPanel 方法的调用:

    public MainWindow()
    {
        InitializeComponent();
    
        this.InitializeFlowLayoutPanel();
    }
    
    Public Sub New()
        InitializeComponent()
    
        Me.InitializeFlowLayoutPanel()
    
    End Sub
    
  4. F5 生成和运行应用程序。 WindowsFormsHost 元素填充 DockPanelFlowLayoutPanel 在默认 FlowDirection中排列其子控件。

另请参阅