wpf
Introduktion till WPF-databindning
Sök…
Syntax
- {Binding PropertyName} motsvarar {Binding Path = PropertyName}
- {Binding Path = SomeProperty.SomeOtherProperty.YetAnotherProperty}
- {Binding Path = SomeListProperty [1]}
parametrar
Parameter | detaljer |
---|---|
Väg | Anger sökvägen att binda till. Om den inte är specificerad, binder den sig till DataContext. |
UpdateSourceTrigger | Anger när bindningskällan har sitt värde uppdaterat. Standardinställningar för LostFocus . Det mest använda värdet är PropertyChanged . |
Läge | Vanligtvis OneWay eller TwoWay . Om den inte är specificerad av bindningen OneWay den OneWay inte bindningsmålet begär att det ska vara TwoWay . Ett fel inträffar när TwoWay används för att binda till en läsad egenskap, t.ex. måste OneWay uttryckligen ställas in när en readonly string-egenskap TextBox.Text till TextBox.Text . |
Källa | Tillåter att använda en StaticResource som en bindande källa i stället för den aktuella DataContext. |
RelativeSource | Tillåter att använda ett annat XAML-element som en bindningskälla i stället för den aktuella DataContext. |
ElementName | Tillåter att använda ett namngivet XAML-element som en bindningskälla i stället för den aktuella DataContext. |
FallbackValue | Om bindningen misslyckas tillhandahålls detta värde till bindningsmålet. |
TargetNullValue | Om bindningskällvärdet är null tillhandahålls detta värde till bindningsmålet. |
Omvandlare | Anger omvandlaren StaticResource som används för att konvertera bindningens värde, t.ex. konvertera en booleska till en Visibility enum. |
ConverterParameter | Anger en valfri parameter som ska tillhandahållas till omvandlaren. Detta värde måste vara statiskt och kan inte bindas. |
StringFormat | Anger en formatsträng som ska användas vid visning av det bundna värdet. |
Fördröjning | (WPF 4.5+) Anger en försening i milliseconds för bindningen för att uppdatera BindingSource i ViewModel . Detta måste användas med Mode=TwoWay och UpdateSourceTrigger=PropertyChanged att träda i kraft. |
Anmärkningar
UpdateSourceTrigger
Som standard uppdaterar WPF bindningskällan när kontrollen tappar fokus. Men om det bara finns en kontroll som kan få fokus - något som är vanligt i exempel - måste du ange UpdateSourceTrigger=PropertyChanged
för att uppdateringarna ska fungera.
Du kommer att vilja använda PropertyChanged
som utlösare för många tvåvägsbindningar om inte uppdatering av bindningskällan för varje tangenttryckning är kostsamt eller validering av livedata är inte önskvärt.
Att använda LostFocus
har en olycklig bieffekt: genom att trycka på enter för att skicka ett formulär med en knapp märkt IsDefault
uppdateras inte egenskapen som stöder din bindning, och ångrar effektivt dina ändringar. Lyckligtvis finns det några lösningar .
Observera också att till skillnad från UWP, WPF (4.5+) också har Delay
i bindningar, som kanske bara räcker för vissa bindningar med lokala eller enkla mindre intelligensinställningar, som vissa TextBox
valideringar.
Konvertera en boolean till synlighetsvärde
Detta exempel döljer den röda rutan (gränsen) om kryssrutan inte är markerad genom att använda en IValueConverter
.
Obs: BooleanToVisibilityConverter
används i exemplet nedan är en inbyggd värdekonverterare som finns i namnsområdet 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>
Definiera DataContext
För att arbeta med bindningar i WPF måste du definiera en DataContext . DataContext berättar för bindningar var de kan hämta sina data som standard.
<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>
Du kan också ställa in DataContext via kod bakom, men det är värt att notera att XAML IntelliSense är något picky: en starkt typad DataContext måste ställas in i XAML för IntelliSense för att föreslå egenskaper tillgängliga för bindning.
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new HelloWorldViewModel();
}
}
Det finns ramar som hjälper dig att definiera din DataContext på ett mer flexibelt sätt (t.ex. MVVM Light har en visningsmodellokalisator som använder inversion av kontroll ), vi använder den snabba och smutsiga metoden för syftet med denna handledning.
Du kan definiera en DataContext för nästan alla visuella element i WPF. DataContext ärveras vanligtvis från förfäder i det visuella trädet om det inte uttryckligen har åsidosatts, t.ex. i ett ContentPresenter.
Implementera INotifyPropertyChanged
INotifyPropertyChanged
är ett gränssnitt som används av bindningskällor (dvs. DataContext) för att låta användargränssnittet eller andra komponenter veta att en egenskap har ändrats. WPF uppdaterar automatiskt användargränssnittet för dig när händelsen PropertyChanged
tas upp. Det är önskvärt att detta gränssnitt implementeras i en basklass som alla dina visningsmodeller kan ärva från.
I C # 6 är detta allt du behöver:
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
Detta gör att du kan åberopa NotifyPropertyChanged
på två olika sätt:
-
NotifyPropertyChanged()
, vilket kommer att höja händelsen för den setter som åberopar den, tack vare attributet CallerMemberName . -
NotifyPropertyChanged(nameof(SomeOtherProperty))
, vilket kommer att höja händelsen för SomeOtherProperty.
För .NET 4.5 och högre med C # 5.0 kan detta användas istället:
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));
}
}
}
I versioner av .NET före 4.5 måste du nöja dig med egendomnamn som strängkonstanter eller som en lösning med uttryck .
Obs: Det är möjligt att binda till en egenskap hos ett "vanligt gammalt C # -objekt" (POCO) som inte implementerar INotifyPropertyChanged
och observera att bindningarna fungerar bättre än förväntat. Detta är en dold funktion i .NET och bör förmodligen undvikas. Speciellt eftersom det kommer att orsaka minnesläckage när bindningens Mode
inte är OneTime
(se här ).
Varför uppdateras den bindande uppdateringen utan att implementera INotifyPropertyChanged?
Bindas till egendom hos ett annat namngivet element
Du kan binda till en egenskap på ett namngivet element, men det namngivna elementet måste vara i omfattning.
<StackPanel>
<CheckBox x:Name="MyCheckBox" IsChecked="True" />
<TextBlock Text="{Binding IsChecked, ElementName=MyCheckBox}" />
</StackPanel>
Bindas till en förfäder
Du kan binda till en egenskap hos en förfader i det visuella trädet genom att använda en RelativeSource
bindning. Den närmaste kontrollen högre i det visuella trädet som har samma typ eller härrör från den typ du anger kommer att användas som bindningens källa:
<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>
I det här exemplet har knapp 1 en grå bakgrund eftersom den närmaste Grid
har en grå bakgrund. Knapp2 har en vit bakgrund eftersom den närmaste förfäder som härrör från FrameworkElement
är den vita StackPanel
.
Bindning av flera värden med en MultiBinding
MultiBinding tillåter att flera värden binds till samma egenskap. I följande exempel är flera värden bundna till egenskapen Text i en textbox och formaterad med egenskapen StringFormat.
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="User.Forename"/>
<Binding Path="User.Surname"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
Förutom StringFormat
kan en IMultiValueConverter
också användas för att konvertera värdena från bindningarna till ett värde för MultiBindings mål.
MultiBindings kan dock inte kapslas.