Exemplarische Vorgehensweise: Hosten eines zusammengesetzten WPF-Steuerelements in Windows Forms

Windows Presentation Foundation (WPF) bietet eine umfangreiche Umgebung zum Erstellen von Anwendungen. Wenn Sie allerdings bereits erheblichen Aufwand in Windows Forms-Code investiert haben, kann es effektiver sein, Ihre Windows Forms-Anwendung um WPF zu erweitern, anstatt sie vollständig neu zu schreiben. Ein häufiges Szenario ist, wenn Sie ein oder mehrere mit WPF implementierte Steuerelemente in Ihre Windows Forms-Anwendung einbetten möchten. Weitere Informationen zum Anpassen von WPF-Steuerelementen finden Sie unter Anpassung von Steuerelementen.

Diese exemplarische Vorgehensweise führt Sie durch eine Anwendung, die ein zusammengesetztes WPF-Steuerelement zur Dateneingabe in einer Windows Forms-Anwendung hostet. Das zusammengesetzte Steuerelement ist in eine DLL verpackt. Dieses allgemeine Verfahren kann für komplexere Anwendungen und Steuerelemente erweitert werden. Diese exemplarische Vorgehensweise wurde so gestaltet, dass sie in Darstellung und Funktionalität nahezu identisch mit Exemplarische Vorgehensweise: Hosten eines zusammengesetzten Windows Forms-Steuerelements in WPF ist. Der Hauptunterschied besteht darin, dass das Hosting-Szenario umgekehrt ist.

Diese exemplarische Vorgehensweise ist in zwei Abschnitte unterteilt. Im ersten Abschnitt wird die Implementierung des zusammengesetzten WPF-Steuerelements kurz beschrieben. Im zweiten Abschnitt wird detailliert erläutert, wie Sie das zusammengesetzte Steuerelement in einer Windows Forms-Anwendung hosten, Ereignisse vom Steuerelement empfangen und auf einige Eigenschaften des Steuerelements zugreifen können.

In dieser exemplarischen Vorgehensweise werden u. a. folgende Aufgaben veranschaulicht:

  • Implementieren des zusammengesetzten WPF-Steuerelements

  • Implementieren der Windows Forms-Hostanwendung

Eine vollständige Codeauflistung der Aufgaben in dieser exemplarischen Vorgehensweise finden Sie unter Beispiel zum Hosten eines zusammengesetzten WPF-Steuerelements in Windows Forms.

Voraussetzungen

Für diese exemplarische Vorgehensweise benötigen Sie Visual Studio.

Implementieren des zusammengesetzten WPF-Steuerelements

Das in diesem Beispiel verwendete zusammengesetzte WPF-Steuerelement ist ein einfaches Dateneingabeformular, das den Namen und die Adresse des Benutzers erfasst. Klickt der Benutzer eine der zwei Schaltflächen, um anzugeben, dass die Aufgabe abgeschlossen ist, löst das Steuerelement ein benutzerdefiniertes Ereignis aus, um diese Informationen an den Host zurückzugeben. Die folgende Abbildung zeigt das gerenderte Steuerelement.

Die folgende Abbildung zeigt ein zusammengesetztes WPF-Steuerelement:

Screenshot that shows a simple WPF control.

Erstellen des Projekts

Um das Projekt zu starten:

  1. Starten Sie Visual Studio, und öffnen Sie das Dialogfeld Neues Projekt.

  2. Wählen Sie in Visual C# in der Kategorie „Windows” die Vorlage WPF-Benutzersteuerelementbibliothek aus.

  3. Geben Sie dem neuen Projekt den Namen MyControls.

  4. Geben Sie als Speicherort einen entsprechend benannten Ordner der obersten Ebene an, z. B. WindowsFormsHostingWpfControl. Sie werden die Host-Anwendung später in diesem Ordner ablegen.

  5. Klicken Sie auf OK, um das Projekt zu erstellen. Das Standardprojekt enthält ein einzelnes Steuerelement namens UserControl1.

  6. Benennen Sie im Projektmappen-Explorer UserControl1 in MyControl1 um.

Das Projekt sollte Verweise auf die folgenden System-DLLs aufweisen. Sollten eine oder mehrere dieser DLLs nicht standardmäßig enthalten sein, fügen Sie diese manuell zum Projekt hinzu.

  • PresentationCore

  • PresentationFramework

  • System

  • WindowsBase

Erstellen der Benutzeroberfläche

Die Benutzeroberfläche für das zusammengesetzte Steuerelement wird mit XAML (Extensible Application Markup Language) implementiert. Die Benutzeroberfläche des zusammengesetzten Steuerelements besteht aus fünf TextBox-Elementen. Jedem TextBox-Element ist ein TextBlock-Element zugeordnet, das als Bezeichnung dient. Unten gibt es zwei Button-Elemente, OK und Abbrechen. Wenn der Benutzer auf eine Schaltfläche klickt, löst das Steuerelement ein benutzerdefiniertes Ereignis aus, um die Informationen an den Host zurückzugeben.

Grundlegendes Layout

Die verschiedenen Elemente der Benutzeroberfläche sind in einem Grid-Element (Raster-Element) enthalten. Sie können mithilfe von Table die Inhalte des zusammengesetzten Steuerelements anordnen – ganz ähnlich, wie sie dafür ein Grid-Element in HTML verwenden würden. WPF enthält außerdem ein Table-Element, aber Grid ist einfacher und für einfache Layoutaufgaben besser geeignet.

Das grundlegende Layout ist im nachfolgenden XAML-Code beschrieben. Dieser XAML-Code definiert die allgemeine Struktur des Steuerelements durch Angabe der Anzahl von Spalten und Zeilen im Grid-Element.

Ersetzen Sie in MyControl1.xaml den vorhandenen XAML-Code durch den folgenden.

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="MyControls.MyControl1"
      Background="#DCDCDC"
      Width="375"
      Height="250"
      Name="rootElement"
      Loaded="Init">

  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="Auto"/>
    <ColumnDefinition Width="Auto"/>
  </Grid.ColumnDefinitions>

  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
</Grid>

TextBlock- und TextBox-Elemente zum Raster hinzufügen

Sie platzieren ein Benutzeroberflächenelement im Raster, indem Sie die Attribute RowProperty und ColumnProperty des Elements auf die geeignete Zeilen- und Spaltennummer festlegen. Denken Sie daran, dass die Nummerierungen der Zeilen und Spalten nullbasiert sind. Sie können dafür sorgen, dass sich ein Element über mehrere Spalten erstreckt, indem Sie dessen Attribut ColumnSpanProperty festlegen. Weitere Informationen zu Grid-Elementen finden Sie unter Erstellen eines Grid-Elements.

Der folgende XAML-Code zeigt die TextBox- und TextBlock-Elemente des zusammengesetzten Steuerelements mit deren Attributen RowProperty und ColumnProperty, die so festgelegt sind, dass die Elemente im Raster richtig platziert werden.

Fügen Sie in „MyControl1.xaml“ im Grid-Element den folgenden XAML-Code hinzu.

  <TextBlock Grid.Column="0"
        Grid.Row="0" 
        Grid.ColumnSpan="4"
        Margin="10,5,10,0"
        HorizontalAlignment="Center"
        Style="{StaticResource titleText}">Simple WPF Control</TextBlock>

  <TextBlock Grid.Column="0"
        Grid.Row="1"
        Style="{StaticResource inlineText}"
        Name="nameLabel">Name</TextBlock>
  <TextBox Grid.Column="1"
        Grid.Row="1"
        Grid.ColumnSpan="3"
        Name="txtName"/>

  <TextBlock Grid.Column="0"
        Grid.Row="2"
        Style="{StaticResource inlineText}"
        Name="addressLabel">Street Address</TextBlock>
  <TextBox Grid.Column="1"
        Grid.Row="2"
        Grid.ColumnSpan="3"
        Name="txtAddress"/>

  <TextBlock Grid.Column="0"
        Grid.Row="3"
        Style="{StaticResource inlineText}"
        Name="cityLabel">City</TextBlock>
  <TextBox Grid.Column="1"
        Grid.Row="3"
        Width="100"
        Name="txtCity"/>

  <TextBlock Grid.Column="2"
        Grid.Row="3"
        Style="{StaticResource inlineText}"
        Name="stateLabel">State</TextBlock>
  <TextBox Grid.Column="3"
        Grid.Row="3"
        Width="50"
        Name="txtState"/>

  <TextBlock Grid.Column="0"
        Grid.Row="4"
        Style="{StaticResource inlineText}"
        Name="zipLabel">Zip</TextBlock>
  <TextBox Grid.Column="1"
        Grid.Row="4"
        Width="100"
        Name="txtZip"/>

Formatieren der Benutzeroberflächenelemente

Viele der Elemente auf dem Dateneingabeformular verfügen über ein ähnliches Erscheinungsbild, was bedeutet, dass viele ihrer Eigenschaften identische Einstellungen aufweisen. Statt die Attribute jedes Elements separat festzulegen, verwendet der vorstehende XAML-Code Style-Elemente zum Definieren von Standardeigenschaftseinstellungen für Elementklassen. Dieser Ansatz reduziert die Komplexität des Steuerelements und ermöglicht es Ihnen, die Darstellung mehrerer Elemente durch ein einziges Stilattribut zu ändern.

Die Style-Elemente sind in der Eigenschaft Grid des Elements Resources enthalten, damit sie von allen Elementen im Steuerelement verwendet werden können. Wenn ein Stil benannt ist, wenden Sie ihn auf ein Element an, indem Sie ein Style-Element hinzufügen, das als Wert den Stilnamen hat. Unbenannte Stile werden zum Standardstil für das Element. Weitere Informationen zu Stilen finden Sie unter Erstellen von Formaten und Vorlagen.

Der folgende XAML-Code zeigt die Style-Elemente für das zusammengesetzte Steuerelement. Wie die Stile auf Elemente angewendet werden, können Sie dem vorherigen XAML-Code entnehmen. Beispielsweise hat das letzte TextBlock-Element den Stil inlineText, und das letzte TextBox-Element verwendet den Standardstil.

Fügen Sie in „MyControl1.xaml“ den folgenden XAML-Code direkt hinter dem Grid-Startelement hinzu.

<Grid.Resources>
  <Style x:Key="inlineText" TargetType="{x:Type TextBlock}">
    <Setter Property="Margin" Value="10,5,10,0"/>
    <Setter Property="FontWeight" Value="Normal"/>
    <Setter Property="FontSize" Value="12"/>
  </Style>
  <Style x:Key="titleText" TargetType="{x:Type TextBlock}">
    <Setter Property="DockPanel.Dock" Value="Top"/>
    <Setter Property="FontWeight" Value="Bold"/>
    <Setter Property="FontSize" Value="14"/>
    <Setter Property="Margin" Value="10,5,10,0"/>
  </Style>
  <Style TargetType="{x:Type Button}">
    <Setter Property="Margin" Value="10,5,10,0"/>
    <Setter Property="Width" Value="60"/>
  </Style>
  <Style TargetType="{x:Type TextBox}">
    <Setter Property="Margin" Value="10,5,10,0"/>
  </Style>
</Grid.Resources>

Hinzufügen der Schaltflächen „OK” und „Abbrechen”

Die letzten Elemente des zusammengesetzten Steuerelements sind die Elemente OK und AbbrechenButton, die nur die ersten beiden Spalten der letzten Zeile von Grid belegen. Diese Elemente verwenden einen allgemeinen Ereignishandler, ButtonClicked, und den im vorhergehenden XAML-Code definierten Button-Standardstil.

Fügen Sie in „MyControl1.xaml“ den folgenden XAML-Code hinter dem letzten TextBox-Element hinzu. Der XAML-Teil des zusammengesetzten Steuerelements ist jetzt vollständig.

<Button Grid.Row="5"
        Grid.Column="0"
        Name="btnOK"
        Click="ButtonClicked">OK</Button>
<Button Grid.Row="5"
        Grid.Column="1"
        Name="btnCancel"
        Click="ButtonClicked">Cancel</Button>

Implementieren der CodeBehind-Datei

Die CodeBehind-Datei „MyControl1.xaml.cs” implementiert drei wichtige Aufgaben:

  1. Sie behandelt das Ereignis, das auftritt, wenn der Benutzer eine der Schaltflächen klickt.

  2. Sie ruft die Daten aus den TextBox-Elementen ab und verpackt sie in einem benutzerdefinierten Ereignisargumentobjekt.

  3. Sie löst das benutzerdefinierte OnButtonClick-Ereignis aus, das den Host darüber benachrichtigt, dass der Benutzer die Eingabe abgeschlossen hat, und übergibt die Daten zurück an den Host.

Das Steuerelement macht auch eine Reihe von Farb- und Schriftart-Eigenschaften verfügbar, mit deren Hilfe Sie das Erscheinungsbild anpassen können. Im Gegensatz zur Klasse WindowsFormsHost, die zum Hosten eines Windows Forms-Steuerelements verwendet wird, macht die Klasse ElementHost nur die Eigenschaft Background des Steuerelements verfügbar. Um die Ähnlichkeit zwischen diesem Codebeispiel und dem Beispiel aus Exemplarische Vorgehensweise: Hosten eines zusammengesetzten Windows Forms-Steuerelements in WPF beizubehalten, macht das Steuerelement die verbleibenden Eigenschaften direkt verfügbar.

Die grundlegende Struktur der CodeBehind-Datei

Die CodeBehind-Datei besteht aus einem einzigen Namespace, MyControls, der zwei Klassen, MyControl1 und MyControlEventArgs, enthält.

namespace MyControls  
{  
  public partial class MyControl1 : Grid  
  {  
    //...  
  }  
  public class MyControlEventArgs : EventArgs  
  {  
    //...  
  }  
}  

Die erste Klasse, MyControl1, ist eine partielle Klasse mit dem Code, der die Funktionalität der in „MyControl1.xaml“ definierten Benutzeroberfläche implementiert. Wenn „MyControl1.xaml“ analysiert wird, wird der XAML-Code in die gleiche partielle Klasse konvertiert, und die beiden partiellen Klassen werden zusammengeführt, um das kompilierte Steuerelement zu bilden. Aus diesem Grund muss der Klassenname in der CodeBehind-Datei mit dem übereinstimmen, der MyControl1.xaml zugewiesen wurde, und er muss vom Stammelement des Steuerelements erben. Die zweite Klasse, MyControlEventArgs, ist eine Klasse für Ereignisargumente, mit der die Daten zurück an den Host gesendet werden.

Öffnen Sie "MyControl1.xaml.cs". Ändern Sie die vorhandene Klassendeklaration so, dass sie den folgenden Namen hat und von Grid erbt.

public partial class MyControl1 : Grid

Initialisieren des Steuerelements

Im folgenden Code werden mehrere grundlegende Aufgaben implementiert:

  • Deklarieren eines privaten Ereignisses, OnButtonClick, und seines zugeordneten Delegaten MyControlEventHandler.

  • Erstellen von mehreren privaten globalen Variablen, welche die Benutzerdaten speichern. Diese Daten werden durch entsprechende Eigenschaften verfügbar gemacht.

  • Implementieren eines Handlers, Init, für das Loaded-Ereignis des Steuerelements. Dieser Handler initialisiert die globalen Variablen, indem er ihnen die in MyControl1.xaml definierten Werte zuweist. Zu diesem Zweck verwendet er den Name, der einem typischen TextBlock-Element (nameLabel) zugewiesen wurde, um auf die Standardeigenschaftseinstellungen dieses Elements zuzugreifen.

Löschen Sie den vorhandenen Konstruktor, und fügen Sie Ihrer Klasse MyControl1 den folgenden Code hinzu.

public delegate void MyControlEventHandler(object sender, MyControlEventArgs args);
public event MyControlEventHandler OnButtonClick;
private FontWeight _fontWeight;
private double _fontSize;
private FontFamily _fontFamily;
private FontStyle _fontStyle;
private SolidColorBrush _foreground;
private SolidColorBrush _background;

private void Init(object sender, EventArgs e)
{
    //They all have the same style, so use nameLabel to set initial values.
    _fontWeight = nameLabel.FontWeight;
    _fontSize = nameLabel.FontSize;
    _fontFamily = nameLabel.FontFamily;
    _fontStyle = nameLabel.FontStyle;
    _foreground = (SolidColorBrush)nameLabel.Foreground;
    _background = (SolidColorBrush)rootElement.Background;
}

Behandeln der Click-Ereignisse der Schaltflächen

Der Benutzer gibt an, dass die Dateneingabe abgeschlossen ist, indem er entweder auf die Schaltfläche OK oder die Schaltfläche Abbrechen klickt. Beide Schaltflächen verwenden denselben Click-Ereignishandler, ButtonClicked. Beide Schaltflächen haben einen Namen, btnOK oder btnCancel, der es dem Handler ermöglicht, durch Untersuchen des Argumentwerts sender zu ermitteln, auf welche Schaltfläche geklickt wurde. Der Handler führt die folgenden Aktionen aus:

  • Er erstellt ein MyControlEventArgs-Objekt, das die Daten aus den TextBox-Elementen enthält.

  • Wenn der Benutzer auf die Schaltfläche Abbrechen geklickt hat, legt der Handler die Eigenschaft IsOK des Objekts MyControlEventArgs auf false fest.

  • Er löst das OnButtonClick-Ereignis aus, um dem Host anzuzeigen, dass der Benutzer die Dateneingabe abgeschlossen hat, und übergibt die gesammelten Daten zurück.

Fügen Sie Ihrer Klasse MyControl1 den folgenden Code nach der Init-Methode hinzu.

private void ButtonClicked(object sender, RoutedEventArgs e)
{
    MyControlEventArgs retvals = new MyControlEventArgs(true,
                                                        txtName.Text,
                                                        txtAddress.Text,
                                                        txtCity.Text,
                                                        txtState.Text,
                                                        txtZip.Text);
    if (sender == btnCancel)
    {
        retvals.IsOK = false;
    }
    if (OnButtonClick != null)
        OnButtonClick(this, retvals);
}

Erstellen von Eigenschaften

Der Rest der Klasse macht lediglich Eigenschaften verfügbar, die den oben erläuterten globalen Variablen entsprechen. Wenn sich eine Eigenschaft ändert, passt der Set-Accessor das Erscheinungsbild des Steuerelements an, indem er die entsprechenden Elementeigenschaften und die zugrunde liegenden globalen Variablen aktualisiert.

Fügen Sie Ihrer Klasse MyControl1 den folgenden Code hinzu.

public FontWeight MyControl_FontWeight
{
    get { return _fontWeight; }
    set
    {
        _fontWeight = value;
        nameLabel.FontWeight = value;
        addressLabel.FontWeight = value;
        cityLabel.FontWeight = value;
        stateLabel.FontWeight = value;
        zipLabel.FontWeight = value;
    }
}
public double MyControl_FontSize
{
    get { return _fontSize; }
    set
    {
        _fontSize = value;
        nameLabel.FontSize = value;
        addressLabel.FontSize = value;
        cityLabel.FontSize = value;
        stateLabel.FontSize = value;
        zipLabel.FontSize = value;
    }
}
public FontStyle MyControl_FontStyle
{
    get { return _fontStyle; }
    set
    {
        _fontStyle = value;
        nameLabel.FontStyle = value;
        addressLabel.FontStyle = value;
        cityLabel.FontStyle = value;
        stateLabel.FontStyle = value;
        zipLabel.FontStyle = value;
    }
}
public FontFamily MyControl_FontFamily
{
    get { return _fontFamily; }
    set
    {
        _fontFamily = value;
        nameLabel.FontFamily = value;
        addressLabel.FontFamily = value;
        cityLabel.FontFamily = value;
        stateLabel.FontFamily = value;
        zipLabel.FontFamily = value;
    }
}

public SolidColorBrush MyControl_Background
{
    get { return _background; }
    set
    {
        _background = value;
        rootElement.Background = value;
    }
}
public SolidColorBrush MyControl_Foreground
{
    get { return _foreground; }
    set
    {
        _foreground = value;
        nameLabel.Foreground = value;
        addressLabel.Foreground = value;
        cityLabel.Foreground = value;
        stateLabel.Foreground = value;
        zipLabel.Foreground = value;
    }
}

Zurücksenden der Daten an den Host

Die letzte Komponente in der Datei ist die Klasse MyControlEventArgs, die dazu dient, die gesammelten Daten zurück an den Host zu senden.

Fügen Sie Ihrem MyControls-Namespace den folgenden Code hinzu. Die Implementierung ist einfach und wird nicht weiter erläutert.

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

Erstellen Sie die Projektmappe. Der Build erzeugt eine DLL mit dem Namen MyControls.dll.

Implementieren der Windows Forms-Hostanwendung

Die Windows Forms-Hostanwendung verwendet ein ElementHost-Objekt zum Hosten des zusammengesetzten WPF-Steuerelements. Die Anwendung verarbeitet das OnButtonClick-Ereignis, um die Daten aus dem zusammengesetzten Steuerelement zu empfangen. In der Anwendung gibt es außerdem eine Reihe von Optionsfeldern, über die Sie die Darstellung des Steuerelements ändern können. Die folgende Abbildung zeigt die Anwendung.

Die folgende Abbildung zeigt ein in einer Windows Forms-Anwendung gehostetes zusammengesetztes WPF-Steuerelement.

Screenshot that shows a Windows Form Hosting Avalon control.

Erstellen des Projekts

Um das Projekt zu starten:

  1. Starten Sie Visual Studio, und öffnen Sie das Dialogfeld Neues Projekt.

  2. Wählen Sie in Visual C# in der Kategorie „Windows” die Vorlage Windows Forms-Anwendung aus.

  3. Geben Sie dem neuen Projekt den Namen WFHost.

  4. Geben Sie für den Speicherort denselben Stammordner an, der das Projekt „MyControls” enthält.

  5. Klicken Sie auf OK, um das Projekt zu erstellen.

Sie müssen auch Verweise auf die DLL, die MyControl1 enthält, und auf andere Assemblys hinzufügen.

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Projektnamen, und wählen Sie Verweis hinzufügen aus.

  2. Klicken Sie auf die Registerkarte Durchsuchen, und navigieren Sie zu dem Ordner, der „MyControls.dll“ enthält. In dieser exemplarischen Vorgehensweise ist dies der Ordner "MyControls\bin\Debug".

  3. Wählen Sie „MyControls.dll“ aus, und klicken Sie auf OK.

  4. Fügen Sie Verweise auf die folgenden Assemblys hinzu.

    • PresentationCore

    • PresentationFramework

    • System.Xaml

    • WindowsBase

    • WindowsFormsIntegration

Implementieren der Benutzeroberfläche für die Anwendung

Die Benutzeroberfläche für die Windows Forms-Anwendung enthält mehrere Steuerelemente, die dazu dienen, mit dem zusammengesetzten WPF-Steuerelement zu interagieren.

  1. Öffnen Sie Form1 im Windows Forms-Designer.

  2. Vergrößern Sie das Formular, um den Steuerelementen genügend Platz zu geben.

  3. Fügen Sie in der oberen rechten Ecke des Formulars ein System.Windows.Forms.Panel-Steuerelement zur Aufnahme des zusammengesetzten WPF-Steuerelements hinzu.

  4. Fügen Sie dem Formular die folgenden System.Windows.Forms.GroupBox-Steuerelemente hinzu.

    Name Text
    groupBox1 Hintergrundfarbe
    groupBox2 Vordergrundfarbe
    groupBox3 Schriftgrad
    groupBox4 Schriftfamilie
    groupBox5 Schriftschnitt
    groupBox6 Schriftbreite
    groupBox7 Daten vom Steuerelement
  5. Fügen Sie den System.Windows.Forms.GroupBox-Steuerelementen die folgenden System.Windows.Forms.RadioButton-Steuerelemente hinzu.

    GroupBox Name Text
    groupBox1 radioBackgroundOriginal Ursprünglich
    groupBox1 radioBackgroundLightGreen Hellgrün
    groupBox1 radioBackgroundLightSalmon Helles Lachsrot
    groupBox2 radioForegroundOriginal Ursprünglich
    groupBox2 radioForegroundRed Red
    groupBox2 radioForegroundYellow Gelb
    groupBox3 radioSizeOriginal Ursprünglich
    groupBox3 radioSizeTen 10
    groupBox3 radioSizeTwelve 12
    groupBox4 radioFamilyOriginal Ursprünglich
    groupBox4 radioFamilyTimes Times New Roman
    groupBox4 radioFamilyWingDings WingDings
    groupBox5 radioStyleOriginal Normal
    groupBox5 radioStyleItalic Kursiv
    groupBox6 radioWeightOriginal Ursprünglich
    groupBox6 radioWeightBold Fett
  6. Fügen Sie dem letzten System.Windows.Forms.GroupBox die folgenden System.Windows.Forms.Label-Steuerelemente hinzu. Diese Steuerelemente zeigen die vom zusammengesetzten WPF-Steuerelement zurückgegebenen Daten an.

    GroupBox Name Text
    groupBox7 lblName Name:
    groupBox7 lblAddress Straße und Hausnummer:
    groupBox7 lblCity Ort:
    groupBox7 lblState Status:
    groupBox7 lblZip Postleitzahl:

Initialisieren des Formulars

Sie implementieren den Hostingcode generell im Load-Ereignishandler des Formulars. Der folgende Code zeigt den Load-Ereignishandler, einen Handler für das Loaded-Ereignis des zusammengesetzten WPF-Steuerelements und Deklarationen für mehrere globale Variablen, die später verwendet werden.

Doppelklicken Sie im Windows Forms-Designer auf das Formular, um einen Load-Ereignishandler zu erstellen. Fügen Sie am Anfang von „Form1.cs“ die folgenden using-Anweisungen hinzu.

using System.Windows;
using System.Windows.Forms.Integration;
using System.Windows.Media;

Ersetzen Sie den Inhalt der vorhandenen Form1-Klasse durch den folgenden Code.

private ElementHost ctrlHost;
private MyControls.MyControl1 wpfAddressCtrl;
System.Windows.FontWeight initFontWeight;
double initFontSize;
System.Windows.FontStyle initFontStyle;
System.Windows.Media.SolidColorBrush initBackBrush;
System.Windows.Media.SolidColorBrush initForeBrush;
System.Windows.Media.FontFamily initFontFamily;

public Form1()
{
    InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
    ctrlHost = new ElementHost();
    ctrlHost.Dock = DockStyle.Fill;
    panel1.Controls.Add(ctrlHost);
    wpfAddressCtrl = new MyControls.MyControl1();
    wpfAddressCtrl.InitializeComponent();
    ctrlHost.Child = wpfAddressCtrl;

    wpfAddressCtrl.OnButtonClick +=
        new MyControls.MyControl1.MyControlEventHandler(
        avAddressCtrl_OnButtonClick);
    wpfAddressCtrl.Loaded += new RoutedEventHandler(
        avAddressCtrl_Loaded);
}

void avAddressCtrl_Loaded(object sender, EventArgs e)
{
    initBackBrush = (SolidColorBrush)wpfAddressCtrl.MyControl_Background;
    initForeBrush = wpfAddressCtrl.MyControl_Foreground;
    initFontFamily = wpfAddressCtrl.MyControl_FontFamily;
    initFontSize = wpfAddressCtrl.MyControl_FontSize;
    initFontWeight = wpfAddressCtrl.MyControl_FontWeight;
    initFontStyle = wpfAddressCtrl.MyControl_FontStyle;
}

Die Form1_Load-Methode im vorstehenden Code zeigt die allgemeine Vorgehensweise zum Hosten eines WPF-Steuerelements:

  1. Erstellen Sie ein neues ElementHost-Objekt.

  2. Legen Sie die Eigenschaft Dock des Steuerelements auf DockStyle.Fill fest.

  3. Fügen Sie das Steuerelement ElementHost der Auflistung Controls des Steuerelements Panel hinzu.

  4. Erstellen Sie eine Instanz des WPF-Steuerelements.

  5. Hosten Sie das zusammengesetzte Steuerelement im Formular, indem Sie es der Eigenschaft Child des Steuerelements ElementHost zuweisen.

Die verbleibenden zwei Zeilen in der Form1_Load-Methode fügen Handler an zwei Steuerelementereignisse an:

  • OnButtonClick ist ein benutzerdefiniertes Ereignis, das vom zusammengesetzten Steuerelement ausgelöst wird, wenn der Benutzer auf die Schaltfläche OK oder Abbrechen klickt. Behandeln Sie dieses Ereignis, um die Antwort des Benutzers zu erhalten und alle vom Benutzer angegebenen Daten zu erfassen.

  • Loaded ist ein Standardereignis, das von einem WPF-Steuerelement ausgelöst wird, wenn es vollständig geladen ist. Das Ereignis wird hier verwendet, da dieses Beispiel mehrere globale Variablen mithilfe der Eigenschaften des Steuerelements initialisieren muss. Zum Zeitpunkt des Load-Ereignisses für das Formular ist das Steuerelement nicht vollständig geladen, und diese Werte sind noch auf null festgelegt. Sie müssen warten, bis das Loaded-Ereignis des Steuerelements eintritt, bevor Sie auf diese Eigenschaften zugreifen können.

Der Loaded-Ereignishandler wird im vorhergehenden Code angezeigt. Der OnButtonClick-Handler wird im nächsten Abschnitt erläutert.

Behandeln von OnButtonClick

Das OnButtonClick-Ereignis tritt ein, wenn der Benutzer auf die Schaltfläche OK oder Abbrechen klickt.

Der Ereignishandler überprüft das Feld IsOK des Ereignisarguments, um zu ermitteln, auf welche Schaltfläche geklickt wurde. Die lbldata-Variablen entsprechen den weiter oben erläuterten Label-Steuerelementen. Wenn der Benutzer auf die Schaltfläche OK klickt, werden die Daten aus den TextBox-Steuerelementen des Steuerelements dem entsprechenden Label-Steuerelement zugewiesen. Wenn der Benutzer auf Abbrechen klickt, werden die Text-Werte auf die Standardzeichenfolgen festgelegt.

Fügen Sie der Form1-Klasse den folgenden „ButtonClick“-Ereignishandlercode hinzu.

void avAddressCtrl_OnButtonClick(
    object sender,
    MyControls.MyControl1.MyControlEventArgs args)
{
    if (args.IsOK)
    {
        lblAddress.Text = "Street Address: " + args.MyStreetAddress;
        lblCity.Text = "City: " + args.MyCity;
        lblName.Text = "Name: " + args.MyName;
        lblState.Text = "State: " + args.MyState;
        lblZip.Text = "Zip: " + args.MyZip;
    }
    else
    {
        lblAddress.Text = "Street Address: ";
        lblCity.Text = "City: ";
        lblName.Text = "Name: ";
        lblState.Text = "State: ";
        lblZip.Text = "Zip: ";
    }
}

Erstellen Sie die Anwendung, und führen Sie sie aus. Fügen Sie dem zusammengesetzten WPF-Steuerelement etwas Text hinzu, und klicken Sie auf OK. Der Text wird in den Beschriftungen angezeigt. Zu diesem Zeitpunkt wurde noch kein Code für die Behandlung der Optionsfelder hinzugefügt.

Ändern des Erscheinungsbilds des Steuerelements

Die RadioButton-Steuerelemente im Formular ermöglichen es dem Benutzer, die Vorder- und Hintergrundfarben sowie mehrere Schriftarteigenschaften des zusammengesetzten WPF-Steuerelements zu ändern. Die Hintergrundfarbe wird vom Objekt ElementHost verfügbar gemacht. Die übrigen Eigenschaften werden als benutzerdefinierte Eigenschaften des Steuerelements verfügbar gemacht.

Doppelklicken Sie auf jedes RadioButton-Steuerelement im Formular, um CheckedChanged-Ereignishandler zu erstellen. Ersetzen Sie die CheckedChanged-Ereignishandler durch den folgenden Code.

private void radioBackgroundOriginal_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_Background = initBackBrush;
}

private void radioBackgroundLightGreen_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_Background = new SolidColorBrush(Colors.LightGreen);
}

private void radioBackgroundLightSalmon_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_Background = new SolidColorBrush(Colors.LightSalmon);
}

private void radioForegroundOriginal_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_Foreground = initForeBrush;
}

private void radioForegroundRed_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_Foreground = new System.Windows.Media.SolidColorBrush(Colors.Red);
}

private void radioForegroundYellow_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_Foreground = new System.Windows.Media.SolidColorBrush(Colors.Yellow);
}

private void radioFamilyOriginal_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontFamily = initFontFamily;
}

private void radioFamilyTimes_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontFamily = new System.Windows.Media.FontFamily("Times New Roman");
}

private void radioFamilyWingDings_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontFamily = new System.Windows.Media.FontFamily("WingDings");
}

private void radioSizeOriginal_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontSize = initFontSize;
}

private void radioSizeTen_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontSize = 10;
}

private void radioSizeTwelve_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontSize = 12;
}

private void radioStyleOriginal_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontStyle = initFontStyle;
}

private void radioStyleItalic_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontStyle = System.Windows.FontStyles.Italic;
}

private void radioWeightOriginal_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontWeight = initFontWeight;
}

private void radioWeightBold_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontWeight = FontWeights.Bold;
}

Erstellen Sie die Anwendung, und führen Sie sie aus. Klicken Sie auf die verschiedenen Optionsfelder, um die Auswirkung auf das zusammengesetzte WPF-Steuerelement zu sehen.

Siehe auch