Panoramica di WPF
Windows Presentation Foundation (WPF) consente di creare applicazioni client desktop per Windows con esperienze utente visivamente straordinarie.
Il core di WPF è un motore di rendering indipendente dalla risoluzione e basato su vettori creato per sfruttare i vantaggi dell'hardware grafico moderno. WPF estende il core con un set completo di funzionalità di sviluppo di applicazioni che includono XAML (Extensible Application Markup Language), controlli, data binding, layout, grafica 2D e 3D, animazione, stili, modelli, documenti, supporti, testo e tipografia. WPF fa parte di .NET, quindi è possibile compilare applicazioni che incorporano altri elementi dell'API .NET.
Questa panoramica è destinata ai nuovi arrivati e illustra le funzionalità e i concetti chiave di WPF.
Programmare con WPF
WPF esiste come un sottoinsieme di tipi di .NET che, per la maggior parte, si trovano nello spazio dei nomi System.Windows. Se in precedenza sono state compilate applicazioni con .NET usando tecnologie gestite come ASP.NET e Windows Form, l'esperienza di programmazione WPF fondamentale dovrebbe essere familiare; è possibile creare un'istanza 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à e eventi: proprietà di dipendenza e eventi instradati.
Markup e codice sottostante
WPF consente di sviluppare un'applicazione usando sia markup che code-behind, un'esperienza con cui gli sviluppatori ASP.NET devono avere familiarità. In genere si usa il markup XAML per implementare l'aspetto di un'applicazione usando linguaggi di programmazione gestiti (code-behind) per implementarne il comportamento. Questa separazione dell'aspetto e del comportamento presenta i vantaggi seguenti:
I costi di sviluppo e manutenzione sono ridotti perché il markup specifico dell'aspetto non è strettamente associato al codice del comportamento.
Lo sviluppo è più efficiente perché i progettisti possono implementare l'aspetto di un'applicazione contemporaneamente agli sviluppatori che implementano il comportamento dell'applicazione.
di globalizzazione e localizzazione per le applicazioni WPF è semplificata.
Marcatura
XAML è un linguaggio di markup basato su XML che implementa l'aspetto di un'applicazione in modo dichiarativo. In genere viene usato per creare finestre, finestre di dialogo, pagine e controlli utente e per riempirli con controlli, forme e grafica.
L'esempio seguente usa XAML per implementare l'aspetto di una finestra che contiene un singolo 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 usando rispettivamente gli elementi Window
e Button
. Ogni elemento viene configurato con attributi, ad esempio l'attributo Title
dell'elemento Window
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 mostra l'interfaccia utente definita dal codice XAML nell'esempio precedente:
Poiché XAML è basato su XML, l'interfaccia utente che componi con esso è assemblata in una gerarchia di elementi annidati noti come albero degli elementi . L'albero degli elementi offre un modo logico e intuitivo per creare e gestire interfacce utente.
Codice dietro
Il comportamento principale di un'applicazione consiste nell'implementare le funzionalità che rispondono alle interazioni dell'utente, tra cui la gestione degli eventi (ad esempio, facendo clic su un menu, una barra degli strumenti o un pulsante) e chiamando la logica di business e la logica di accesso ai dati in risposta. In WPF questo comportamento viene implementato nel codice associato al 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
assicura che l'implementazione venga inizializzata correttamente quando viene creata. La classe code-behind implementa anche un gestore eventi per l'evento Click del pulsante. Quando si fa clic sul pulsante, il gestore eventi visualizza una finestra di messaggio chiamando il metodo System.Windows.MessageBox.Show.
La figura seguente mostra il risultato quando si fa clic sul pulsante:
riquadro di messaggio
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 in una pagina, hanno un'interfaccia utente e implementano un comportamento.
Per altre informazioni, vedere Controlli.
Controlli WPF per funzione
I controlli WPF predefiniti sono elencati di seguito:
pulsanti: Button e RepeatButton.
visualizzazione e selezione della data: Calendar e DatePicker.
finestre di dialogo: OpenFileDialog, PrintDialoge SaveFileDialog.
Digital Ink: InkCanvas e InkPresenter.
Documenti: DocumentViewer, FlowDocumentPageViewer, FlowDocumentReader, FlowDocumentScrollViewere StickyNoteControl.
Input: TextBox, RichTextBoxe PasswordBox.
Layout: Border, BulletDecorator, Canvas, DockPanel, Expander, Grid, GridView, GridSplitter, GroupBox, Panel, ResizeGrip, Separator, ScrollBar, ScrollViewer, StackPanel, Thumb, Viewbox, VirtualizingStackPanel, Windowe WrapPanel.
Media: Image, MediaElemente SoundPlayerAction.
Menu : ContextMenu, Menue ToolBar.
navigazione: Frame, Hyperlink, Page, NavigationWindowe TabControl.
selezione: CheckBox, ComboBox, ListBox, RadioButtone Slider.
Informazioni utente: AccessText, Label, Popup, ProgressBar, StatusBar, TextBlocke ToolTip.
Input e comandi
I controlli rilevano e rispondono più spesso all'input dell'utente. Il sistema di input WPF utilizza sia eventi diretti che eventi instradati per supportare l'immissione di testo, la gestione dello stato attivo e il posizionamento del mouse.
Le applicazioni spesso hanno requisiti di input complessi. WPF fornisce un sistema di comandi che separa le azioni di input dell'utente dal codice che risponde a tali azioni.
Impaginazione
Quando si crea un'interfaccia utente, si dispone i controlli in base alla posizione e alle dimensioni per formare un layout. Un requisito fondamentale di qualsiasi layout consiste nell'adattarsi alle modifiche apportate alle dimensioni della finestra e alle impostazioni di visualizzazione. Anziché forzare la scrittura del codice per adattare un layout in queste circostanze, WPF offre automaticamente un sistema di layout estendibile di prima classe.
La pietra angolare del sistema di layout è il posizionamento relativo, che aumenta la capacità di adattarsi alla modifica della finestra e delle condizioni di visualizzazione. Inoltre, il sistema di layout gestisce la negoziazione tra i controlli per determinare il layout. La negoziazione è un processo in due passaggi: innanzitutto, un controllo indica al suo genitore la posizione e le dimensioni richieste; in secondo luogo, il genitore indica al controllo quale spazio può avere.
Il sistema di layout viene esposto ai controlli figlio tramite classi WPF di base. Per i layout comuni, come griglia, impilamento e ancoraggio, WPF include vari controlli di layout.
Canvas: i controlli secondari forniscono il proprio layout.
DockPanel: i controlli figlio sono allineati ai bordi del pannello.
Grid: i controlli figlio vengono posizionati in base a righe e colonne.
StackPanel: i controlli dei bambini vengono impilati verticalmente o orizzontalmente.
VirtualizingStackPanel: i controlli figlio vengono virtualizzati e disposti su una singola riga orientata orizzontalmente o verticalmente.
WrapPanel: i controlli figlio vengono posizionati nell'ordine da sinistra a destra e racchiusi nella riga successiva quando sono presenti più controlli sulla riga corrente rispetto allo spazio consentito.
Nell'esempio seguente viene usato un DockPanel per posizionare diversi 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>
Il DockPanel permette ai controlli del componente figlio TextBox di indicare come disporli. A tale scopo, il DockPanel implementa una proprietà associata Dock
che viene esposta ai controlli figlio per consentire a ciascuno di specificare uno stile di ancoraggio.
Nota
Una proprietà implementata da un controllo padre da utilizzare dai controlli figlio è un costrutto WPF denominato proprietà associata.
La figura seguente mostra il risultato del markup XAML nell'esempio precedente:
Associazione dei dati
La maggior parte delle applicazioni viene creata per fornire agli utenti i mezzi per visualizzare e modificare i dati. Per le applicazioni WPF, il lavoro di archiviazione e accesso ai dati è già disponibile per tecnologie come SQL Server e ADO .NET. Dopo l'accesso e il caricamento dei dati negli oggetti gestiti di un'applicazione, inizia il lavoro duro per le applicazioni WPF. In sostanza, questo comporta due aspetti:
Copia dei dati dagli oggetti gestiti in controlli, in cui è possibile visualizzare e modificare i dati.
Assicurarsi che le modifiche apportate ai dati usando i controlli vengano copiate nuovamente negli oggetti gestiti.
Per semplificare lo sviluppo di applicazioni, WPF fornisce un motore di data binding per eseguire automaticamente questi passaggi. L'unità principale del motore di associazione dati è la classe Binding, il cui processo consiste nell'associare un controllo (la destinazione di associazione) a un oggetto dati (origine di associazione). Questa relazione è illustrata nella figura seguente:
Nell'esempio seguente viene illustrato come associare un TextBox a un'istanza di un oggetto Person
personalizzato. L'implementazione Person
è illustrata nel codice seguente:
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 il TextBox a un'istanza di un oggetto Person
personalizzato:
<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 istanziata la classe Person
dal code-behind e viene impostata come contesto dati per il DataBindingWindow
. Nel markup, la proprietà Text del TextBox è associata alla proprietà Person.Name
(usando la sintassi XAML "{Binding ... }
"). Questo codice XAML indica a WPF di associare il controllo TextBox all'oggetto Person
archiviato nella proprietà DataContext della finestra.
Il motore di data binding WPF offre supporto aggiuntivo che include convalida, ordinamento, filtro e raggruppamento. Inoltre, il data binding supporta 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 è appropriata.
Per altre informazioni, vedere panoramica del data binding .
Grafica
WPF introduce un set completo, scalabile e flessibile di funzionalità grafiche con i vantaggi seguenti:
grafica indipendente dalla risoluzione e dal dispositivo. L'unità di misura di base nel sistema grafico WPF è il pixel indipendente dal dispositivo, che è 1/96 di pollice, indipendentemente dalla risoluzione effettiva dello schermo, e fornisce la base per il rendering indipendente dalla risoluzione e indipendente dal dispositivo. Ogni pixel indipendente dal dispositivo viene ridimensionato automaticamente in modo che corrisponda all'impostazione punti per pollice (dpi) del sistema su cui viene eseguito il rendering.
Precisione migliorata. Il sistema di coordinate WPF viene misurato con numeri a virgola mobile e precisione doppia anziché con precisione singola. Le trasformazioni e i valori di opacità sono espressi anche con doppia precisione. WPF supporta anche un'ampia gamma di colori (scRGB) e fornisce supporto integrato per la gestione degli input da spazi di colore diversi.
Supporto per la grafica avanzata e l'animazione. WPF semplifica la programmazione grafica gestendo le scene di animazione; non è necessario preoccuparsi dell'elaborazione della scena, dei cicli di rendering e dell'interpolazione bilineare. WPF offre inoltre supporto per hit testing e supporto per la composizione alfa completa.
Accelerazione hardware. Il sistema grafico WPF sfrutta l'hardware grafico per ridurre al minimo l'utilizzo della CPU.
Forme 2D
WPF offre una libreria di forme 2D comuni disegnate da vettori, ad esempio i rettangoli e i puntini di sospensione illustrati nella figura seguente:
Una funzionalità interessante delle forme è che non sono solo per la visualizzazione; le forme implementano molte delle funzionalità previste dai controlli, tra cui input da tastiera e mouse. Nell'esempio seguente viene mostrato come viene gestito l'evento MouseUp di un Ellipse.
<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:
Per altre informazioni, vedere Forme e disegno di base in WPF overview.
Geometrie 2D
Le forme 2D fornite da WPF coprono il set standard di forme di base. Tuttavia, potrebbe essere necessario creare forme personalizzate per facilitare la progettazione di un'interfaccia utente personalizzata. A questo scopo, WPF fornisce geometrie. La figura seguente illustra l'uso delle geometrie per creare una forma personalizzata che può essere disegnata direttamente, utilizzata come pennello o utilizzata per ritagliare altre forme e controlli.
Path oggetti possono essere utilizzati per disegnare forme chiuse o aperte, più forme e persino forme curve.
Geometry oggetti possono essere usati per ritagliare, verificare le collisioni e renderizzare dati grafici 2D.
Per ulteriori informazioni, vedere la panoramica della geometria .
Effetti 2D
Le funzionalità 2D di WPF comprendono effetti visivi, come sfumature, bitmap, disegni, pittura con video, rotazione, ridimensionamento e inclinazione. Questi sono tutti ottenuti con pennelli; la figura seguente illustra alcuni esempi:
Per ulteriori informazioni, vedere la panoramica sui pennelli WPF .
Rendering 3D
WPF include anche funzionalità di rendering 3D che si integrano con grafica 2D per consentire la creazione di interfacce utente più interessanti e interessanti. Ad esempio, la figura seguente mostra le immagini 2D di cui è stato eseguito il rendering in forme 3D:
Per altre informazioni, vedere panoramica della grafica 3D.
Animazione
Il supporto per le animazioni WPF consente di ingrandire, scuotere, ruotare e dissolvere i controlli, per creare transizioni di pagina interessanti e altro ancora. È possibile animare la maggior parte delle classi WPF, anche classi personalizzate. La figura seguente mostra un'animazione semplice in azione:
Per ulteriori informazioni, vedere la panoramica dell'animazione .
Media
Un modo per trasmettere contenuti ricchi è l'uso dei media audiovisivi. WPF offre supporto speciale per immagini, video e audio.
Immagini
Le immagini sono comuni alla maggior parte delle applicazioni e WPF offre diversi modi per usarle. La figura seguente mostra un'interfaccia utente con una casella di riepilogo contenente immagini di anteprima. Quando si seleziona un'anteprima, l'immagine viene visualizzata a dimensione intera.
Per altre informazioni, vedere panoramica dell'immagine .
Video e audio
Il controllo MediaElement è in grado di riprodurre sia video che audio ed è sufficientemente flessibile da essere la 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 controllo MediaElement in azione:
Per altre informazioni, vedere Elementi grafici e multimediali.
Testo e tipografia
Per facilitare 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 l'accelerazione hardware.
Integrazione del testo con elementi multimediali, grafici e animazioni.
Supporto dei tipi di carattere internazionale e meccanismi di fallback.
Come dimostrazione dell'integrazione del testo con la grafica, la figura seguente illustra l'applicazione delle decorazioni di testo:
Per altre informazioni, vedere tipografia in Windows Presentation Foundation.
Personalizzare le app WPF
Fino a questo punto, sono stati illustrati i blocchi predefiniti WPF principali per lo sviluppo di applicazioni. Si usa il modello di applicazione per ospitare e distribuire il contenuto dell'applicazione, costituito principalmente da controlli. Per semplificare la disposizione dei controlli in un'interfaccia utente e per garantire che la disposizione venga mantenuta in caso di modifiche alle impostazioni di visualizzazione e dimensioni della finestra, si usa il sistema di layout WPF. Poiché la maggior parte delle applicazioni consente agli utenti di interagire con i dati, è possibile usare il data binding per ridurre il lavoro di integrazione dell'interfaccia utente con i dati. Per migliorare l'aspetto visivo dell'applicazione, è possibile usare la gamma completa di grafica, animazione e supporto multimediale fornito da WPF.
Spesso, tuttavia, le nozioni di base non sono sufficienti per creare e gestire un'esperienza utente veramente distinta e visivamente straordinaria. 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 dell'applicazione potrebbe non essere adatta all'aspetto predefinito dei temi di Windows. In molti modi, una tecnologia di presentazione richiede estendibilità visiva tanto quanto qualsiasi altro tipo di estendibilità.
Per questo motivo, WPF offre un'ampia gamma di meccanismi per la creazione di esperienze utente univoche, tra cui un modello di contenuto avanzato per controlli, trigger, modelli di dati e controlli, stili, risorse dell'interfaccia utente e temi e interfacce.
Modello di contenuto
Lo scopo principale di una maggior parte dei controlli WPF è quello di visualizzare il contenuto. In WPF il tipo e il numero di elementi che possono costituire il contenuto di un controllo viene definito modello di contenuto del controllo. Alcuni controlli possono contenere un singolo elemento e un tipo di contenuto; Ad esempio, il contenuto di un TextBox è un valore stringa assegnato alla proprietà Text. Nell'esempio seguente viene impostato il contenuto di un 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:
Altri controlli, tuttavia, possono contenere più elementi di diversi tipi di contenuto; Il contenuto di un Button, specificato dalla proprietà Content, può contenere un'ampia gamma di elementi, tra cui controlli di layout, testo, immagini e forme. Nell'esempio seguente viene illustrato un Button con contenuto che include un DockPanel, un Label, un Bordere un MediaElement:
<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:
Per altre informazioni sui tipi di contenuto supportati da vari controlli, vedere modello di contenuto WPF.
Triggeri
Anche se lo scopo principale del markup XAML è implementare l'aspetto di un'applicazione, puoi anche usare XAML per implementare alcuni aspetti del comportamento di un'applicazione. Un esempio è l'uso di 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 vengono in genere costruite da altri controlli e forme. Ad esempio, un Button è composto sia da ButtonChrome che da controlli ContentPresenter. Il ButtonChrome fornisce l'aspetto standard del pulsante, mentre il ContentPresenter visualizza il contenuto del pulsante, come specificato dalla proprietà Content.
A volte l'aspetto predefinito di un controllo può essere incongruente con l'aspetto complessivo di un'applicazione. In questo caso, è possibile usare un 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 usando un ControlTemplate:
<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 del pulsante predefinita è stata sostituita da un Ellipse con un bordo blu scuro ed è riempita usando un RadialGradientBrush. Il controllo ContentPresenter visualizza il contenuto del Button, "Click Me!" Quando si fa clic sul Button, l'evento Click viene comunque generato come parte del comportamento predefinito del controllo Button. Il risultato è illustrato nella figura seguente:
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 vengono spesso usati per migliorare la modalità di visualizzazione dei dati associati. La figura seguente mostra l'aspetto predefinito di un ListBox associato a una raccolta di oggetti Task
, in cui ogni attività ha un nome, una descrizione e una priorità:
L'aspetto predefinito è ciò che ci si aspetterebbe da un ListBox. Tuttavia, l'aspetto predefinito di ogni attività contiene solo il nome dell'attività. Per visualizzare il nome, la descrizione e la priorità dell'attività, è necessario modificare l'aspetto predefinito degli elementi associati dell'elenco del controllo ListBox utilizzando un DataTemplate. Il codice XAML seguente definisce un DataTemplatecome questo, che 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:
Si noti che il ListBox ha mantenuto il suo comportamento e l'aspetto complessivo; solo l'aspetto del contenuto visualizzato dalla casella di riepilogo è cambiato.
Per altre informazioni, vedere la panoramica della modellazione dei dati .
Stili
Gli stili consentono agli sviluppatori e ai progettisti di standardizzare in base a un aspetto specifico per il prodotto. WPF offre un modello di stile sicuro, la cui base è l'elemento Style. Nell'esempio seguente viene creato uno stile che imposta il colore di sfondo per ogni Button in 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é questo stile è destinato a tutti i controlli Button, lo stile viene applicato automaticamente a tutti i pulsanti nella finestra, come illustrato nella figura seguente:
Per altre informazioni, vedere Stili e modelli.
Risorse
I controlli in un'applicazione devono condividere lo stesso aspetto, che può includere qualsiasi elemento, dai tipi di carattere e dai colori di sfondo ai modelli di controllo, ai modelli di dati e agli stili. È possibile usare il supporto di WPF per le risorse dell'interfaccia utente per incapsulare queste risorse in un'unica posizione per il riutilizzo.
Nell'esempio seguente viene definito un colore di sfondo comune condiviso da un Button e da un 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>
In questo esempio viene implementata una risorsa colore di sfondo usando la proprietà Window.Resources
. Questa risorsa è disponibile per tutti i bambini del Window. Esistono diversi ambiti di risorsa, inclusi i seguenti, elencati nell'ordine in cui vengono risolti:
Un controllo individuale (utilizzando la proprietà System.Windows.FrameworkElement.Resources ereditata).
Un Window o un Page (utilizzando anche la proprietà System.Windows.FrameworkElement.Resources ereditata).
Un Application (utilizzando la proprietà System.Windows.Application.Resources).
La varietà di ambiti offre flessibilità rispetto al modo in cui si definiscono e si condividono le risorse.
In alternativa all'associazione diretta delle risorse a un particolare ambito, è possibile creare un pacchetto di una o più risorse usando un 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>
Le risorse e i dizionari delle risorse sono la base del supporto WPF per i temi e le skin.
Per altre informazioni, vedere Risorse.
Controlli personalizzati
Sebbene WPF offra una serie di supporto per la personalizzazione, è possibile che si verifichino situazioni in cui i controlli WPF esistenti non soddisfano le esigenze dell'applicazione o dei relativi utenti. Questo problema può verificarsi quando:
L'interfaccia utente necessaria non può essere creata personalizzando l'aspetto delle implementazioni WPF esistenti.
Il comportamento richiesto non è supportato (o non facilmente supportato) dalle implementazioni WPF esistenti.
A questo punto, tuttavia, è possibile sfruttare uno dei tre modelli 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 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 creare implementazioni che separano il comportamento dal loro aspetto usando modelli, in modo analogo alla maggior parte dei controlli WPF. Derivare da Control ti permette maggiore libertà per creare un'interfaccia utente personalizzata rispetto ai controlli utente, ma potrebbe richiedere più impegno.
Modello di Elementi del Framework. Un controllo personalizzato deriva da FrameworkElement quando l'aspetto è definito dalla logica di rendering personalizzata (non dai modelli).
Nell'esempio seguente viene illustrato un controllo numerico personalizzato 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 Window:
<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>
Nella figura seguente viene illustrato il controllo NumericUpDown
ospitato in un Window:
un UserControl personalizzato
Per altre informazioni sui controlli personalizzati, vedere Panoramica sulla creazione di controlli.
Procedure consigliate per WPF
Come per qualsiasi piattaforma di sviluppo, WPF può essere usato in diversi modi per ottenere il risultato desiderato. Come modo per garantire che le applicazioni WPF forniscano l'esperienza utente necessaria e soddisfino le esigenze del pubblico in generale, esistono procedure consigliate per l'accessibilità, la globalizzazione e la localizzazione e le prestazioni. Per altre informazioni, vedere:
- accessibilità
- Globalizzazione e localizzazione WPF
- prestazioni dell'applicazione WPF
- sicurezza WPF
Passaggi successivi
Sono stati esaminati le funzionalità principali di WPF. È ora di creare la tua prima app WPF.
Vedere anche
.NET Desktop feedback