wpf
Introduzione al binding dei dati WPF
Ricerca…
Sintassi
- {Binding PropertyName} è equivalente a {Binding Path = PropertyName}
- {Binding Path = SomeProperty.SomeOtherProperty.YetAnotherProperty}
- {Binding Path = SomeListProperty [1]}
Parametri
Parametro | Dettagli |
---|---|
Sentiero | Specifica il percorso per associare a. Se non specificato, si collega a DataContext stesso. |
UpdateSourceTrigger | Specifica quando l'origine dell'associazione ha il suo valore aggiornato. Il valore predefinito è LostFocus . Il valore più utilizzato è PropertyChanged . |
Modalità | In genere OneWay o TwoWay . Se non specificato dal TwoWay viene TwoWay su OneWay meno che la destinazione vincolante non richieda che sia TwoWay . Si verifica un errore quando TwoWay viene utilizzato per collegarsi a una proprietà readonly, ad esempio OneWay deve essere impostato in modo esplicito quando si TextBox.Text una proprietà stringa di sola lettura a TextBox.Text . |
fonte | Consente l'utilizzo di StaticResource come origine di binding anziché DataContext corrente. |
RelativeSource | Consente l'utilizzo di un altro elemento XAML come origine di associazione anziché DataContext corrente. |
ElementName | Consente l'utilizzo di un elemento XAML denominato come origine di associazione anziché DataContext corrente. |
FallbackValue | Se l'associazione fallisce, questo valore viene fornito alla destinazione vincolante. |
TargetNullValue | Se il valore dell'origine dell'associazione è null , questo valore viene fornito alla destinazione vincolante. |
Converter | Specifica il convertitore StaticResource utilizzato per convertire il valore dell'associazione, ad esempio, converte un valore booleano in un elemento enumerazione Visibility . |
ConverterParameter | Specifica un parametro facoltativo da fornire al convertitore. Questo valore deve essere statico e non può essere associato. |
StringFormat | Specifica una stringa di formato da utilizzare quando si visualizza il valore associato. |
Ritardo | (WPF 4.5+) Specifica un ritardo in milliseconds affinché il binding aggiorni BindingSource in ViewModel . Deve essere utilizzato con Mode=TwoWay e UpdateSourceTrigger=PropertyChanged per avere effetto. |
Osservazioni
UpdateSourceTrigger
Per impostazione predefinita, WPF aggiorna l'origine dell'associazione quando il controllo perde lo stato attivo. Tuttavia, se esiste un solo controllo che può ottenere l' UpdateSourceTrigger=PropertyChanged
comune negli esempi, è necessario specificare UpdateSourceTrigger=PropertyChanged
perché gli aggiornamenti funzionino.
Vorrai utilizzare PropertyChanged
come trigger su molti collegamenti bidirezionali, a meno che l'aggiornamento dell'origine dell'assegnazione su ogni sequenza di tasti sia costoso o la convalida dei dati in tempo reale non sia desiderabile.
L'uso di LostFocus
ha uno sfortunato effetto collaterale: premendo Invio per inviare un modulo utilizzando un pulsante contrassegnato con IsDefault
non si aggiorna la proprietà di backup del binding, annullando in modo efficace le modifiche. Fortunatamente, esistono alcuni soluzioni alternative .
Si noti inoltre che, a differenza di UWP, WPF (4.5+) ha anche la proprietà Delay
in binding, che potrebbe essere sufficiente per alcuni binding con impostazioni di intelligenza minore solo locali o semplici, come alcune validazioni di TextBox
.
Converti un valore booleano in visibilità
Questo esempio nasconde il riquadro rosso (bordo) se la casella di controllo non è selezionata facendo uso di un IValueConverter
.
Nota: il BooleanToVisibilityConverter
utilizzato nell'esempio seguente è un convertitore di valori incorporato, ubicato nello spazio dei nomi System.Windows.Controls.
XAML:
<Window x:Class="StackOverflowDataBindingExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="VisibleIfTrueConverter" />
</Window.Resources>
<StackPanel>
<CheckBox x:Name="MyCheckBox"
IsChecked="True" />
<Border Background="Red" Width="20" Height="20"
Visibility="{Binding Path=IsChecked,ElementName=MyCheckBox, Converter={StaticResource VisibleIfTrueConverter}}" />
</StackPanel>
</Window>
Definizione del DataContext
Per lavorare con i binding in WPF, è necessario definire un DataContext . DataContext indica i collegamenti da cui ottenere i dati per impostazione predefinita.
<Window x:Class="StackOverflowDataBindingExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:StackOverflowDataBindingExample"
xmlns:vm="clr-namespace:StackOverflowDataBindingExample.ViewModels"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:HelloWorldViewModel />
</Window.DataContext>
...
</Window>
È inoltre possibile impostare DataContext tramite code-behind, ma vale la pena notare che XAML IntelliSense è piuttosto esigente: è necessario impostare DataContext fortemente tipizzato in XAML per IntelliSense per suggerire le proprietà disponibili per l'associazione.
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new HelloWorldViewModel();
}
}
Mentre ci sono framework per aiutarti a definire il tuo DataContext in un modo più flessibile (es. MVVM Light ha un viewmodel locator che usa l' inversione del controllo ), usiamo il metodo rapido e sporco ai fini di questo tutorial.
È possibile definire un DataContext per quasi tutti gli elementi visivi in WPF. DataContext è generalmente ereditato dagli antenati nella struttura ad albero visuale a meno che non sia stato esplicitamente ignorato, ad esempio all'interno di un ContentPresenter.
Implementazione di INotifyPropertyChanged
INotifyPropertyChanged
è un'interfaccia utilizzata dalle fonti di binding (ovvero il DataContext) per consentire all'interfaccia utente o ad altri componenti di sapere che una proprietà è stata modificata. WPF aggiorna automaticamente l'interfaccia utente quando rileva l'evento PropertyChanged
generato. È auspicabile che questa interfaccia sia implementata su una classe base che tutti i tuoi viewmodels possano ereditare.
In C # 6, questo è tutto ciò di cui hai bisogno:
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
Ciò consente di invocare NotifyPropertyChanged
in due modi diversi:
-
NotifyPropertyChanged()
, che genererà l'evento per il setter che lo invoca, grazie all'attributo CallerMemberName . -
NotifyPropertyChanged(nameof(SomeOtherProperty))
, che genererà l'evento per SomeOtherProperty.
Per .NET 4.5 e versioni successive con C # 5.0, è possibile utilizzare invece:
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] string name = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
Nelle versioni di .NET precedenti alla 4.5, è necessario accontentarsi dei nomi di proprietà come costanti di stringa o di una soluzione che utilizza espressioni .
Nota: è possibile associare a una proprietà di un "vecchio oggetto C # semplice" (POCO) che non implementa INotifyPropertyChanged
e osservare che le associazioni funzionano meglio del previsto. Questa è una funzionalità nascosta in .NET e dovrebbe probabilmente essere evitata. Soprattutto perché causerà perdite di memoria quando la Mode
di rilegatura non è OneTime
(vedi qui ).
Perché l'aggiornamento dell'associazione non implementa INotifyPropertyChanged?
Associare alla proprietà di un altro elemento denominato
È possibile associare a una proprietà su un elemento denominato, ma l'elemento denominato deve essere incluso nell'ambito.
<StackPanel>
<CheckBox x:Name="MyCheckBox" IsChecked="True" />
<TextBlock Text="{Binding IsChecked, ElementName=MyCheckBox}" />
</StackPanel>
Legarsi alla proprietà di un antenato
È possibile eseguire il binding a una proprietà di un antenato nell'albero visivo utilizzando un'associazione RelativeSource
. Il controllo più vicino più in alto nell'albero visivo che ha lo stesso tipo o è derivato dal tipo specificato verrà utilizzato come origine del legame:
<Grid Background="Blue">
<Grid Background="Gray" Margin="10">
<Border Background="Red" Margin="20">
<StackPanel Background="White" Margin="20">
<Button Margin="10" Content="Button1" Background="{Binding Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}}}" />
<Button Margin="10" Content="Button2" Background="{Binding Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type FrameworkElement}}}" />
</StackPanel>
</Border>
</Grid>
</Grid>
In questo esempio, Button1 ha uno sfondo grigio perché l'antenato Grid
più vicino ha uno sfondo grigio. Button2 ha uno sfondo bianco perché l'antenato più prossimo derivato da FrameworkElement
è lo StackPanel
bianco.
Associazione di più valori con un MultiBinding
Il MultiBinding consente di associare più valori alla stessa proprietà. Nell'esempio seguente più valori sono associati alla proprietà Text di una casella di testo e formattati utilizzando la proprietà StringFormat.
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="User.Forename"/>
<Binding Path="User.Surname"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
Oltre a StringFormat
, è possibile utilizzare anche IMultiValueConverter
per convertire i valori dai binding in un valore per la destinazione di MultiBinding.
Tuttavia, MultiBindings non può essere annidato.