Freigeben über


Was sind Kontrollen?

Windows Presentation Foundation (WPF) enthält viele der allgemeinen UI-Komponenten, die in fast jeder Windows-App verwendet werden, z. B. Button, Label, TextBox, Menu und ListBox. In der Vergangenheit werden diese Objekte als Steuerelemente bezeichnet. Der Begriff "Steuerelement" wird lose verwendet, um jede Klasse zu bedeuten, die ein sichtbares Objekt in einer App darstellt. Es ist wichtig zu beachten, dass eine Klasse nicht von der Control Klasse erben muss, um eine sichtbare Anwesenheit zu haben. Klassen, die von der Control Klasse erben, enthalten eine ControlTemplate, mit der der Consumer eines Steuerelements die Darstellung des Steuerelements radikal ändern kann, ohne eine neue Unterklasse erstellen zu müssen. In diesem Artikel wird erläutert, wie Steuerelemente (sowohl diejenigen, die von der Control Klasse erben als auch nicht) häufig in WPF verwendet werden.

Erstellen einer Instanz eines Steuerelements

Sie können einer App ein Steuerelement hinzufügen, indem Sie entweder XAML (Extensible Application Markup Language) oder Code verwenden. Betrachten Sie z. B. die folgende Abbildung eines WPF-Fensters, in dem ein Benutzer nach ihrem Namen und seiner Adresse gefragt wird:

Screenshot einer WPF-App mit zwei Textfeldern mit bezeichnungsgeschütztem Namen und Adresse. Zwei Schaltflächen sind sichtbar. Eine Schaltfläche heißt

Dieses Fenster verfügt über sechs Steuerelemente: zwei Beschriftungen, zwei Textfelder und zwei Schaltflächen. XAML wird verwendet, um diese Steuerelemente zu erstellen, wie im folgenden Codeausschnitt veranschaulicht:

<Window x:Class="Examples.ExampleApp"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Input Record" Height="Auto" Width="300" SizeToContent="Height">
    <Grid Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Label>Enter your name:</Label>
        <TextBox Grid.Row="0" Grid.Column="1" Name="FirstName" Margin="2" />

        <Label Grid.Row="1">Enter your address:</Label>
        <TextBox Grid.Row="1" Grid.Column="1" Name="LastName" Margin="2" />

        <Button Grid.Row="2" Grid.Column="0" Name="Reset" Margin="2">Reset</Button>
        <Button Grid.Row="2" Grid.Column="1" Name="Submit" Margin="2">Submit</Button>
    </Grid>
</Window>

Alle Steuerelemente können in XAML ähnlich erstellt werden. Dasselbe Fenster kann im Code erstellt werden:

// Grid container which is the content of the Window
Grid container = new() { Margin = new Thickness(5) };
container.RowDefinitions.Add(new RowDefinition());
container.RowDefinitions.Add(new RowDefinition());
container.RowDefinitions.Add(new RowDefinition());
container.ColumnDefinitions.Add(new ColumnDefinition());
container.ColumnDefinitions.Add(new ColumnDefinition());

// Create the two labels, assign the second label to the second row
Label labelName = new() { Content = "Enter your name:" };
container.Children.Add(labelName);

Label labelAddress = new() { Content = "Enter your address:" };
Grid.SetRow(labelAddress, 1);
container.Children.Add(labelAddress);

// Create the two textboxes, assign both to the second column and
// assign the second textbox to the second row.
TextBox textboxName = new() { Margin = new Thickness(2) };
Grid.SetColumn(textboxName, 1);
container.Children.Add(textboxName);

TextBox textboxAddress = new() { Margin = new Thickness(2) };
Grid.SetRow(textboxAddress, 1);
Grid.SetColumn(textboxAddress, 1);
container.Children.Add(textboxAddress);

// Create the two buttons, assign both to the third row and
// assign the second button to the second column.
Button buttonReset = new() { Margin = new Thickness(2), Content = "Reset" };
Grid.SetRow(buttonReset, 2);
container.Children.Add(buttonReset);

Button buttonSubmit = new() { Margin = new Thickness(2), Content = "Submit" };
Grid.SetColumn(buttonSubmit, 1);
Grid.SetRow(buttonSubmit, 2);
container.Children.Add(buttonSubmit);

// Create the popup window and assign the container (Grid) as its content
Window inputWindow = new()
{
    Title = "Input Record",
    Height = double.NaN,
    Width = 300,
    SizeToContent = SizeToContent.Height,
    Content = container
};

inputWindow.Show();
' Grid container which is the content of the Window
Dim container As New Grid() With {.Margin = New Thickness(5)}
container.RowDefinitions.Add(New RowDefinition())
container.RowDefinitions.Add(New RowDefinition())
container.RowDefinitions.Add(New RowDefinition())
container.ColumnDefinitions.Add(New ColumnDefinition())
container.ColumnDefinitions.Add(New ColumnDefinition())

' Create the two labels, assign the second label to the second row
Dim labelName As New Label() With {.Content = "Enter your name:"}
container.Children.Add(labelName)

Dim labelAddress As New Label() With {.Content = "Enter your address:"}
Grid.SetRow(labelAddress, 1)
container.Children.Add(labelAddress)

' Create the two textboxes, assign both to the second column and
' assign the second textbox to the second row.
Dim textboxName As New TextBox() With {.Margin = New Thickness(2)}
Grid.SetColumn(textboxName, 1)
container.Children.Add(textboxName)

Dim textboxAddress As New TextBox() With {.Margin = New Thickness(2)}
Grid.SetRow(textboxAddress, 1)
Grid.SetColumn(textboxAddress, 1)
container.Children.Add(textboxAddress)

' Create the two buttons, assign both to the third row and
' assign the second button to the second column.
Dim buttonReset As New Button() With {.Margin = New Thickness(2), .Content = "Reset"}
Grid.SetRow(buttonReset, 2)
container.Children.Add(buttonReset)

Dim buttonSubmit As New Button() With {.Margin = New Thickness(2), .Content = "Submit"}
Grid.SetColumn(buttonSubmit, 1)
Grid.SetRow(buttonSubmit, 2)
container.Children.Add(buttonSubmit)

' Create the window and assign the container (Grid) as its content
Dim inputWindow As New Window() With
{
    .Title = "Input Record",
    .Height = Double.NaN,
    .Width = 300,
    .SizeToContent = SizeToContent.Height,
    .Content = container
}

inputWindow.Show()

Abonnieren von Ereignissen

Sie können das Ereignis eines Steuerelements mithilfe von XAML oder Code abonnieren, aber Sie können ein Ereignis nur im Code behandeln.

In XAML wird das Ereignis als Attribut für das Element festgelegt. Sie können die <Element.Event>handler<Element.Event> Schreibweise nicht für Ereignisse verwenden. Der folgende Codeausschnitt zeigt, wie Sie das Ereignis einer Click abonnieren:

<Button Click="Submit_Click" Grid.Row="2" Grid.Column="1" Name="Submit" Margin="2">Submit</Button>

Und so machen Sie das Gleiche im Code:

Button buttonSubmit = new() { Margin = new Thickness(2), Content = "Submit" };
buttonSubmit.Click += Submit_Click;
Dim buttonSubmit As New Button() With {.Margin = New Thickness(2), .Content = "Submit"}
AddHandler buttonSubmit.Click, AddressOf Submit_Click

Der folgende Codeausschnitt behandelt das Click Ereignis eines Button:

private void Submit_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Someone clicked the submit button.");
}
Private Sub Submit_Click(sender As Object, e As Windows.RoutedEventArgs)
    MessageBox.Show("Someone clicked the submit button.")
End Sub

Ändern des Erscheinungsbilds eines Steuerelements

Es ist üblich, das Erscheinungsbild eines Steuerelements zu ändern, um das Aussehen und Verhalten Ihrer App anzupassen. Sie können die Darstellung eines Steuerelements ändern, indem Sie eine der folgenden Aktionen ausführen, je nachdem, was Sie erreichen möchten:

  • Ändern Sie den Wert einer Eigenschaft des Steuerelements.
  • Erstellen Sie ein Style für die Steuerung.
  • Erstellen Sie ein neues ControlTemplate Steuerelement.

Ändern Sie die Eigenschaft eines Steuerelements

Viele Steuerelemente verfügen über Eigenschaften, mit denen Sie ändern können, wie das Steuerelement angezeigt wird, z. B. den Hintergrund einer Schaltfläche. Sie können die Werteigenschaften sowohl in XAML als auch im Code festlegen. Im folgenden Beispiel werden die Background, FontSize und FontWeight Eigenschaften eines Button in XAML festgelegt:

<Button Grid.Row="2" Grid.Column="1" Name="Submit" Margin="2" Content="Submit">
    <Button.FontSize>18</Button.FontSize>
    <Button.FontWeight>Bold</Button.FontWeight>
    <Button.Background>
        <LinearGradientBrush>
            <GradientStop Color="#0073E6" Offset="0.0" />
            <GradientStop Color="#81D4FA" Offset="0.9" />
        </LinearGradientBrush>
    </Button.Background>
</Button>

Und so machen Sie das Gleiche im Code:

Button buttonSubmit = new() { Margin = new Thickness(2), Content = "Submit" };
buttonSubmit.FontSize = 18f;
buttonSubmit.FontWeight = FontWeights.Bold;
buttonSubmit.Background =
    new LinearGradientBrush(
        (Color)ColorConverter.ConvertFromString("#0073E6"),
        (Color)ColorConverter.ConvertFromString("#81D4FA"),
        new Point(0d, 0d),
        new Point(0.9d, 0d));
Dim buttonSubmit As New Button() With {.Margin = New Thickness(2), .Content = "Submit"}
buttonSubmit.FontSize = 18.0F
buttonSubmit.FontWeight = FontWeights.Bold
buttonSubmit.Background =
        New LinearGradientBrush(
            ColorConverter.ConvertFromString("#0073E6"),
            ColorConverter.ConvertFromString("#81D4FA"),
            New Point(0D, 0D),
            New Point(0.9D, 0D))

Das Beispielfenster sieht nun wie die folgende Abbildung aus:

Screenshot einer WPF-App mit zwei Textfeldern, die mit Name und Adresse beschriftet sind. Zwei Buttons sind sichtbar: Ein Button heißt

Erstellen einer Formatvorlage für ein Steuerelement

Mit WPF können Sie die Darstellung von Steuerelementen umfassend angeben, indem Sie eine Style erstellen, anstatt die Eigenschaft jedes einzelnen Steuerelements festzulegen. Style Definitionen werden in der Regel in XAML in einem ResourceDictionary festgelegt, z. B. in der Resources-Eigenschaft eines Steuerelements oder eines Fensters. Ressourcen werden auf den Bereich angewendet, in dem sie deklariert werden. Weitere Informationen finden Sie unter Übersicht über XAML-Ressourcen.

Im folgenden Beispiel wird eine Style auf alle Button angewendet, die in dem Grid enthalten sind, das die Formatvorlage definiert.

<Grid.Resources>
    <Style TargetType="{x:Type Button}">
        <Style.Setters>
            <Setter Property="FontSize" Value="18" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="Background">
                <Setter.Value>
                    <LinearGradientBrush>
                        <GradientStop Color="#0073E6" Offset="0.0" />
                        <GradientStop Color="#81D4FA" Offset="0.9" />
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style.Setters>
    </Style>
</Grid.Resources>

Und so machen Sie das Gleiche im Code:

Grid container = new() { Margin = new Thickness(5) };
container.RowDefinitions.Add(new RowDefinition());
container.RowDefinitions.Add(new RowDefinition());
container.RowDefinitions.Add(new RowDefinition());
container.ColumnDefinitions.Add(new ColumnDefinition());
container.ColumnDefinitions.Add(new ColumnDefinition());

Style buttonStyle = new(typeof(Button));
buttonStyle.Setters.Add(new Setter(Button.FontSizeProperty, 18d));
buttonStyle.Setters.Add(new Setter(Button.FontWeightProperty, FontWeights.Bold));
buttonStyle.Setters.Add(new Setter(Button.BackgroundProperty,
    new LinearGradientBrush(
        (Color)ColorConverter.ConvertFromString("#0073E6"),
        (Color)ColorConverter.ConvertFromString("#81D4FA"),
        new Point(0d, 0d),
        new Point(0.9d, 0d))));

container.Resources.Add(typeof(Button), buttonStyle);
Dim container As New Grid() With {.Margin = New Thickness(5)}
container.RowDefinitions.Add(New RowDefinition())
container.RowDefinitions.Add(New RowDefinition())
container.RowDefinitions.Add(New RowDefinition())
container.ColumnDefinitions.Add(New ColumnDefinition())
container.ColumnDefinitions.Add(New ColumnDefinition())

Dim buttonStyle As New Style(GetType(Button))
buttonStyle.Setters.Add(New Setter(Button.FontSizeProperty, 18.0R))
buttonStyle.Setters.Add(New Setter(Button.FontWeightProperty, FontWeights.Bold))
buttonStyle.Setters.Add(New Setter(Button.BackgroundProperty,
        New LinearGradientBrush(
            ColorConverter.ConvertFromString("#0073E6"),
            ColorConverter.ConvertFromString("#81D4FA"),
            New Point(0D, 0D),
            New Point(0.9D, 0D))))

container.Resources.Add(GetType(Button), buttonStyle)

Die folgende Abbildung zeigt den Stil, der auf das Raster des Fensters angewendet wird und das Aussehen der beiden Schaltflächen ändert.

Screenshot einer WPF-App mit zwei Textfeldern mit den Bezeichnungen Name und Adresse. Zwei Schaltflächen sind sichtbar. Eine Schaltfläche heißt

Anstatt die Formatvorlage auf alle Steuerelemente eines bestimmten Typs anzuwenden, kann sie auch bestimmten Steuerelementen zugewiesen werden, indem der Formatvorlage im Ressourcenwörterbuch ein Schlüssel hinzugefügt und auf diesen Schlüssel in der Style-Eigenschaft des Steuerelements verwiesen wird. Weitere Informationen zu Formatvorlagen finden Sie unter "Formatieren und Vorlagen".

Erstellen einer ControlTemplate

Mithilfe eines Style Steuerelements können Sie Eigenschaften für mehrere Steuerelemente gleichzeitig festlegen, aber manchmal möchten Sie möglicherweise das Erscheinungsbild eines Steuerelements anpassen, das über das hinausgeht, was Sie mit einem StyleSteuerelement tun können. Klassen, die von der Control Klasse erben, haben eine ControlTemplate, die die Struktur und Darstellung eines Steuerelements definiert.

Betrachten Sie das Button Steuerelement, ein gängiges Steuerelement, das von fast jeder App verwendet wird. Das Hauptverhalten einer Schaltfläche besteht darin, eine App zu aktivieren, um eine Aktion auszuführen, wenn der Benutzer die Schaltfläche auswählt. Standardmäßig wird die Schaltfläche in WPF als ausgelöstes Rechteck angezeigt. Beim Entwickeln einer App möchten Sie möglicherweise das Verhalten einer Schaltfläche nutzen, d. h. wie der Benutzer mit der Schaltfläche interagiert, wodurch ein Click Ereignis ausgelöst wird, aber Sie können das Erscheinungsbild der Schaltfläche über das hinaus ändern, was Sie tun können, indem Sie die Eigenschaften der Schaltfläche ändern. In diesem Fall können Sie ein neues ControlTemplateerstellen.

Im folgenden Beispiel wird ein ControlTemplate für ein Button erstellt. Das ControlTemplate erstellt eine grafische Darstellung für die Button, die einen Rahmen mit abgerundeten Ecken und einen Hintergrund mit Farbverlauf präsentiert.

<Button Grid.Row="2" Grid.Column="1" Name="Submit" Margin="2" Content="Submit">
    <Button.Template>
        <ControlTemplate TargetType="Button">
            <Border Name="Border" CornerRadius="10" BorderThickness="1" BorderBrush="Black">
                <Border.Background>
                    <LinearGradientBrush StartPoint="0,0.5" 
                         EndPoint="1,0.5">
                        <GradientStop Color="{Binding Background.Color, RelativeSource={RelativeSource TemplatedParent}}" Offset="0.0" />
                        <GradientStop Color="PeachPuff" Offset="0.9" />
                    </LinearGradientBrush>
                </Border.Background>
                <ContentPresenter Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True"/>
            </Border>
            <ControlTemplate.Triggers>
                <!--Change the appearance of the button when the user clicks it.-->
                <Trigger Property="IsPressed" Value="true">
                    <Setter TargetName="Border" Property="Background">
                        <Setter.Value>
                            <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
                                <GradientStop Color="{Binding Background.Color, RelativeSource={RelativeSource TemplatedParent}}" Offset="0.0" />
                                <GradientStop Color="LightBlue" Offset="0.9" />
                            </LinearGradientBrush>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Button.Template>
</Button>

Hinweis

Die Background Eigenschaft des Button Objekts muss auf ein SolidColorBrush festgelegt werden, damit das Beispiel ordnungsgemäß funktioniert.

Und hier erfahren Sie, wie Sie dasselbe im Code ausführen. Mit dem folgenden Code wird eine XAML-Zeichenfolge erstellt und analysiert, um eine Vorlage zu generieren, die angewendet werden kann. Dies ist die unterstützte Methode zum Generieren einer Vorlage zur Laufzeit.

Button buttonSubmit = new() { Margin = new Thickness(2), Content = "Submit" };

// Create the XAML used to define the button template
const string xaml = """
    <ControlTemplate TargetType="Button">
        <Border Name="Border" CornerRadius="10" BorderThickness="1" BorderBrush="Black">
            <Border.Background>
                <LinearGradientBrush StartPoint="0,0.5" 
                     EndPoint="1,0.5">
                    <GradientStop Color="{Binding Background.Color, RelativeSource={RelativeSource TemplatedParent}}" Offset="0.0" />
                    <GradientStop Color="PeachPuff" Offset="0.9" />
                </LinearGradientBrush>
            </Border.Background>
            <ContentPresenter Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True"/>
        </Border>
        <ControlTemplate.Triggers>
            <!--Change the appearance of the button when the user clicks it.-->
            <Trigger Property="IsPressed" Value="true">
                <Setter TargetName="Border" Property="Background">
                    <Setter.Value>
                        <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
                            <GradientStop Color="{Binding Background.Color, RelativeSource={RelativeSource TemplatedParent}}" Offset="0.0" />
                            <GradientStop Color="LightBlue" Offset="0.9" />
                        </LinearGradientBrush>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
    """;

// Load the XAML into a stream that can be parsed
using MemoryStream stream = new(System.Text.Encoding.UTF8.GetBytes(xaml));

// Create a parser context and add the default namespace and 
// the x namespace, which is common to WPF XAML
System.Windows.Markup.ParserContext context = new();
context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");

// Parse the XAML and assign it to the button's template
buttonSubmit.Template = (ControlTemplate)System.Windows.Markup.XamlReader.Load(stream, context);

// Set the other properties of the button
Grid.SetColumn(buttonSubmit, 1);
Grid.SetRow(buttonSubmit, 2);

// Assign the button to the grid container
container.Children.Add(buttonSubmit);
Dim buttonSubmit As New Button() With {.Margin = New Thickness(2), .Content = "Submit"}

' Create the XAML used to define the button template
Const xaml As String = "
    <ControlTemplate TargetType=""Button"">
        <Border Name=""Border"" CornerRadius=""10"" BorderThickness=""1"" BorderBrush=""Black"">
            <Border.Background>
                <LinearGradientBrush StartPoint=""0,0.5"" 
                     EndPoint=""1,0.5"">
                    <GradientStop Color=""{Binding Background.Color, RelativeSource={RelativeSource TemplatedParent}}"" Offset=""0.0"" />
                    <GradientStop Color=""PeachPuff"" Offset=""0.9"" />
                </LinearGradientBrush>
            </Border.Background>
            <ContentPresenter Margin=""2"" HorizontalAlignment=""Center"" VerticalAlignment=""Center"" RecognizesAccessKey=""True""/>
        </Border>
        <ControlTemplate.Triggers>
            <!--Change the appearance of the button when the user clicks it.-->
            <Trigger Property=""IsPressed"" Value=""true"">
                <Setter TargetName=""Border"" Property=""Background"">
                    <Setter.Value>
                        <LinearGradientBrush StartPoint=""0,0.5"" EndPoint=""1,0.5"">
                            <GradientStop Color=""{Binding Background.Color, RelativeSource={RelativeSource TemplatedParent}}"" Offset=""0.0"" />
                            <GradientStop Color=""LightBlue"" Offset=""0.9"" />
                        </LinearGradientBrush>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>"

' Load the XAML into a stream that can be parsed
Using stream As New MemoryStream(System.Text.Encoding.UTF8.GetBytes(xaml))

    ' Create a parser context and add the default namespace and 
    ' the x namespace, which is common to WPF XAML
    Dim context = New System.Windows.Markup.ParserContext()
    context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation")
    context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml")

    ' Parse the XAML and assign it to the button's template
    buttonSubmit.Template = System.Windows.Markup.XamlReader.Load(stream, context)
End Using

' Set the other properties of the button
Grid.SetColumn(buttonSubmit, 1)
Grid.SetRow(buttonSubmit, 2)

' Assign the button to the grid container
container.Children.Add(buttonSubmit)

Die folgende Abbildung zeigt, wie die Vorlage aussieht, wenn sie angewendet wird:

Screenshot einer WPF-App mit zwei Textfeldern, die als Name und Adresse beschriftet sind. Zwei Schaltflächen sind sichtbar. Eine Schaltfläche ist als

Im vorherigen Beispiel wird die ControlTemplate Schaltfläche auf eine einzelne Schaltfläche angewendet. Jedoch kann ein ControlTemplate einem Style zugewiesen und auf alle Schaltflächen angewendet werden, wie im Abschnitt Erstellen einer Formatvorlage für ein Steuerelement veranschaulicht wurde.

Weitere Informationen zum Nutzen der einzigartigen Features, die eine Vorlage bereitstellt, finden Sie unter "Formatieren und Vorlagen".

Reichhaltiger Inhalt in Steuerelementen

Die meisten Klassen, die von der Control Klasse erben, verfügen über die Kapazität, umfangreiche Inhalte zu enthalten. Zum Beispiel kann ein Label jedes beliebige Objekt enthalten, wie eine Zeichenfolge, ein Image oder ein Panel. Die folgenden Klassen bieten Unterstützung für umfangreiche Inhalte und dienen als Basisklassen für die meisten Steuerelemente in WPF: