演练:在 WPF 中排列 Windows 窗体控件
本演练演示如何使用 WPF 布局功能在混合应用程序中排列 Windows 窗体控件。
本演练涉及以下任务:
- 创建项目。
- 使用默认布局设置。
- 根据内容调整大小。
- 使用绝对定位。
- 显式指定大小。
- 设置布局属性。
- 了解 Z 顺序限制。
- 停靠。
- 设置可见性。
- 承载不拉伸的控件。
- 缩放。
- 旋转。
- 设置填充和边距。
- 使用动态布局容器。
有关本演练中介绍的任务的完整代码列表,请参阅有关在 WPF 中排列 Windows 窗体控件的示例。
完成本演练后,可获得对基于 WPF 的应用程序中的 Windows 窗体布局功能的一定了解。
先决条件
若要完成本演练,必须具有 Visual Studio。
创建项目
若要创建和设置项目,请执行以下步骤:
创建名为
WpfLayoutHostingWf
的 WPF 应用程序项目。在解决方案资源管理器中,添加对下列程序集的引用:
- WindowsFormsIntegration
- System.Windows.Forms
- System.Drawing
双击 MainWindow.xaml,在 XAML 视图中将其打开。
在 Window 元素中,添加以下 Windows 窗体命名空间映射。
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
在 Grid 元素中,将 ShowGridLines 属性设置为
true
,并定义五行三列。<Grid ShowGridLines="true"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions>
使用默认布局设置
默认情况下,WindowsFormsHost 元素处理托管的 Windows 窗体控件的布局。
若要使用默认布局设置,请执行以下步骤:
将以下 XAML 复制到 Grid 元素中:
<!-- Default layout. --> <Canvas Grid.Row="0" Grid.Column="0"> <WindowsFormsHost Background="Yellow"> <wf:Button Text="Windows Forms control" FlatStyle="Flat"/> </WindowsFormsHost> </Canvas>
按 F5 生成并运行应用程序。 Windows 窗体 System.Windows.Forms.Button 控件随即出现在 Canvas 中。 托管控件根据其内容调整大小,WindowsFormsHost 元素根据托管控件调整大小。
按内容调整大小
WindowsFormsHost 元素确保按控件内容调整托管控件的大小,以正确显示其内容。
若要按内容调整大小,请执行以下步骤:
将以下 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>
按 F5 生成并运行应用程序。 两个新按钮控件会调整大小以正确显示较长文本字符串和较大字号,WindowsFormsHost 元素会根据托管控件调整大小。
使用绝对定位
可以使用绝对定位将 WindowsFormsHost 元素置于用户界面 (UI) 中的任何位置。
若要使用绝对定位,请执行以下步骤:
将以下 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>
按 F5 生成并运行应用程序。 WindowsFormsHost 元素置于网格单元格中距顶部 20 个像素、距左侧 20 个像素的位置。
显式指定大小
可以使用 Width 和 Height 属性指定 WindowsFormsHost 元素的大小。
若要显式指定大小,请执行以下步骤:
将以下 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>
按 F5 生成并运行应用程序。 WindowsFormsHost 元素的大小设为宽 50 像素、高 70 像素,这比默认布局设置小。 将相应重新排列 Windows 窗体控件的内容。
设置布局属性
应始终使用 WindowsFormsHost 元素的属性在托管控件上设置与布局相关的属性。 直接对承载控件设置布局属性会产生意外结果。
在 XAML 中对托管控件设置与布局相关的属性将不起作用。
若要查看对托管控件设置属性的效果,请执行以下步骤:
将以下 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>
在“解决方案资源管理器”中,双击 MainWindow.xaml.vb 或 MainWindow.xaml.cs 以在代码编辑器中打开它。
将以下代码复制到
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
按 F5 生成并运行应用程序。
单击“单击我”按钮。
button1_Click
事件处理程序设置托管控件的 Top 和 Left 属性。 这会导致在 WindowsFormsHost 元素中重新定位托管控件。 宿主保持相同的屏幕区域,但承载控件被剪裁。 相反,托管控件应始终填充 WindowsFormsHost 元素。
了解 Z 顺序限制
可见的 WindowsFormsHost 元素始终绘制在其他 WPF 元素的顶部,且不受 Z 顺序的影响。 若要查看此 Z 顺序行为,请执行以下操作:
将以下 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>
按 F5 生成并运行应用程序。 WindowsFormsHost 元素绘于标签元素上方。
停靠
WindowsFormsHost 元素支持 WPF 停靠。 设置 Dock 附加属性以停靠 DockPanel 元素中的托管控件。
若要停靠托管控件,请执行以下步骤:
将以下 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>
按 F5 生成并运行应用程序。 WindowsFormsHost 元素停靠在 DockPanel 元素的右侧。
设置可见性
通过在 WindowsFormsHost 元素上设置 Visibility 属性,可以使 Windows 窗体控件不可见或使其折叠。 当控件不可见时,控件不会显示,但会占据布局空间。 当控件处于折叠状态时,控件不会显示,也不会占据布局空间。
若要设置托管控件的可见性,请执行以下步骤:
将以下 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>
在 MainWindow.xaml.vb 或 MainWindow.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
按 F5 生成并运行应用程序。
单击“单击以隐藏”按钮使 WindowsFormsHost 元素不可见。
单击“单击以折叠”按钮使 WindowsFormsHost 元素在布局中完全隐藏。 当 Windows 窗体控件处于折叠状态时,周围的元素会重新排列以占据其空间。
承载不拉伸的控件
一些 Windows 窗体控件具有固定大小,不会拉伸以填充布局中的可用空间。 例如,MonthCalendar 控件在固定的空间中显示月份。
若要托管不拉伸的控件,请执行以下步骤:
将以下 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>
按 F5 生成并运行应用程序。 WindowsFormsHost 元素处于网格行正中,但不会拉伸以填充可用空间。 如果窗口足够大,可能会看到托管 MonthCalendar 控件显示两个或更多个月份,但这些月份会在一行中居中显示。 WPF 布局引擎使不能通过调整大小来填充可用空间的元素居中显示。
扩展
与 WPF 元素不同,大多数 Windows 窗体控件不以连续方式缩放。 若要提供自定义缩放,请重写 WindowsFormsHost.ScaleChild 方法。
若要使用默认行为缩放托管控件,请执行以下步骤:
将以下 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>
按 F5 生成并运行应用程序。 承载控件及其周围元素按 0.5 的比例进行缩放。 但是,承载控件的字体不缩放。
旋转
与 WPF 元素不同,Windows 窗体控件不支持旋转。 应用旋转转换时,WindowsFormsHost 元素不与其他 WPF 元素一起旋转。 180 度以外的任何旋转值都会引发 LayoutError 事件。
若要查看混合应用程序中的旋转效果,请执行以下步骤:
将以下 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>
按 F5 生成并运行应用程序。 承载控件不旋转,但是它周围的元素旋转 180 度。 可能必须调整窗口大小才能看到这些元素。
设置填充和边距
WPF 布局中的填充和边距类似于 Windows 窗体中的填充和边距。 只需在 WindowsFormsHost 元素上设置 Padding 和 Margin 属性即可。
若要为托管控件设置填充和边距,请执行以下步骤:
将以下 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>
按 F5 生成并运行应用程序。 填充和边距设置应用于托管的 Windows 窗体控件的方式与 Windows 窗体中的应用方式相同。
使用动态布局容器
Windows 窗体提供两个动态布局容器,即 FlowLayoutPanel 和 TableLayoutPanel。 还可在 WPF 布局中使用这些容器。
若要使用动态布局容器,请执行以下步骤:
将以下 XAML 复制到 Grid 元素中:
<!-- Flow layout. --> <DockPanel Grid.Row="4" Grid.Column="2"> <WindowsFormsHost Name="flowLayoutHost" Background="Yellow"> <wf:FlowLayoutPanel/> </WindowsFormsHost> </DockPanel>
在 MainWindow.xaml.vb 或 MainWindow.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
将调用添加到构造函数中的
InitializeFlowLayoutPanel
方法:public MainWindow() { InitializeComponent(); this.InitializeFlowLayoutPanel(); }
Public Sub New() InitializeComponent() Me.InitializeFlowLayoutPanel() End Sub
按 F5 生成并运行应用程序。 WindowsFormsHost 元素填充 DockPanel,而 FlowLayoutPanel 按默认的 FlowDirection 排列其子控件。