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

更新:2007 年 11 月

Windows Presentation Foundation (WPF) 提供用于创建应用程序的丰富环境。但是,如果您对 Windows 窗体代码的投入较大,那么更有效的办法是在您的 WPF 应用程序中至少重用该代码的一部分,而不是从头开始重新编写应用程序。最常见的情况是您有现有的自定义 Windows 窗体控件。在某些情况下,您可能甚至没有对这些控件的源代码的访问权。WPF 提供了一个在 WPF 应用程序中承载此类控件的简单过程。例如,您可以在承载专用的 System.Windows.Forms.DataGridView 控件时,将 WPF 用于大多数编程。

本演练引导您创建一个在 WPF 页上承载一个复合 Windows 窗体控件的应用程序。该一般过程可以扩展到更复杂的应用程序和控件。

本演练分为两部分。第一部分简要介绍 Windows 窗体控件的实现。第二部分详细讨论如何在 WPF 应用程序中承载该控件、从该控件接收事件以及访问该控件的一些属性。

本演练涉及以下任务:

  • 实现 Windows 窗体控件。

  • 使用 Windows Presentation Foundation 实现宿主应用程序。

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

先决条件

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

  • Visual Studio 2008.

实现 Windows 窗体控件

本示例中使用的 Windows 窗体控件是一个简单的数据输入窗体。该窗体接受用户的名称和地址,然后使用自定义事件将此信息返回到宿主。下图演示呈现的控件。

Windows 窗体控件

简单的 Windows 窗体控件

创建项目

若要开始创建项目,请执行以下操作:

  1. 启动 Microsoft Visual Studio,打开“新建项目”对话框。

  2. 选择“C# 项目”和“Windows 窗体控件库”模板。

  3. 将新项目命名为 MyControls,并单击“确定”以创建此项目。默认项目包含一个名为 UserControl1 的控件。

  4. 将 UserControl1 的名称更改为 MyControl1。

您的项目应当具有对以下系统 DLL 的引用。如果默认情况下未包括其中任何一个 DLL,请将它添加到项目中。

  • System

  • System.Data

  • System.Drawing

  • System.Windows.Forms

  • System.XML

向窗体添加控件

向窗体添加控件:

  • 打开 MyControl1 的设计器。

在窗体中放置六个 System.Windows.Forms.Label 控件及其相应的 System.Windows.Forms.TextBox 控件,大小和排列方式如前面的插图中所示。在此示例中,TextBox 控件命名为:

  • txtName

  • txtAddress

  • txtCity

  • txtState

  • txtZip

添加两个标有“OK”(确定)和“Cancel”(取消)的 System.Windows.Forms.Button 控件。在此示例中,按钮名称分别为 btnOK 和 btnCancel。

实现支持代码

打开窗体的代码视图。控件通过引发自定义 OnButtonClick 事件向其宿主返回所收集的数据。这些数据包含在事件参数对象中。下面的代码示例演示事件和委托声明。将此代码添加到代码文件中由设计器生成的代码之下。

Public Delegate Sub MyControlEventHandler(ByVal sender As Object, ByVal args As MyControlEventArgs)
Public Event OnButtonClick As MyControlEventHandler
public delegate void MyControlEventHandler(object sender, MyControlEventArgs args);
public event MyControlEventHandler OnButtonClick;

MyControlEventArgs 类包含要返回到宿主的信息。向窗体的命名空间添加以下类。

Public Class MyControlEventArgs
    Inherits EventArgs
    Private _Name As String
    Private _StreetAddress As String
    Private _City As String
    Private _State As String
    Private _Zip As String
    Private _IsOK As Boolean


    Public Sub New(ByVal result As Boolean, ByVal name As String, ByVal address As String, ByVal city As String, ByVal state As String, ByVal zip As String) 
        _IsOK = result
        _Name = name
        _StreetAddress = address
        _City = city
        _State = state
        _Zip = zip

    End Sub


    Public Property MyName() As String 
        Get
            Return _Name
        End Get
        Set
            _Name = value
        End Set
    End Property

    Public Property MyStreetAddress() As String 
        Get
            Return _StreetAddress
        End Get
        Set
            _StreetAddress = value
        End Set
    End Property

    Public Property MyCity() As String 
        Get
            Return _City
        End Get
        Set
            _City = value
        End Set
    End Property

    Public Property MyState() As String 
        Get
            Return _State
        End Get
        Set
            _State = value
        End Set
    End Property

    Public Property MyZip() As String 
        Get
            Return _Zip
        End Get
        Set
            _Zip = value
        End Set
    End Property

    Public Property IsOK() As Boolean 
        Get
            Return _IsOK
        End Get
        Set
            _IsOK = value
        End Set
    End Property
End Class
public class MyControlEventArgs : EventArgs
{
    private string _Name;
    private string _StreetAddress;
    private string _City;
    private string _State;
    private string _Zip;
    private bool _IsOK;

    public MyControlEventArgs(bool result,
                                   string name,
                                   string address,
                                   string city,
                                   string state,
                                   string zip)
    {
        _IsOK = result;
        _Name = name;
        _StreetAddress = address;
        _City = city;
        _State = state;
        _Zip = zip;
    }

    public string MyName
    {
        get { return _Name; }
        set { _Name = value; }
    }
    public string MyStreetAddress
    {
        get { return _StreetAddress; }
        set { _StreetAddress = value; }
    }
    public string MyCity
    {
        get { return _City; }
        set { _City = value; }
    }
    public string MyState
    {
        get { return _State; }
        set { _State = value; }
    }
    public string MyZip
    {
        get { return _Zip; }
        set { _Zip = value; }
    }
    public bool IsOK
    {
        get { return _IsOK; }
        set { _IsOK = value; }
    }
}

用户单击“OK”(确定)或“Cancel”(取消)按钮时,Control.Click 事件处理程序创建一个 MyControlEventArgs 对象,该对象包含这些数据并引发 OnButtonClick 事件。两个处理程序的唯一区别在于事件参数的 IsOK 属性。通过该属性,宿主可以确定单击了哪个按钮。对于“OK”(确定)按钮,它设置为 true,对于“Cancel”(取消)按钮,则设置为 false。下面的代码示例演示两个按钮处理程序。将此代码添加到您的类中,放在本节第一个代码示例中演示的事件和委托声明之下。

    Private Sub OKButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnOK.Click

        Dim retvals As New MyControlEventArgs(True, txtName.Text, txtAddress.Text, txtCity.Text, txtState.Text, txtZip.Text)
        RaiseEvent OnButtonClick(Me, retvals)

    End Sub


    Private Sub CancelButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnCancel.Click
        Dim retvals As New MyControlEventArgs(False, txtName.Text, txtAddress.Text, txtCity.Text, txtState.Text, txtZip.Text)
        RaiseEvent OnButtonClick(Me, retvals)

    End Sub
End Class
private void OKButton_Click(object sender, System.EventArgs e)
{

    MyControlEventArgs retvals = new MyControlEventArgs(true,
                                                         txtName.Text,
                                                         txtAddress.Text,
                                                         txtCity.Text,
                                                         txtState.Text,
                                                         txtZip.Text);
    OnButtonClick(this, retvals);
}

private void CancelButton_Click(object sender, System.EventArgs e)
{
    MyControlEventArgs retvals = new MyControlEventArgs(false,
                                                         txtName.Text,
                                                         txtAddress.Text,
                                                         txtCity.Text,
                                                         txtState.Text,
                                                         txtZip.Text);
    OnButtonClick(this, retvals);
}

为程序集赋予强名称并生成该程序集

若要使 WPF 应用程序引用该程序集,该程序集必须具有强名称。若要创建强名称,请使用 Sn.exe 创建一个密钥文件并将其添加到项目的 AssemblyInfo.cs 文件中。

  1. 打开一个 Visual Studio 命令提示窗口。为此,请单击“开始”菜单,然后依次选择“所有程序”/“Microsoft Visual Studio 2008”/“Visual Studio Tools”/“Visual Studio 2008 命令提示”。这将启动一个控制台窗口,该窗口带有自定义的环境变量。

  2. 在命令提示符处,使用“cd”命令转至您的项目文件夹。

  3. 运行以下命令以生成一个名为 MyControls.snk 的密钥文件。

    Sn.exe -k MyControls.snk
    
  4. 若要将密钥文件包括在项目中,请在解决方案资源管理器中右击项目名称,并打开“属性”对话框。选择“签名”选项卡,并输入密钥文件的名称。

  5. 生成该程序集。此生成行为将生成一个名为 MyControls.dll 的 DLL。

使用 Windows Presentation Foundation 实现宿主应用程序

WPF 宿主应用程序使用 WindowsFormsHost 控件来承载 MyControl1。该应用程序处理 OnButtonClick 事件以接收来自控件的数据。它还具有选项按钮集合,可用于从 WPF 页更改控件的一些属性。下图演示已完成的应用程序。

完整的应用程序,显示 Windows Presentation Foundation 页中嵌入的控件

嵌入在 WPF 页中的控件

创建项目

若要开始创建项目,请执行以下操作:

  1. 打开 Visual Studio,并选择“新建项目”。

  2. 选择“WPF 浏览器应用程序”模板。

  3. 将项目命名为 WpfHost,并单击“确定”以打开该项目。

您还将需要添加一个对包含 MyControl1 的 DLL 的引用。以下是添加该引用的最简单的方法。

  1. 在解决方案资源管理器中右击项目名称,并启动“添加引用”对话框。

  2. 单击“浏览”选项卡,并浏览至该 Windows 窗体控件的输出文件夹。对于本示例,该文件夹为 MyControls\bin\Debug。

  3. 选择包含该控件的 DLL,然后单击“确定”将其添加到引用列表中。对于在 Windows Presentation Foundation 中承载 Windows 窗体复合控件的示例,该 DLL 命名为 MyControls.dll。

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

实现基本布局

宿主应用程序的用户界面 (UI) 在 Page1.xaml 中实现。此文件包含定义页面布局并承载 Windows 窗体 控件的可扩展应用程序标记语言 (XAML) 标记。该页分为三个区域:

  • “控件属性”面板,该面板包含可用于修改所承载控件的各个属性的选项按钮集合。

  • “来自控件的数据”[Data from Control]面板,该面板包含若干显示从所承载控件返回的数据的 TextBlock 元素。

  • 所承载的控件自身。

下面的代码示例演示基本布局代码。该示例中省略了承载 MyControl1 所需的标记代码,但后面将对其进行讨论。将 Page1.xaml 中的代码替换为以下代码。

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="Page1"
      xmlns:mcl="clr-namespace:MyControls;assembly=MyControls"
      Loaded="Init">
  <DockPanel>
    <DockPanel.Resources>
      <Style x:Key="inlineText" TargetType="{x:Type Inline}">
        <Setter Property="FontWeight" Value="Normal"/>
      </Style>
      <Style x:Key="titleText" TargetType="{x:Type TextBlock}">
        <Setter Property="DockPanel.Dock" Value="Top"/>
        <Setter Property="FontWeight" Value="Bold"/>
        <Setter Property="Margin" Value="10,5,10,0"/>
      </Style>
    </DockPanel.Resources>

    <StackPanel Orientation="Vertical"
                DockPanel.Dock="Left"
                Background="Bisque"
                Width="250">

      <TextBlock  Margin="10,10,10,10"
                  FontWeight="Bold"
                  FontSize="12">Control Properties</TextBlock>
      <TextBlock Style="{StaticResource titleText}">Background Color</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnOriginalBackColor"
                    IsChecked="True"
                    Click="BackColorChanged">Original</RadioButton>
        <RadioButton Name="rdbtnBackGreen"
                    Click="BackColorChanged">LightGreen</RadioButton>
        <RadioButton Name="rdbtnBackSalmon"
                    Click="BackColorChanged">LightSalmon</RadioButton>
      </StackPanel>

      <TextBlock Style="{StaticResource titleText}">Foreground Color</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnOriginalForeColor"
                    IsChecked="True"
                    Click="ForeColorChanged">Original</RadioButton>
        <RadioButton Name="rdbtnForeRed"
                    Click="ForeColorChanged">Red</RadioButton>
        <RadioButton Name="rdbtnForeYellow"
                    Click="ForeColorChanged">Yellow</RadioButton>
      </StackPanel>

      <TextBlock Style="{StaticResource titleText}">Font Family</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnOriginalFamily"
                     IsChecked="True"
                    Click="FontChanged">Original</RadioButton>
        <RadioButton Name="rdbtnTimes"
                    Click="FontChanged">Times New Roman</RadioButton>
        <RadioButton Name="rdbtnWingdings"
                    Click="FontChanged">Wingdings</RadioButton>
      </StackPanel>

      <TextBlock Style="{StaticResource titleText}">Font Size</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnOriginalSize"
                    IsChecked="True"
                    Click="FontSizeChanged">Original</RadioButton>
        <RadioButton Name="rdbtnTen"
                    Click="FontSizeChanged">10</RadioButton>
        <RadioButton Name="rdbtnTwelve"
                    Click="FontSizeChanged">12</RadioButton>
      </StackPanel>

      <TextBlock Style="{StaticResource titleText}">Font Style</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnNormalStyle"
                     IsChecked="True"
                     Click="StyleChanged">Original</RadioButton>
        <RadioButton Name="rdbtnItalic"
                     Click="StyleChanged">Italic</RadioButton>
      </StackPanel>

      <TextBlock Style="{StaticResource titleText}">Font Weight</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnOriginalWeight"
                     IsChecked="True"
                   Click="WeightChanged">
          Original
        </RadioButton>
        <RadioButton Name="rdbtnBold"
                   Click="WeightChanged">Bold</RadioButton>
      </StackPanel>
    </StackPanel>

    <WindowsFormsHost Name="wfh"
                     DockPanel.Dock="Top"
                     Height="300">
      <mcl:MyControl1 Name="mc"/>
    </WindowsFormsHost>

    <StackPanel Orientation="Vertical"
                Height="Auto"
                Background="LightBlue">
      <TextBlock Margin="10,10,10,10"
            FontWeight="Bold"
            FontSize="12">Data From Control</TextBlock>
      <TextBlock Style="{StaticResource titleText}">
        Name: <Span Name="txtName" Style="{StaticResource inlineText}"/>
      </TextBlock>
      <TextBlock Style="{StaticResource titleText}">
        Street Address: <Span Name="txtAddress" Style="{StaticResource inlineText}"/>
      </TextBlock>
      <TextBlock Style="{StaticResource titleText}">
        City: <Span Name="txtCity" Style="{StaticResource inlineText}"/>
      </TextBlock>
      <TextBlock Style="{StaticResource titleText}">
        State: <Span Name="txtState" Style="{StaticResource inlineText}"/>
      </TextBlock>
      <TextBlock Style="{StaticResource titleText}">
        Zip: <Span Name="txtZip" Style="{StaticResource inlineText}"/>
      </TextBlock>
    </StackPanel>
  </DockPanel>
</Page>
<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="WpfHost.Page1"
      xmlns:mcl="clr-namespace:MyControls;assembly=MyControls"
      Loaded="Init">
  <DockPanel>
    <DockPanel.Resources>
      <Style x:Key="inlineText" TargetType="{x:Type Inline}">
        <Setter Property="FontWeight" Value="Normal"/>
      </Style>
      <Style x:Key="titleText" TargetType="{x:Type TextBlock}">
        <Setter Property="DockPanel.Dock" Value="Top"/>
        <Setter Property="FontWeight" Value="Bold"/>
        <Setter Property="Margin" Value="10,5,10,0"/>
      </Style>
    </DockPanel.Resources>

    <StackPanel Orientation="Vertical"
                DockPanel.Dock="Left"
                Background="Bisque"
                Width="250">

      <TextBlock  Margin="10,10,10,10"
                  FontWeight="Bold"
                  FontSize="12">Control Properties</TextBlock>
      <TextBlock Style="{StaticResource titleText}">Background Color</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnOriginalBackColor"
                    IsChecked="True"
                    Click="BackColorChanged">Original</RadioButton>
        <RadioButton Name="rdbtnBackGreen"
                    Click="BackColorChanged">LightGreen</RadioButton>
        <RadioButton Name="rdbtnBackSalmon"
                    Click="BackColorChanged">LightSalmon</RadioButton>
      </StackPanel>

      <TextBlock Style="{StaticResource titleText}">Foreground Color</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnOriginalForeColor"
                    IsChecked="True"
                    Click="ForeColorChanged">Original</RadioButton>
        <RadioButton Name="rdbtnForeRed"
                    Click="ForeColorChanged">Red</RadioButton>
        <RadioButton Name="rdbtnForeYellow"
                    Click="ForeColorChanged">Yellow</RadioButton>
      </StackPanel>

      <TextBlock Style="{StaticResource titleText}">Font Family</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnOriginalFamily"
                     IsChecked="True"
                    Click="FontChanged">Original</RadioButton>
        <RadioButton Name="rdbtnTimes"
                    Click="FontChanged">Times New Roman</RadioButton>
        <RadioButton Name="rdbtnWingdings"
                    Click="FontChanged">Wingdings</RadioButton>
      </StackPanel>

      <TextBlock Style="{StaticResource titleText}">Font Size</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnOriginalSize"
                    IsChecked="True"
                    Click="FontSizeChanged">Original</RadioButton>
        <RadioButton Name="rdbtnTen"
                    Click="FontSizeChanged">10</RadioButton>
        <RadioButton Name="rdbtnTwelve"
                    Click="FontSizeChanged">12</RadioButton>
      </StackPanel>

      <TextBlock Style="{StaticResource titleText}">Font Style</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnNormalStyle"
                     IsChecked="True"
                     Click="StyleChanged">Original</RadioButton>
        <RadioButton Name="rdbtnItalic"
                     Click="StyleChanged">Italic</RadioButton>
      </StackPanel>

      <TextBlock Style="{StaticResource titleText}">Font Weight</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnOriginalWeight"
                     IsChecked="True"
                   Click="WeightChanged">
          Original
        </RadioButton>
        <RadioButton Name="rdbtnBold"
                   Click="WeightChanged">Bold</RadioButton>
      </StackPanel>
    </StackPanel>

    <WindowsFormsHost Name="wfh"
                     DockPanel.Dock="Top"
                     Height="300">
      <mcl:MyControl1 Name="mc"/>
    </WindowsFormsHost>

    <StackPanel Orientation="Vertical"
                Height="Auto"
                Background="LightBlue">
      <TextBlock Margin="10,10,10,10"
            FontWeight="Bold"
            FontSize="12">Data From Control</TextBlock>
      <TextBlock Style="{StaticResource titleText}">
        Name: <Span Name="txtName" Style="{StaticResource inlineText}"/>
      </TextBlock>
      <TextBlock Style="{StaticResource titleText}">
        Street Address: <Span Name="txtAddress" Style="{StaticResource inlineText}"/>
      </TextBlock>
      <TextBlock Style="{StaticResource titleText}">
        City: <Span Name="txtCity" Style="{StaticResource inlineText}"/>
      </TextBlock>
      <TextBlock Style="{StaticResource titleText}">
        State: <Span Name="txtState" Style="{StaticResource inlineText}"/>
      </TextBlock>
      <TextBlock Style="{StaticResource titleText}">
        Zip: <Span Name="txtZip" Style="{StaticResource inlineText}"/>
      </TextBlock>
    </StackPanel>
  </DockPanel>
</Page>

第一个 StackPanel 元素包含若干 RadioButton 控件集,使用这些控件可以修改所承载控件的各个默认属性。该元素之后是 WindowsFormsHost 元素,此元素承载 MyControl1。最后的 StackPanel 元素包含若干显示从所承载控件返回的数据的 TextBlock 元素。这些元素的排序以及 DockHeight 属性设置无间隙并且不失真地将所承载的控件嵌入到页面中。

承载控件

下面是上一个代码示例的已编辑版本,重点说明承载 MyControl1 所需的元素。

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="Page1"
      xmlns:mcl="clr-namespace:MyControls;assembly=MyControls"
      Loaded="Init">


...


<WindowsFormsHost Name="wfh"
                 DockPanel.Dock="Top"
                 Height="300">
  <mcl:MyControl1 Name="mc"/>
</WindowsFormsHost>
<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="WpfHost.Page1"
      xmlns:mcl="clr-namespace:MyControls;assembly=MyControls"
      Loaded="Init">


...


<WindowsFormsHost Name="wfh"
                 DockPanel.Dock="Top"
                 Height="300">
  <mcl:MyControl1 Name="mc"/>
</WindowsFormsHost>

xmlns 命名空间映射属性创建一个对包含所承载控件的 MyControls 命名空间的引用。通过该映射,可以在 XAML 中将 MyControl1 表示为 <mcl:MyControl1>。

此代码示例中的以下两个元素处理承载:

  • WindowsFormsHost 表示 WindowsFormsHost 元素,通过该元素可以在 WPF 页面上承载 Windows 窗体控件。

  • mcl:MyControl1,表示 MyControl1,它被添加到 WindowsFormsHost 元素的子集合。因此,该 Windows 窗体控件呈现为 WPF 页的一部分,并且您可以从该页与此控件通信。

实现代码隐藏文件

代码隐藏文件 Page1.xaml.cs 包含用于实现上一节中所述的 UI 功能的程序代码。主要任务是:

  • 将一个事件处理程序附加到 MyControl1 的 OnButtonClick 事件。

  • 基于选项按钮集合的设置方式修改 MyControl1 的各个属性。

  • 显示由控件收集的数据。

初始化应用程序

初始化代码包含在页面的 Loaded 事件的事件处理程序中,并将该事件处理程序附加到控件的 OnButtonClick 事件。将以下代码复制到 Page1.xaml.cs 的 Page1 类中。

Class Page1
    Inherits Page

    Private app As Application
    Private myWindow As NavigationWindow
    Private initFontWeight As FontWeight
    Private initFontSize As [Double]
    Private initFontStyle As FontStyle
    Private initBackBrush As SolidColorBrush
    Private initForeBrush As SolidColorBrush
    Private initFontFamily As FontFamily
    Private UIIsReady As Boolean = False


    Private Sub Init(ByVal sender As Object, ByVal e As RoutedEventArgs)
        app = System.Windows.Application.Current
        myWindow = CType(app.MainWindow, NavigationWindow)
        myWindow.SizeToContent = SizeToContent.WidthAndHeight
        wfh.TabIndex = 10
        initFontSize = wfh.FontSize
        initFontWeight = wfh.FontWeight
        initFontFamily = wfh.FontFamily
        initFontStyle = wfh.FontStyle
        initBackBrush = CType(wfh.Background, SolidColorBrush)
        initForeBrush = CType(wfh.Foreground, SolidColorBrush)

        Dim mc As MyControl1 = wfh.Child

        AddHandler mc.OnButtonClick, AddressOf Pane1_OnButtonClick 
        UIIsReady = True

    End Sub
public partial class Page1 : Page
{
    private Application app;
    private NavigationWindow myWindow;
    FontWeight initFontWeight;
    Double initFontSize;
    FontStyle initFontStyle;
    SolidColorBrush initBackBrush;
    SolidColorBrush initForeBrush;
    FontFamily initFontFamily;
    bool UIIsReady = false;

    private void Init(object sender, EventArgs e)
    {
        app = System.Windows.Application.Current;
        myWindow = (NavigationWindow)app.MainWindow;
        myWindow.SizeToContent = SizeToContent.WidthAndHeight;
        wfh.TabIndex = 10;
        initFontSize = wfh.FontSize;
        initFontWeight = wfh.FontWeight;
        initFontFamily = wfh.FontFamily;
        initFontStyle = wfh.FontStyle;
        initBackBrush = (SolidColorBrush)wfh.Background;
        initForeBrush = (SolidColorBrush)wfh.Foreground;
        (wfh.Child as MyControl1).OnButtonClick += new MyControl1.MyControlEventHandler(Pane1_OnButtonClick);
        UIIsReady = true;
    }

由于已将前面讨论的 XAML 代码 MyControl1 添加到 WindowsFormsHost 元素的子元素集合中,因此您可以强制转换 WindowsFormsHost 元素的 Child,以获取对 MyControl1 的引用。然后,可以使用该引用将事件处理程序附加到 OnButtonClick。

除了提供对控件自身的引用之外,WindowsFormsHost 还公开控件的许多属性,您可以从该页操作这些属性。初始化代码将这些值分配给私有全局变量,以便以后在应用程序中使用。

处理 OnButtonClick 事件

当用户单击控件的任何一个按钮时,MyControl1 将引发 OnButtonClick 事件。将下面的代码添加到 Page1 类中。

    'Handle button clicks on the Windows Form control
    Private Sub Pane1_OnButtonClick(ByVal sender As Object, ByVal args As MyControlEventArgs) 
        txtName.Inlines.Clear()
        txtAddress.Inlines.Clear()
        txtCity.Inlines.Clear()
        txtState.Inlines.Clear()
        txtZip.Inlines.Clear()

        If args.IsOK Then
            txtName.Inlines.Add(" " + args.MyName)
            txtAddress.Inlines.Add(" " + args.MyStreetAddress)
            txtCity.Inlines.Add(" " + args.MyCity)
            txtState.Inlines.Add(" " + args.MyState)
            txtZip.Inlines.Add(" " + args.MyZip)
        End If

    End Sub
End Class
//Handle button clicks on the Windows Form control
private void Pane1_OnButtonClick(object sender, MyControlEventArgs args)
{
    txtName.Inlines.Clear();
    txtAddress.Inlines.Clear();
    txtCity.Inlines.Clear();
    txtState.Inlines.Clear();
    txtZip.Inlines.Clear();

    if (args.IsOK)
    {
        txtName.Inlines.Add( " " + args.MyName );
        txtAddress.Inlines.Add( " " + args.MyStreetAddress );
        txtCity.Inlines.Add( " " + args.MyCity );
        txtState.Inlines.Add( " " + args.MyState );
        txtZip.Inlines.Add( " " + args.MyZip );
    }
}

文本框中的数据将被打包到 MyControlEventArgs 对象中。如果用户单击“OK”(确定)按钮,事件处理程序将提取数据,并在 MyControl1 下面的面板中显示这些数据。

修改控件的属性

WindowsFormsHost 元素公开所承载控件的若干默认属性。因此,您可以更改控件的外观,以便与页面的样式更加匹配。使用左侧面板中的选项按钮集合,可以修改若干颜色和字体属性。每个按钮集合都有用于 Click 事件的处理程序,该处理程序将检测用户的选项按钮选择,并更改控件上的相应属性。将下面的代码复制到 Page1 类中。现在可以编译并运行应用程序。

Private Sub BackColorChanged(ByVal sender As Object, ByVal e As RoutedEventArgs)

    If sender.Equals(rdbtnBackGreen) Then
        wfh.Background = New SolidColorBrush(Colors.LightGreen)
    ElseIf sender.Equals(rdbtnBackSalmon) Then
        wfh.Background = New SolidColorBrush(Colors.LightSalmon)
    ElseIf UIIsReady = True Then
        wfh.Background = initBackBrush
    End If

End Sub

Private Sub ForeColorChanged(ByVal sender As Object, ByVal e As RoutedEventArgs) 
    If sender.Equals(rdbtnForeRed) Then
        wfh.Foreground = New SolidColorBrush(Colors.Red)
    ElseIf sender.Equals(rdbtnForeYellow) Then
        wfh.Foreground = New SolidColorBrush(Colors.Yellow)
    ElseIf UIIsReady = True Then
        wfh.Foreground = initForeBrush
    End If

End Sub

Private Sub FontChanged(ByVal sender As Object, ByVal e As RoutedEventArgs) 
    If sender.Equals(rdbtnTimes) Then
        wfh.FontFamily = New FontFamily("Times New Roman")
    ElseIf sender.Equals(rdbtnWingdings) Then
        wfh.FontFamily = New FontFamily("Wingdings")
    ElseIf UIIsReady = True Then
        wfh.FontFamily = initFontFamily
    End If

End Sub

Private Sub FontSizeChanged(ByVal sender As Object, ByVal e As RoutedEventArgs) 
    If sender.Equals(rdbtnTen) Then
        wfh.FontSize = 10
    ElseIf sender.Equals(rdbtnTwelve) Then
        wfh.FontSize = 12
    ElseIf UIIsReady = True Then
        wfh.FontSize = initFontSize
    End If

End Sub

Private Sub StyleChanged(ByVal sender As Object, ByVal e As RoutedEventArgs) 
    If sender.Equals(rdbtnItalic) Then
        wfh.FontStyle = FontStyles.Italic
    ElseIf UIIsReady = True Then
        wfh.FontStyle = initFontStyle
    End If

End Sub

Private Sub WeightChanged(ByVal sender As Object, ByVal e As RoutedEventArgs) 
    If sender.Equals(rdbtnBold) Then
        wfh.FontWeight = FontWeights.Bold
    ElseIf UIIsReady = True Then
        wfh.FontWeight = initFontWeight
    End If

End Sub
private void BackColorChanged(object sender, RoutedEventArgs e)
{
    if (sender == rdbtnBackGreen)
        wfh.Background = new SolidColorBrush(Colors.LightGreen);
    else if (sender == rdbtnBackSalmon)
        wfh.Background = new SolidColorBrush(Colors.LightSalmon);
    else if (UIIsReady == true)
        wfh.Background = initBackBrush;
}

private void ForeColorChanged(object sender, RoutedEventArgs e)
{
    if (sender == rdbtnForeRed)
        wfh.Foreground = new SolidColorBrush(Colors.Red);
    else if (sender == rdbtnForeYellow)
        wfh.Foreground = new SolidColorBrush(Colors.Yellow);
    else if (UIIsReady == true)
        wfh.Foreground = initForeBrush;
}

private void FontChanged(object sender, RoutedEventArgs e)
{
    if (sender == rdbtnTimes)
        wfh.FontFamily = new FontFamily("Times New Roman");
    else if (sender == rdbtnWingdings)
        wfh.FontFamily = new FontFamily("Wingdings");
    else if (UIIsReady == true)
        wfh.FontFamily = initFontFamily;
}
private void FontSizeChanged(object sender, RoutedEventArgs e)
{
    if (sender == rdbtnTen)
        wfh.FontSize = 10;
    else if (sender == rdbtnTwelve)
        wfh.FontSize = 12;
    else if (UIIsReady == true)
        wfh.FontSize = initFontSize;
}
private void StyleChanged(object sender, RoutedEventArgs e)
{
    if (sender == rdbtnItalic)
        wfh.FontStyle = FontStyles.Italic;
    else if (UIIsReady == true)
        wfh.FontStyle = initFontStyle;
}
private void WeightChanged(object sender, RoutedEventArgs e)
{
    if (sender == rdbtnBold)
        wfh.FontWeight = FontWeights.Bold;
    else if (UIIsReady == true)
        wfh.FontWeight = initFontWeight;
}

请参见

任务

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

概念

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

参考

ElementHost

WindowsFormsHost

其他资源

WPF 设计器