如何轻松地将 WPF 控件托管到 Windows Form 应用程序中






4.93/5 (29投票s)
本文演示了如何在 Windows Form 应用程序中轻松托管 WPF 控件。
引言
在本文中,我将演示如何创建一个“网格状”组合框,并将其托管在 Windows Form 应用程序中。
背景
与 WPF 相比,WinForms 应用程序的用户界面 (UI) 功能有限。这是否足以将整个应用程序从 WinForms 转换为 WPF?
我认为并非总是如此。有时,您可以使用 WPF 控件轻松地为您的应用程序“整容”。
顺便说一句,如果您想升级您的 Windows Form 应用程序,您应该考虑 HTML5 而不是 WPF。虽然我个人喜欢使用 WPF,但升级到 HTML5 将使您以较低的成本获得一个多平台 Web 应用程序,特别是如果您使用转置工具自动完成它。我做过很多这样的项目,而且肯定比重写成 WPF 更容易。
但是,与此同时,您可以使用“托管” - 将 WPF 控件嵌入到您的 Windows Form 应用程序中,以便利用 Windows Form 应用程序中 WPF 的丰富性(和容易性 - 在经过一些练习之后)。此外,在 WPF 中创建复杂的控件通常比在 Windows Form 中创建它们花费的时间更少。
MSDN 上有一篇文章关于“在 Windows Forms 中托管 WPF 复合控件”,但我认为它太复杂了。
我在这里展示的是一个简单的示例,说明如何以一种易于理解和实现的方式在 Windows Forms 应用程序中托管 WPF 控件,并且从项目架构的角度来看也更合适。
阶段
- 创建 WPF“网格状”组合框
- 创建 Windows Form 托管控件
- 将控件添加到 Windows Form 应用程序
1. 创建 WPF“网格状”组合框
让我们从编写 WPF 控件开始。
我们的目标是一个简单的组合框控件,其中包含“客户”的“网格状”属性
XAML
<UserControl x:Class="WindowsFormsControlLibrary1.ComboBoxWithGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="250">
<Grid>
<ComboBox x:Name="comboBox"
Margin="4"
ItemsSource="{Binding Customers}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label BorderThickness="1,1,0,1"
BorderBrush="Black" Content="{Binding Path=Name}" />
<Label BorderThickness="1,1,0,1"
BorderBrush="Black" Content="{Binding Path=Address}" />
<Label BorderThickness="1"
BorderBrush="Black" Content="{Binding Path=TelephoneNumber}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</UserControl>
正如我们在上面的 XAML 中看到的,我们定义了一个以 customer 作为项目源的组合框。 组合框具有一个项目模板,用于以“网格状”样式呈现客户详细信息
在 WPF 中,使用三个标签并将其上下文绑定到“Customer
”类属性很容易做到。
客户类
public class Customer
{
public string Name { get; set; }
public string Address { get; set; }
public string TelephoneNumber { get; set; }
}
然后,我们剩下要做的就是编写 WPF 控件的代码
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class ComboBoxWithGrid : UserControl
{
public ComboBoxWithGrid()
{
InitializeComponent();
SelectedIndex = 0;
this.DataContext = this;
}
public int SelectedIndex
{
get
{
return comboBox.SelectedIndex;
}
set
{
comboBox.SelectedIndex = value;
}
}
public List<Customer> Customers { get; set; }
}
正如我们所看到的,代码非常简单,将 DataContext
设置为此,公开 Customers
列表以供外部和 XAML 数据绑定,并公开 select
索引仅供外部使用。
2. 创建 Windows Form 托管控件
这一步实际上更容易。 我正在创建一个简单的类,它继承自 System.Windows.Forms.Integration.ElementHost
[Designer("System.Windows.Forms.Design.ControlDesigner, System.Design")]
[DesignerSerializer("System.ComponentModel.Design.Serialization.TypeCodeDomSerializer , System.Design", "System.ComponentModel.Design.Serialization.CodeDomSerializer, System.Design")]
public class ComboBoxWithGrid_WinformsHost : System.Windows.Forms.Integration.ElementHost
{
protected ComboBoxWithGrid m_WPFComboBoxWithGrid = new ComboBoxWithGrid();
public ComboBoxWithGrid_WinformsHost()
{
base.Child = m_WPFComboBoxWithGrid;
}
public int SelectedIndex
{
get
{
return m_WPFComboBoxWithGrid.SelectedIndex;
}
set
{
m_WPFComboBoxWithGrid.SelectedIndex = value;
}
}
public List<Customer> Customers
{
get
{
return m_WPFComboBoxWithGrid.Customers;
}
set
{
m_WPFComboBoxWithGrid.Customers = value;
}
}
}
此类继承自 ElementHost
对象,该对象将 WPF 控件作为子控件。
请注意,我已经覆盖回默认的设计器智能标记和 DesignerSerializer
属性,以防止设计器覆盖 Child
元素。
3. 将控件添加到 Windows Form 应用程序
首先,我们只需要将新控件拖放到我们的 Windows Form 中
然后,通过代码将客户列表连接到控件
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var customers = new List<Customer>();
for (int i = 0; i < 10; i++)
{
customers.Add(new Customer() { Name = "Name" + i,
Address = "Address" + i, TelephoneNumber = "TelephoneNumber" + i });
}
this.comboBoxWithGrid_WinformsHost1.Customers = customers;
this.comboBoxWithGrid_WinformsHost1.SelectedIndex = 6;
}
}