共用方式為


什麼是控件?

Windows Presentation Foundation (WPF) 隨附許多通用 UI 元件,這些元件幾乎用於每個 Windows 應用程式,例如 ButtonLabelTextBoxMenuListBox。 從歷史上看,這些對象稱為控件。 「控件」一詞是鬆散地用來表示應用程式中可見物件的任何類別。 請務必注意,類別不需要繼承自 Control 類別,才能有可見的存在。 從 Control 類別繼承的類別會包含 ControlTemplate,可讓控制項的取用者在不須建立新子類別的情況下,大幅變更控制項的外觀。 本文討論在 WPF 中如何經常使用控件,其中包括繼承自 Control 類別的控件以及未繼承該類別的控件。

建立控件的實例

您可以使用可延伸應用程式標記語言 (XAML) 或程式代碼,將控制項新增至應用程式。 例如,請考慮 WPF 視窗的下圖,要求使用者提供其名稱和位址:

WPF 應用程式的螢幕快照,其中包含兩個標示為名稱和位址的文字框。可見兩個按鈕。一個按鈕名為 「重設」,另一個「提交」。

此視窗有六個控件:兩個標籤、兩個文字框和兩個按鈕。 XAML 可用來建立這些控件,如下列代碼段所示:

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

所有控制項都可以在 XAML 中類似地建立。 您可以在程式代碼建立相同的視窗:

// 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()

訂閱活動通知

您可以使用 XAML 或程式碼來訂閱控制項的事件,但只能在程式碼中處理事件。

在 XAML 中,事件會設定為 元素上的屬性。 您無法將 <Element.Event>handler<Element.Event> 表示法用於事件。 下列代碼段示範如何訂閱 ClickButton事件:

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

以下是如何在程式代碼中執行相同的動作:

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

下列代碼段會處理 ClickButton事件:

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

變更控件的外觀

變更控件的外觀,以符合您 app 的外觀和風格很常見。 您可以根據想要達成的目的,執行下列其中一項操作來變更控制項的外觀:

  • 變更控制項的屬性值。
  • 為控制項建立 Style
  • 為控制項建立新的 ControlTemplate

變更控件的屬性

許多控制件都有屬性可讓您變更控制元件的顯示方式,例如按鈕的背景。 您可以在 XAML 和程式碼中都設定值屬性。 下列範例會在 XAML 中對Background設定FontSizeFontWeightButton屬性:

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

以下是如何在程式代碼中執行相同的動作:

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))

範例視窗現在看起來像下圖:

WPF 應用程式的螢幕快照,其中包含兩個標示為名稱和位址的文字框。可見兩個按鈕。一個按鈕名為 「重設」,另一個「提交」。[提交] 按鈕具有漸層背景,從藍色轉換為較淺的藍色。

建立控件的樣式

WPF 可讓您透過建立 Style來指定控制件的外觀,而不是在每個控件上設定屬性。 Style 通常在 ResourceDictionary XAML 中定義,例如控制件或 Window 的 Resources 屬性。 資源會套用至宣告的資源範圍。 如需詳細資訊,請參閱 XAML 資源概觀

下列範例會將 Style 套用至定義樣式之相同 Button 中所含的每個 Grid

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

以下是如何在程式代碼中執行相同的動作:

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)

下圖顯示套用至視窗方格的樣式,這會變更兩個按鈕的外觀:

WPF 應用程式的螢幕快照,其中包含兩個標示為名稱和位址的文字框。可見兩個按鈕。一個按鈕名為 「重設」,另一個「提交」。這兩個按鈕都有漸層背景,從藍色轉換成較淺的藍色。

除了將樣式套用至特定類型的所有控件,也可以藉由將索引鍵新增至資源字典中的樣式,並在控件的 屬性中 Style 參考該索引鍵,來指派給特定控件。 如需樣式的詳細資訊,請參閱樣式設定和範本化

建立 ControlTemplate

Style可讓您一次在多個控制項上設定屬性,但有時您可能想要自訂控制元件的外觀,而不能使用 Style。 繼承自 Control 類別的類別具有 ControlTemplate,其定義控件的結構和外觀。

請考慮控制項 Button ,這是幾乎每個應用程式所使用的通用控制件。 按鈕的主要行為是讓用戶選取按鈕時,讓應用程式採取一些動作。 根據預設,WPF 中的按鈕會顯示為突起的矩形。 在開發應用程式時,您可能希望利用按鈕的行為,也就是使用者與按鈕的互動方式,這會引發一個 Click 事件,但您可能會希望改變按鈕的外觀,而不僅限於調整按鈕的屬性。 在此情況下,您可以建立一個新的 ControlTemplate

下列範例將為 ControlTemplate 建立 ButtonControlTemplateButton 創造具有圓角及漸層背景的邊框視覺效果。

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

備註

BackgroundButton 屬性必須設定為 SolidColorBrush,此範例才能正確運作。

以下是如何在程式代碼中執行相同的動作。 下列程式代碼會建立 XAML 字串並加以剖析,以產生可套用的範本,這是在運行時間產生範本的支援方式。

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)

下圖顯示套用時範本的外觀:

WPF 應用程式的螢幕快照,其中包含兩個標示為名稱和位址的文字框。可見兩個按鈕。一個按鈕名為 「重設」,另一個「提交」。[提交] 按鈕有圓角,並套用桃色。

在上一個範例中,會 ControlTemplate 套用至單一按鈕。 但是,ControlTemplate 可以被指派至 Style,並且套用至所有按鈕,例如在 建立控制項的樣式 部分中所示範的。

如需如何利用範本提供之獨特功能的詳細資訊,請參閱 設定樣式和範本化。

控件中的豐富內容

大多數會從 Control 類別繼承的類別都能夠包含多格式內容。 例如,Label 便可以包含任何物件,像是字串、ImagePanel。 下列類別提供豐富內容的支援,並做為 WPF 中大部分控件的基類: