Panoramica di WPF

Windows Presentation Foundation (WPF) consente di creare applicazioni client desktop per Windows capaci di offrire all'utente un'esperienza visiva sorprendente.

Contoso Healthcare UI sample

L'elemento principale di WPF è un motore di rendering vettoriale e indipendente dalla risoluzione compilato per sfruttare i vantaggi dei moderni componenti hardware grafici. Oltre a questo elemento principale, WPF offre un set completo di funzionalità per lo sviluppo di applicazioni che includono Extensible Application Markup Language (XAML), controlli, data binding, layout, grafica 2D e 3D, animazioni, stili, modelli, documenti, supporti, testo e tipografia. WPF fa parte di .NET e, pertanto, è possibile compilare applicazioni che incorporano altri elementi dell'API .NET.

Questa panoramica, destinata ai principianti, illustra le funzionalità e i concetti chiave di WPF.

Programmazione con WPF

WPF è un subset di tipi di .NET in gran parte contenuti nello spazio dei nomi System.Windows. Se in precedenza si sono già compilate applicazioni con .NET usando tecnologie gestite come ASP.NET e Windows Forms, si è già acquisita familiarità con le operazioni fondamentali di programmazione WPF. È possibile creare istanze di classi, impostare proprietà, chiamare metodi e gestire eventi usando il linguaggio di programmazione .NET preferito, ad esempio C# o Visual Basic.

WPF include costrutti di programmazione aggiuntivi che migliorano proprietà ed eventi: proprietà di dipendenza ed eventi indirizzati.

Markup e code-behind

WPF consente di sviluppare applicazioni usando sia markup sia code-behind, un'esperienza nota agli sviluppatori ASP.NET. Il markup XAML viene normalmente usato per implementare l'aspetto di un'applicazione, mentre i linguaggi di programmazione gestiti (code-behind) vengono usati per implementarne il comportamento. La separazione tra aspetto e comportamento offre alcuni vantaggi:

  • I costi di sviluppo e gestione risultano ridotti, perché il markup specifico per l'aspetto non è associato strettamente a codice specifico per il comportamento.

  • Lo sviluppo è più efficiente, perché i progettisti possono implementare l'aspetto di un'applicazione mentre, contemporaneamente, gli sviluppatori ne implementano il comportamento.

  • Le operazioni diglobalizzazione e localizzazione delle applicazioni WPF sono state semplificate.

Ricarico

XAML è un linguaggio di markup basato su XML che implementa l'aspetto di un'applicazione in modo dichiarativo. Viene in genere usato per creare finestre, finestre di dialogo, pagine e controlli utente e per inserire in questi elementi controlli, forme e grafica.

L'esempio seguente descrive come usare XAML per implementare l'aspetto di una finestra che contiene un solo pulsante:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    Title="Window with Button"
    Width="250" Height="100">

  <!-- Add button to window -->
  <Button Name="button">Click Me!</Button>

</Window>

In particolare, questo codice XAML definisce una finestra e un pulsante con gli elementi Window e Button , rispettivamente. Ogni elemento viene configurato con attributi, ad esempio l'attributo Window dell'elemento Title per specificare il testo della barra del titolo della finestra. In fase di esecuzione, WPF converte gli elementi e gli attributi definiti nel markup in istanze di classi WPF. Ad esempio, l'elemento Window viene convertito in un'istanza della classe Window la cui proprietà Title è il valore dell'attributo Title .

La figura seguente illustra l'interfaccia utente (UI) definita da XAML nell'esempio precedente:

A window that contains a button

Poiché XAML è basato su XML, l'interfaccia utente composta con tale linguaggio viene assemblata in una gerarchia di elementi annidati nota come struttura ad albero di elementi. Questa struttura ad albero di elementi costituisce un modo logico e intuitivo per creare e gestire le interfacce utente.

Code-behind

Il comportamento principale di un'applicazione consiste nell'implementare la funzionalità che risponde alle interazioni dell'utente, inclusa la gestione di eventi (ad esempio la scelta di un menu, una barra degli strumenti o un pulsante) e la chiamata alla logica di business e alla logica di accesso ai dati in risposta a tali eventi. In WPF questo comportamento viene in genere implementato in codice associato a markup. Questo tipo di codice è noto come code-behind. L'esempio seguente illustra il markup aggiornato dell'esempio precedente e il code-behind:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.AWindow"
    Title="Window with Button"
    Width="250" Height="100">

  <!-- Add button to window -->
  <Button Name="button" Click="button_Click">Click Me!</Button>

</Window>
using System.Windows; // Window, RoutedEventArgs, MessageBox

namespace SDKSample
{
    public partial class AWindow : Window
    {
        public AWindow()
        {
            // InitializeComponent call is required to merge the UI
            // that is defined in markup with this class, including  
            // setting properties and registering event handlers
            InitializeComponent();
        }

        void button_Click(object sender, RoutedEventArgs e)
        {
            // Show message box when button is clicked.
            MessageBox.Show("Hello, Windows Presentation Foundation!");
        }
    }
}
Namespace SDKSample

    Partial Public Class AWindow
        Inherits System.Windows.Window

        Public Sub New()

            ' InitializeComponent call is required to merge the UI
            ' that is defined in markup with this class, including  
            ' setting properties and registering event handlers
            InitializeComponent()

        End Sub

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

            ' Show message box when button is clicked.
            MessageBox.Show("Hello, Windows Presentation Foundation!")

        End Sub

    End Class

End Namespace

In questo esempio il code-behind implementa una classe che deriva dalla classe Window . L'attributo x:Class viene usato per associare il markup alla classe code-behind. InitializeComponent viene chiamato dal costruttore della classe code-behind per unire l'interfaccia utente definita nel markup con la classe code-behind. (InitializeComponent viene generato automaticamente quando l'applicazione viene compilata, motivo per cui non è necessario implementarla manualmente. La combinazione di x:Class e InitializeComponent assicurarsi che l'implementazione venga inizializzata correttamente ogni volta che viene creata. La classe code-behind implementa anche un gestore dell'evento Click del pulsante. Quando si fa clic sul pulsante, il gestore eventi mostra una finestra di messaggio chiamando il metodo System.Windows.MessageBox.Show .

La figura seguente illustra il risultato della scelta del pulsante:

A MessageBox

Controlli

Le esperienze utente fornite dal modello di applicazione sono controlli costruiti. In WPF, controllo è un termine generico che si applica a una categoria di classi WPF ospitate in una finestra o una pagina, che hanno un'interfaccia utente e che implementano un comportamento.

Per altre informazioni, vedere Controlli.

Controlli WPF per funzione

I controlli WPF incorporati sono elencati di seguito:

Input e comandi

I controlli nella maggior parte dei casi rilevano e rispondono all'input dell'utente. Il sistema di input di WPF usa eventi sia diretti sia indirizzati per supportare l'input di testo, la gestione dello stato attivo e il posizionamento del mouse.

I requisiti di input delle applicazioni sono spesso complessi. In WPF è disponibile un sistema di comandi che separa le azioni di input utente dal codice che risponde a tali azioni.

Layout

Quando si crea un'interfaccia utente, si dispongono i controlli per percorso e dimensione per creare un layout. Il requisito principale di qualsiasi layout è quello di adattarsi alle modifiche nella dimensione delle finestre e nelle impostazioni di visualizzazione. Anziché richiedere la scrittura di codice per adattare un layout in tali circostanze, WPF offre un efficiente sistema di layout estendibile.

L'elemento fondamentale del sistema di layout è il posizionamento relativo che aumenta la capacità di adattamento a condizioni di finestre e visualizzazione mutevoli. Il sistema di layout gestisce inoltre la negoziazione tra i controlli per determinare il layout. La negoziazione è un processo a due fasi in cui innanzitutto un controllo indica il percorso e le dimensioni richieste alla relativa entità principale, quindi l'entità principale indica lo spazio disponibile al controllo.

Il sistema di layout viene esposto ai controlli figlio tramite le classi base di WPF. Per layout comuni, ad esempio griglie, sovrapposizioni e ancoraggio, WPF include vari controlli di layout:

  • Canvas: i controlli figlio forniscono il proprio layout.

  • DockPanel: i controlli figlio sono allineati ai bordi del pannello.

  • Grid: i controlli figlio sono posizionati per righe e colonne.

  • StackPanel: i controlli figlio sono sovrapposti in verticale o in orizzontale.

  • VirtualizingStackPanel: i controlli figlio sono virtualizzati e disposti su una sola riga orientata in senso orizzontale o verticale.

  • WrapPanel: i controlli figlio sono posizionati in ordine da sinistra a destra e mandati a capo quando sulla riga corrente sono presenti troppi controlli rispetto allo spazio disponibile.

L'esempio seguente descrive come usare un oggetto DockPanel per applicare il layout a più controlli TextBox:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.LayoutWindow"
    Title="Layout with the DockPanel" Height="143" Width="319">
  
  <!--DockPanel to layout four text boxes--> 
  <DockPanel>
    <TextBox DockPanel.Dock="Top">Dock = "Top"</TextBox>
    <TextBox DockPanel.Dock="Bottom">Dock = "Bottom"</TextBox>
    <TextBox DockPanel.Dock="Left">Dock = "Left"</TextBox>
    <TextBox Background="White">This TextBox "fills" the remaining space.</TextBox>
  </DockPanel>

</Window>

DockPanel consente ai controlli TextBox figlio di indicare la modalità di disposizione. A tale scopo, DockPanel implementa una proprietà associata Dock esposta ai controlli figlio per consentire a ognuno di essi di specificare uno stile di ancoraggio.

Nota

Una proprietà implementata da un controllo padre per essere usata dai controlli figlio è un costrutto di WPF denominato proprietà associata.

La figura seguente illustra il risultato del markup XAML dell'esempio precedente:

DockPanel page

Data binding

La maggior parte delle applicazioni viene creata per consentire agli utenti di visualizzare e modificare i dati. Per le applicazioni WPF, le operazioni di archiviazione e accesso ai dati sono fornite da tecnologie quali SQL Server e ADO.NET. Dopo l'accesso ai dati e il loro caricamento negli oggetti gestiti di un'applicazione, ha inizio la fase più complessa delle applicazioni WPF. Questa fase comporta essenzialmente due punti:

  1. Copia dei dati dagli oggetti gestiti ai controlli, per consentirne la visualizzazione e la modifica.

  2. Verifica che le modifiche apportate ai dati usando i controlli vengano copiate negli oggetti gestiti.

Per semplificare lo sviluppo delle applicazioni, in WPF è disponibile un motore di data binding per eseguire automaticamente queste operazioni. L'unità principale di questo motore è la classe Binding , il cui scopo è associare un controllo (destinazione) a un oggetto dati (origine). La figura seguente illustra questa relazione:

Basic data binding diagram

L'esempio seguente descrive come associare un oggetto TextBox a un'istanza di un oggetto Person personalizzato. L'esempio di codice seguente mostra l'implementazione di Person:

Namespace SDKSample

    Class Person

        Private _name As String = "No Name"

        Public Property Name() As String
            Get
                Return _name
            End Get
            Set(ByVal value As String)
                _name = value
            End Set
        End Property

    End Class

End Namespace
namespace SDKSample
{
    class Person
    {
        string name = "No Name";

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
    }
}

Il markup seguente associa l'oggetto a un'istanza TextBox di un oggetto personalizzato Person :

 <Window
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     x:Class="SDKSample.DataBindingWindow">

   <!-- Bind the TextBox to the data source (TextBox.Text to Person.Name) -->
   <TextBox Name="personNameTextBox" Text="{Binding Path=Name}" />

 </Window>
Imports System.Windows ' Window

Namespace SDKSample

    Partial Public Class DataBindingWindow
        Inherits Window

        Public Sub New()
            InitializeComponent()

            ' Create Person data source
            Dim person As Person = New Person()

            ' Make data source available for binding
            Me.DataContext = person

        End Sub

    End Class

End Namespace
using System.Windows; // Window

namespace SDKSample
{
    public partial class DataBindingWindow : Window
    {
        public DataBindingWindow()
        {
            InitializeComponent();

            // Create Person data source
            Person person = new Person();

            // Make data source available for binding
            this.DataContext = person;
        }
    }
}

In questo esempio viene creata un'istanza della classe Person in code-behind e viene impostata come contesto dei dati per l'oggetto DataBindingWindow. Nel markup la proprietà Text dell'oggetto TextBox è associata alla proprietà Person.Name per mezzo della sintassi XAML "{Binding ... }". Questo codice XAML comunica a WPF di associare il controllo TextBox all'oggetto Person archiviato nella proprietà DataContext della finestra.

Il motore di data binding di WPF offre supporto aggiuntivo che include convalida, ordinamento, filtro e raggruppamento. Il data binding supporta anche l'uso di modelli di dati per creare un'interfaccia utente personalizzata per i dati associati quando l'interfaccia utente visualizzata dai controlli WPF standard non è adatta.

Per altre informazioni, vedere Panoramica sul data binding.

Grafica

In WPF è disponibile un set completo, scalabile e flessibile di funzionalità grafiche che offrono i vantaggi seguenti:

  • Grafica indipendente dalla risoluzione e dal dispositivo. L'unità di misura di base nel sistema grafico di WPF è il Device Independent Pixel, pari a 1/96 di pollice, indipendentemente dall'effettiva risoluzione dello schermo, che costituisce la base per il rendering indipendente dalla risoluzione e dal dispositivo. Ogni Device Independent Pixel viene ridimensionato automaticamente in modo da corrispondere all'impostazione in punti per pollice (dpi) del sistema in cui viene eseguito il rendering.

  • Maggiore precisione. Il sistema di coordinate WPF viene misurato con numeri a virgola mobile a precisione doppia anziché a precisione singola. Anche i valori di opacità e delle trasformazioni vengono espressi come precisione doppia. WPF supporta anche un'ampia gamma di colori (scRGB) e offre il supporto integrato per la gestione di input da spazi colore diversi.

  • Grafica e supporto dell'animazione avanzati. WPF semplifica la programmazione grafica. Grazie alla gestione automatica delle scene di animazione, infatti, non occorre preoccuparsi dell'elaborazione delle scene, dei cicli di rendering e dell'interpolazione bilineare. In WPF è anche disponibile il supporto per hit testing e composizione alfa completa.

  • Accelerazione hardware. Il sistema grafico di WPF sfrutta i vantaggi dei componenti hardware grafici per ridurre al minimo l'uso della CPU.

Forme 2D

In WPF è disponibile una libreria di forme 2D comuni disegnate da vettori, ad esempio i rettangoli e le ellissi mostrati nella figura seguente:

Ellipses and rectangles

La caratteristica interessante delle forme è che non vengono usate solo per la visualizzazione. Le forme, infatti, implementano molte delle funzionalità fornite dai controlli, incluso l'input della tastiera e del mouse. L'esempio seguente mostra l'evento MouseUp di un Ellipse oggetto gestito:

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.EllipseEventHandlingWindow"
    Title="Click the Ellipse">
    <Ellipse Name="clickableEllipse" Fill="Blue" MouseUp="clickableEllipse_MouseUp" />
</Window>
Imports System.Windows ' Window, MessageBox
Imports System.Windows.Input ' MouseButtonEventArgs

Namespace SDKSample

    Public Class EllipseEventHandlingWindow
        Inherits Window

        Public Sub New()
            InitializeComponent()
        End Sub

        Private Sub clickableEllipse_MouseUp(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
            MessageBox.Show("You clicked the ellipse!")
        End Sub

    End Class

End Namespace
using System.Windows; // Window, MessageBox
using System.Windows.Input; // MouseButtonEventHandler

namespace SDKSample
{
    public partial class EllipseEventHandlingWindow : Window
    {
        public EllipseEventHandlingWindow()
        {
            InitializeComponent();
        }

        void clickableEllipse_MouseUp(object sender, MouseButtonEventArgs e)
        {
            // Display a message
            MessageBox.Show("You clicked the ellipse!");
        }
    }
}

La figura seguente illustra cosa viene prodotto dal codice precedente:

A window with the text

Per altre informazioni, vedere Cenni preliminari sugli oggetti Shape e sulle funzionalità di disegno di base di WPF.

Geometrie 2D

Le forme 2D disponibili in WPF coprono il set standard di forme di base. Può tuttavia essere necessario creare forme personalizzate per semplificare la progettazione di un'interfaccia utente personalizzata. A questo scopo, in WPF sono disponibili le geometrie. La figura seguente illustra come usare le geometrie per creare una forma personalizzata che può essere disegnata direttamente o usata come pennello o per ritagliare altre forme e controlli.

Gli oggettiPath possono essere usati per disegnare forme chiuse o aperte, più forme e anche forme curve.

Gli oggetti Geometry possono essere usati per ritagliare ed eseguire hit testing e rendering di dati grafici 2D.

Various uses of a path

Per altre informazioni, vedere Cenni preliminari sulle classi Geometry.

Effetti 2D

Un subset di funzionalità 2D di WPF include effetti visivi, ad esempio sfumature, bitmap, disegni, disegni con video, rotazione, ridimensionamento e inclinazione. Questi sono tutti ottenuti con pennelli; la figura seguente illustra alcuni esempi:

Illustration of different brushes

Per altre informazioni, vedere Cenni preliminari sui pennelli di WPF.

Rendering 3D

WPF include anche funzionalità di rendering 3D che si integrano con la grafica 2D per consentire la creazione di interfacce utente più accattivanti ed efficaci. La figura seguente, ad esempio, illustra immagini 2D di cui è stato eseguito il rendering in forme 3D:

Visual3D sample screen shot

Per altre informazioni, vedere Cenni preliminari sulla grafica tridimensionale.

Animazione

Il supporto di animazione di WPF consente di fare crescere, muovere, ruotare e dissolvere i controlli per creare interessanti transizioni di pagina e altro ancora. È possibile animare la maggior parte delle classi WPF, anche quelle personalizzate. La figura seguente illustra una semplice animazione in azione:

Images of an animated cube

Per altre informazioni, vedere Cenni preliminari sull'animazione.

Elementi multimediali

L'uso di supporti audiovisivi è un modo per inserire contenuto dettagliato. WPF offre un supporto speciale per immagini, video e audio.

Immagini

Le immagini sono comuni alla maggior parte delle applicazioni e in WPF possono essere usate in diversi modi. La figura seguente illustra un'interfaccia utente con una casella di riepilogo che contiene immagini di anteprima. Quando si seleziona un'anteprima, l'immagine viene visualizzata ingrandita.

Thumbnail images and a full-size image

Per altre informazioni, vedere Cenni preliminari sulla creazione dell'immagine.

Video e audio

Il controllo MediaElement consente di riprodurre video e audio e, grazie alle caratteristiche di flessibilità, può essere usato come base per un lettore multimediale personalizzato. Il markup XAML seguente implementa un lettore multimediale:

<MediaElement 
  Name="myMediaElement" 
  Source="media/wpf.wmv" 
  LoadedBehavior="Manual" 
  Width="350" Height="250" />

La finestra nella figura seguente mostra il MediaElement controllo in azione:

A MediaElement control with audio and video

Per altre informazioni, vedere Grafica e funzionalità multimediali.

Testo e tipografia

Per semplificare il rendering di testo di alta qualità, WPF offre le funzionalità seguenti:

  • Supporto dei tipi di carattere OpenType

  • Miglioramenti di ClearType.

  • Prestazioni elevate che sfruttano i vantaggi dell'accelerazione hardware.

  • Integrazione del testo con elementi multimediali, grafica e animazione.

  • Supporto dei tipi di carattere internazionali e meccanismi di fallback.

La figura seguente illustra l'applicazione di decorazioni di testo per dimostrare l'integrazione di testo e grafica:

Text with various text decorations

Per altre informazioni, vedere Funzionalità tipografiche di WPF.

Personalizzazione delle applicazioni WPF

Finora, sono stati presentati i blocchi di compilazione principali di WPF per lo sviluppo di applicazioni. Il modello di applicazione viene usato per ospitare e fornire contenuto di applicazione, costituito principalmente da controlli. Per semplificare la disposizione dei controlli in un'interfaccia utente e per mantenere tale disposizione anche in caso di modifiche alle dimensioni della finestra e alle impostazioni di visualizzazione, viene usato il sistema di layout di WPF. Poiché la maggior parte delle applicazioni consente agli utenti di interagire con i dati, per ridurre le operazioni di integrazione dell'interfaccia utente con i dati viene usato il data binding. Per migliorare l'aspetto visivo dell'applicazione, è possibile usare una gamma completa di grafica, animazione ed elementi multimediali disponibili in WPF.

Spesso, tuttavia, le funzionalità di base non sono sufficienti per creare e gestire applicazioni davvero uniche e visivamente sorprendenti per gli utenti. I controlli WPF standard potrebbero non integrarsi con l'aspetto desiderato dell'applicazione. I dati potrebbero non essere visualizzati nel modo più efficace. L'esperienza utente complessiva di un'applicazione può non essere adeguata all'aspetto dei temi di Windows. Per una tecnologia di presentazione è necessaria l'estendibilità visiva, tanto quanto altri tipi di estendibilità.

Per questo motivo, WPF offre una varietà di meccanismi per la creazione di esperienze utente univoche, incluso un modello di contenuto dettagliato per controlli, trigger, modelli di controllo e di dati, stili, risorse dell'interfaccia utente, temi e interfacce.

Modello di contenuto

Lo scopo principale di gran parte dei controlli di WPF è quello di visualizzare il contenuto. In WPF il tipo e il numero di elementi che possono costituire il contenuto di un controllo è indicato come modello di contenutodel controllo. Alcuni controlli possono contenere un solo elemento e tipo di contenuto. Ad esempio, il contenuto di un oggetto TextBox è un valore stringa assegnato alla proprietà Text . Nell'esempio seguente viene impostato il contenuto di un oggetto TextBox:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.TextBoxContentWindow"
    Title="TextBox Content">

    <TextBox Text="This is the content of a TextBox." />
</Window>

La figura seguente mostra il risultato:

A TextBox control that contains text

Gli altri controlli, tuttavia, possono contenere più elementi di tipi diversi di contenuto. Il contenuto di un oggetto Button, specificato dalla proprietà Content, può contenere vari elementi, inclusi i controlli di layout, testo, immagini e forme. Nell'esempio seguente viene illustrato un Button oggetto con contenuto che include un DockPaneloggetto , Labelun , un Bordere un MediaElementoggetto :

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.ButtonContentWindow"
    Title="Button Content">

  <Button Margin="20">
    <!-- Button Content -->
    <DockPanel Width="200" Height="180">
      <Label DockPanel.Dock="Top" HorizontalAlignment="Center">Click Me!</Label>
      <Border Background="Black" BorderBrush="Yellow" BorderThickness="2"
        CornerRadius="2" Margin="5">
        <MediaElement Source="media/wpf.wmv" Stretch="Fill" />
      </Border>
    </DockPanel>
  </Button>
</Window>

La figura seguente mostra il contenuto di questo pulsante:

A button that contains multiple types of content

Per altre informazioni sui tipi di contenuto supportati dai vari controlli, vedere Modello di contenuto WPF.

Trigger

Anche se lo scopo principale del markup XAML consiste nell'implementare l'aspetto di un'applicazione, è anche possibile usare XAML per implementare alcuni aspetti del comportamento di un'applicazione. Un esempio è dato dall'uso dei trigger per modificare l'aspetto di un'applicazione in base alle interazioni dell'utente. Per altre informazioni, vedere Stili e modelli.

Modelli di controllo

Le interfacce utente predefinite per i controlli WPF sono in genere costituite da altri controlli e forme. Ad esempio, un oggetto Button è composto da entrambi i controlli ButtonChrome e ContentPresenter . ButtonChrome fornisce l'aspetto del pulsante standard, mentre ContentPresenter consente di visualizzare il contenuto del pulsante, come specificato dalla proprietà Content .

A volte l'aspetto predefinito di un controllo può non essere coerente con l'aspetto complessivo di un'applicazione. In tal caso, è possibile usare un oggetto ControlTemplate per modificare l'aspetto dell'interfaccia utente del controllo senza modificarne il contenuto e il comportamento.

Nell'esempio seguente viene illustrato come modificare l'aspetto di un Button oggetto usando un ControlTemplateoggetto :

<Window 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.ControlTemplateButtonWindow"
  Title="Button with Control Template" Height="158" Width="290">

  <!-- Button using an ellipse -->
  <Button Content="Click Me!" Click="button_Click">
    <Button.Template>
      <ControlTemplate TargetType="{x:Type Button}">
        <Grid Margin="5">
          <Ellipse Stroke="DarkBlue" StrokeThickness="2">
            <Ellipse.Fill>
              <RadialGradientBrush Center="0.3,0.2" RadiusX="0.5" RadiusY="0.5">
                <GradientStop Color="Azure" Offset="0.1" />
                <GradientStop Color="CornflowerBlue" Offset="1.1" />
              </RadialGradientBrush>
            </Ellipse.Fill>
          </Ellipse>
          <ContentPresenter Name="content" HorizontalAlignment="Center" 
            VerticalAlignment="Center"/>
        </Grid>
      </ControlTemplate>
    </Button.Template>

  </Button>

</Window>
using System.Windows; // Window, RoutedEventArgs, MessageBox

namespace SDKSample
{
    public partial class ControlTemplateButtonWindow : Window
    {
        public ControlTemplateButtonWindow()
        {
            InitializeComponent();
        }

        void button_Click(object sender, RoutedEventArgs e)
        {
            // Show message box when button is clicked
            MessageBox.Show("Hello, Windows Presentation Foundation!");
        }
    }
}
Imports System.Windows ' Window, RoutedEventArgs, MessageBox

Namespace SDKSample

    Public Class ControlTemplateButtonWindow
        Inherits Window

        Public Sub New()

            InitializeComponent()

        End Sub

        Private Sub button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            MessageBox.Show("Hello, Windows Presentation Foundation!")
        End Sub

    End Class

End Namespace

In questo esempio, l'interfaccia utente predefinita del pulsante è stata sostituita con un oggetto Ellipse che presenta un bordo blu scuro e viene riempito con un oggetto RadialGradientBrush. Il ContentPresenter controllo visualizza il contenuto di Button, "Click Me!" Button Quando si fa clic su , l'evento Click viene comunque generato come parte del Button comportamento predefinito del controllo. Il risultato è illustrato nella figura seguente:

An elliptical button and a second window

Modelli di dati

Mentre un modello di controllo consente di specificare l'aspetto di un controllo, un modello di dati consente di specificare l'aspetto del contenuto di un controllo. I modelli di dati sono spesso usati per migliorare la modalità di visualizzazione dei dati associati. La figura seguente illustra l'aspetto predefinito per un oggetto ListBox associato a una raccolta di oggetti Task, dove ogni attività ha un nome, una descrizione e una priorità:

A list box with the default appearance

L'aspetto predefinito è quello previsto per un oggetto ListBox. L'aspetto predefinito di ciascuna attività, tuttavia, contiene solo il nome dell'attività. Per visualizzare il nome, la descrizione e la priorità di un'attività, è necessario modificare l'aspetto predefinito degli elementi elenco associati del controllo ListBox usando un oggetto DataTemplate. Il codice XAML seguente definisce tale , DataTemplateche viene applicato a ogni attività usando l'attributo ItemTemplate :

<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.DataTemplateWindow"
  Title="With a Data Template">
  <Window.Resources>
    <!-- Data Template (applied to each bound task item in the task collection) -->
    <DataTemplate x:Key="myTaskTemplate">
      <Border Name="border" BorderBrush="DarkSlateBlue" BorderThickness="2"
        CornerRadius="2" Padding="5" Margin="5">
        <Grid>
          <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
          </Grid.RowDefinitions>
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <TextBlock Grid.Row="0" Grid.Column="0" Padding="0,0,5,0" Text="Task Name:"/>
          <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=TaskName}"/>
          <TextBlock Grid.Row="1" Grid.Column="0" Padding="0,0,5,0" Text="Description:"/>
          <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=Description}"/>
          <TextBlock Grid.Row="2" Grid.Column="0" Padding="0,0,5,0" Text="Priority:"/>
          <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path=Priority}"/>
        </Grid>
      </Border>
    </DataTemplate>
  </Window.Resources>

  <!-- UI -->
  <DockPanel>
    <!-- Title -->
    <Label DockPanel.Dock="Top" FontSize="18" Margin="5" Content="My Task List:"/>

    <!-- Data template is specified by the ItemTemplate attribute -->
    <ListBox
      ItemsSource="{Binding}"
      ItemTemplate="{StaticResource myTaskTemplate}"
      HorizontalContentAlignment="Stretch"
      IsSynchronizedWithCurrentItem="True"
      Margin="5,0,5,5" />

 </DockPanel>
</Window>

La figura seguente illustra l'effetto di questo codice:

List box that uses a data template

Si noti che ListBox mantiene il proprio comportamento e l'aspetto complessivo. Solo l'aspetto del contenuto visualizzato dalla casella di riepilogo viene modificato.

Per altre informazioni, vedere Cenni preliminari sui modelli di dati.

Stili

Gli stili consentono agli sviluppatori e ai progettisti di standardizzare un determinato aspetto del prodotto. WPF offre un modello di stile avanzato, basato sull'elemento Style . Nell'esempio seguente viene creato uno stile che imposta il colore di sfondo per ogni Button oggetto di una finestra su Orange:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.StyleWindow"
    Title="Styles">
    
    <Window.Resources>
        <!-- Style that will be applied to all buttons for this window -->
        <Style TargetType="{x:Type Button}">
            <Setter Property="Background" Value="Orange" />
            <Setter Property="BorderBrush" Value="Crimson" />
            <Setter Property="FontSize" Value="20" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="Margin" Value="5" />
        </Style>
    </Window.Resources>
    <StackPanel>

        <!-- This button will have the style applied to it -->
        <Button>Click Me!</Button>

        <!-- This label will not have the style applied to it -->
        <Label>Don't Click Me!</Label>

        <!-- This button will have the style applied to it -->
        <Button>Click Me!</Button>
        
    </StackPanel>
</Window>

Poiché lo stile ha come destinazione tutti i controlli Button, viene applicato automaticamente a tutti i pulsanti nella finestra, come illustrato nella figura seguente:

Two orange buttons

Per altre informazioni, vedere Stili e modelli.

Risorse

I controlli di un'applicazione devono condividere lo stesso aspetto, che può includere qualsiasi elemento dai tipi di carattere e i colori di sfondo ai modelli di controllo e di dati, agli stili. È possibile usare il supporto WPF per le risorse dell'interfaccia utente per incapsulare queste risorse in un'unica posizione e permettere di usarle nuovamente.

L'esempio seguente definisce un colore di sfondo comune condiviso da un oggetto Button e un oggetto Label:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.ResourcesWindow"
    Title="Resources Window">

  <!-- Define window-scoped background color resource -->
  <Window.Resources>
    <SolidColorBrush x:Key="defaultBackground" Color="Red" />
  </Window.Resources>

  <!-- Button background is defined by window-scoped resource -->
  <Button Background="{StaticResource defaultBackground}">One Button</Button>

  <!-- Label background is defined by window-scoped resource -->
  <Label Background="{StaticResource defaultBackground}">One Label</Label>
</Window>

Questo esempio implementa una risorsa di colore di sfondo usando l'elemento della proprietà Window.Resources . Questa risorsa è disponibile per tutti gli elementi figlio dell'oggetto Window. Sono disponibili vari ambiti di risorsa, inclusi quelli riportati di seguito, elencati nell'ordine in cui vengono risolti:

  1. Un singolo controllo (che usa la proprietà System.Windows.FrameworkElement.Resources ereditata).

  2. Un oggetto Window o Page (che usa la proprietà System.Windows.FrameworkElement.Resources ereditata).

  3. Un oggetto Application (che usa la proprietà System.Windows.Application.Resources ).

La varietà degli ambiti offre flessibilità riguardo alla modalità di definizione e condivisione delle risorse.

In alternativa all'associazione diretta delle risorse a un determinato ambito, è possibile comprimere una o più risorse usando un oggetto ResourceDictionary separato a cui è possibile fare riferimento in altre parti di un'applicazione. L'esempio seguente, ad esempio, definisce un colore di sfondo predefinito in un dizionario risorse:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <!-- Define background color resource -->
  <SolidColorBrush x:Key="defaultBackground" Color="Red" />

  <!-- Define other resources -->
</ResourceDictionary>

L'esempio seguente fa riferimento al dizionario risorse definito nell'esempio precedente in modo che venga condiviso in un'applicazione:

<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.App">

  <Application.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="BackgroundColorResources.xaml"/>
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Application.Resources>
</Application>

Risorse e dizionari risorse sono la base del supporto di WPF per temi e interfacce.

Per altre informazioni, vedere Risorse.

Controlli personalizzati

Anche se WPF offre un ampio supporto per la personalizzazione, in alcune situazioni i controlli di WPF esistenti potrebbero non soddisfare le necessità di un'applicazione o degli utenti. Questo può verificarsi nei casi seguenti:

  • Non è possibile creare l'interfaccia utente richiesta personalizzando l'aspetto delle implementazioni di WPF esistenti.

  • Il comportamento richiesto non è supportato (o non è supportato facilmente) dalle implementazioni di WPF esistenti.

A questo punto, è tuttavia possibile sfruttare uno dei tre modelli di WPF per creare un nuovo controllo. Ogni modello è destinato a uno scenario specifico e richiede che il controllo personalizzato derivi da una determinata classe di base di WPF. I tre modelli sono elencati di seguito:

  • Modello di controllo utente. Un controllo personalizzato deriva da UserControl ed è composto da uno o più controlli.

  • Modello di controllo. Un controllo personalizzato deriva da Control e viene usato per compilare implementazioni che separano il comportamento dall'aspetto tramite modelli, come la maggior parte dei controlli di WPF. La derivazione da Control consente una maggiore libertà nella creazione di un'interfaccia utente personalizzata rispetto ai controlli utente, ma può risultare più complessa.

  • Modello di elemento framework. Un controllo personalizzato deriva da FrameworkElement quando il suo aspetto è definito da logica di rendering personalizzata (non dai modelli).

L'esempio seguente mostra un controllo numerico personalizzato su/giù che deriva da UserControl:

<UserControl
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.NumericUpDown">

  <Grid>

    <Grid.RowDefinitions>
      <RowDefinition/>
      <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition/>
      <ColumnDefinition/>
    </Grid.ColumnDefinitions>

    <!-- Value text box -->
    <Border BorderThickness="1" BorderBrush="Gray" Margin="2" Grid.RowSpan="2" 
      VerticalAlignment="Center" HorizontalAlignment="Stretch">
      <TextBlock Name="valueText" Width="60" TextAlignment="Right" Padding="5"/>
    </Border>

    <!-- Up/Down buttons -->
    <RepeatButton Name="upButton" Click="upButton_Click" Grid.Column="1" 
      Grid.Row="0">Up</RepeatButton>
    <RepeatButton Name="downButton" Click="downButton_Click" Grid.Column="1" 
      Grid.Row="1">Down</RepeatButton>

  </Grid>

</UserControl>
using System; // EventArgs
using System.Windows; // DependencyObject, DependencyPropertyChangedEventArgs,
                      // FrameworkPropertyMetadata, PropertyChangedCallback,
                      // RoutedPropertyChangedEventArgs
using System.Windows.Controls; // UserControl

namespace SDKSample
{
    public partial class NumericUpDown : UserControl
    {
        // NumericUpDown user control implementation
    }
}
imports System 'EventArgs
imports System.Windows 'DependencyObject, DependencyPropertyChangedEventArgs, 
                       ' FrameworkPropertyMetadata, PropertyChangedCallback, 
                       ' RoutedPropertyChangedEventArgs
imports System.Windows.Controls 'UserControl

Namespace SDKSample

    ' Interaction logic for NumericUpDown.xaml
    Partial Public Class NumericUpDown
        Inherits System.Windows.Controls.UserControl

        'NumericUpDown user control implementation

    End Class

End Namespace

L'esempio seguente illustra il codice XAML necessario per incorporare il controllo utente in un Windowoggetto :

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.UserControlWindow"
    xmlns:local="clr-namespace:SDKSample" 
    Title="User Control Window">

  <!-- Numeric Up/Down user control -->
  <local:NumericUpDown />

</Window>

La figura seguente mostra il NumericUpDown controllo ospitato in un Windowoggetto :

A custom UserControl

Per altre informazioni sui controlli personalizzati, vedere Cenni preliminari sulla modifica di controlli.

Procedure consigliate di WPF

Come per qualsiasi piattaforma di sviluppo, è possibile usare WPF in diversi modi per ottenere il risultato desiderato. Per creare applicazioni WPF capaci di fornire l'esperienza utente richiesta e soddisfare le esigenze generali dei destinatari, ci sono procedure consigliate per l'accessibilità, la globalizzazione e localizzazione e le prestazioni. Per altre informazioni, vedere:

Passaggi successivi

Abbiamo esaminato le funzionalità chiave di WPF. Adesso è necessario compilare la prima applicazione WPF.

Vedi anche