Leggere in inglese

Condividi tramite


Che cosa sono i controlli?

Windows Presentation Foundation (WPF) viene fornito con molti dei componenti comuni dell'interfaccia utente usati in quasi tutte le app di Windows, ad esempio Button, TextBoxLabel, , Menue ListBox. Storicamente, questi oggetti vengono definiti controlli. Il termine "control" viene usato in modo libero per indicare qualsiasi classe che rappresenta un oggetto visibile in un'app. È importante notare che una classe non deve ereditare dalla Control classe per avere una presenza visibile. Le classi che ereditano dalla classe Control contengono un ControlTemplate, il quale consente all'utente di un controllo di modificarne radicalmente l'aspetto senza la necessità di creare una nuova sotto-classe. Questo articolo illustra in che modo i controlli (sia quelli che ereditano dalla Control classe che quelli che non lo fanno) vengono comunemente usati in WPF.

Creare un'istanza di un controllo

Puoi aggiungere un controllo a un'app usando Extensible Application Markup Language (XAML) o il codice. Si consideri ad esempio l'immagine seguente di una finestra WPF che chiede a un utente il nome e l'indirizzo:

Screenshot di un'app WPF con due caselle di testo con etichetta nome e indirizzo. Sono visibili due pulsanti. Un pulsante è denominato 'Reset' e l'altro 'Submit'.

Questa finestra include sei controlli: due etichette, due caselle di testo e due pulsanti. XAML viene usato per creare questi controlli, come illustrato nel frammento di codice seguente:

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

Tutti i controlli possono essere creati in modo analogo in XAML. La stessa finestra può essere creata nel codice:

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

Sottoscrivere eventi

Puoi sottoscrivere l'evento di un controllo usando XAML o codice, ma puoi gestire solo un evento nel codice.

In XAML l'evento viene impostato come attributo sull'elemento . Non è possibile usare la <Element.Event>handler<Element.Event> notazione per gli eventi. Il frammento di codice seguente illustra come sottoscrivere l'evento Click di un oggetto Button:

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

Ecco come eseguire la stessa operazione nel codice:

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

Il frammento di codice seguente gestisce l'evento Click di un oggetto 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

Modificare l'aspetto di un controllo

È comune modificare l'aspetto di un controllo per adattare l'aspetto dell'app. È possibile modificare l'aspetto di un controllo eseguendo una delle operazioni seguenti, a seconda di ciò che si vuole eseguire:

  • Modificare il valore di una proprietà del controllo .
  • Creare un Style per il controllo.
  • Crea un nuovo ControlTemplate per il controllo.

Modificare la proprietà di un controllo

Molti controlli hanno proprietà che consentono di modificare la modalità di visualizzazione del controllo, ad esempio lo sfondo di un pulsante. Puoi impostare le proprietà del valore sia in XAML che nel codice. L'esempio seguente imposta le proprietà Background, FontSize e FontWeight in un Button in XAML.

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

Ecco come eseguire la stessa operazione nel codice:

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

La finestra di esempio è ora simile all'immagine seguente:

Screenshot di un'app WPF con due caselle di testo con etichetta nome e indirizzo. Sono visibili due pulsanti. Un pulsante è denominato 'Reset' e l'altro 'Submit'. Il pulsante

Creare uno stile per un controllo

WPF offre un'ampia capacità di specificare l'aspetto dei controlli creando un Style oggetto, invece di impostare le proprietà in ogni controllo. Style le definizioni vengono in genere definite in XAML in un ResourceDictionary oggetto, ad esempio la proprietà Resources di un controllo o di una finestra. Le risorse vengono applicate all'ambito in cui vengono dichiarate. Per altre informazioni, vedere Panoramica delle risorse XAML.

Nell'esempio seguente, viene applicato un Style a ogni Button contenuto nello stesso Grid che definisce lo stile:

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

Ecco come eseguire la stessa operazione nel codice:

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)

L'immagine seguente mostra lo stile applicato alla griglia della finestra, che modifica l'aspetto dei due pulsanti:

Screenshot di un'app WPF con due caselle di testo con etichetta nome e indirizzo. Sono visibili due pulsanti. Un pulsante è denominato 'Reset' e l'altro 'Submit'. Entrambi i pulsanti presentano uno sfondo sfumato che passa da un blu a un blu più chiaro.

Anziché applicare lo stile a tutti i controlli di un tipo specifico, possono anche essere assegnati a controlli specifici aggiungendo una chiave allo stile nel dizionario risorse e facendo riferimento a tale chiave nella Style proprietà del controllo . Per ulteriori informazioni sugli stili, vedere Styling e Templating.

Creare un ControlTemplate

Un Style oggetto consente di impostare le proprietà su più controlli alla volta, ma a volte può essere utile personalizzare l'aspetto di un controllo oltre a quello che è possibile eseguire con un oggetto Style. Le classi che ereditano dalla classe Control hanno un oggetto ControlTemplate, che definisce la struttura e l'aspetto di un controllo.

Si consideri il Button controllo , un controllo comune usato da quasi tutte le app. Il comportamento principale di un pulsante consiste nell'consentire a un'app di eseguire alcune azioni quando l'utente seleziona il pulsante. Per impostazione predefinita, il pulsante in WPF viene visualizzato come un rettangolo in rilievo. Durante lo sviluppo di un'app, potresti voler sfruttare il comportamento di un pulsante, ovvero il modo in cui l'utente interagisce con il pulsante, che genera un Click evento, ma potresti modificare l'aspetto del pulsante oltre a ciò che puoi fare modificando le proprietà del pulsante. In questo caso, è possibile creare un nuovo ControlTemplate.

Nell'esempio seguente viene creato un ControlTemplate per un Button. ControlTemplate crea un oggetto visivo per il Button che presenta un bordo con angoli arrotondati e uno sfondo sfumato.

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

Nota

La proprietà Background del Button deve essere impostata su un SolidColorBrush affinché l'esempio funzioni correttamente.

Ecco come eseguire la stessa operazione nel codice. Il codice seguente crea una stringa XAML e la analizza per generare un modello che può essere applicato, che è il modo supportato per generare un modello in fase di esecuzione.

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)

L'immagine seguente mostra l'aspetto del modello quando applicato:

Screenshot di un'app WPF con due caselle di testo con etichetta nome e indirizzo. Sono visibili due pulsanti. Un pulsante è denominato 'Reset' e l'altro 'Submit'. Il pulsante

Nell'esempio precedente, l'oggetto ControlTemplate viene applicato a un singolo pulsante. Tuttavia, un ControlTemplate oggetto può essere assegnato a un Style oggetto e applicato a tutti i pulsanti, come illustrato nella sezione Creare uno stile per un controllo .

Per altre informazioni su come sfruttare le caratteristiche univoche offerte da un modello, vedere Applicazione di stili e modelli.

Contenuto avanzato nei controlli

La maggior parte delle classi che ereditano dalla classe Control hanno la capacità di contenere contenuto avanzato. Ad esempio, un Label può contenere qualsiasi oggetto, ad esempio una stringa, un Imageo un Panel. Le classi seguenti forniscono supporto per contenuti avanzati e fungono da classi di base per la maggior parte dei controlli in WPF: