wpf
Введение в привязку данных WPF
Поиск…
Синтаксис
- {Binding PropertyName} эквивалентно {Binding Path = PropertyName}
- {Binding Path = SomeProperty.SomeOtherProperty.YetAnotherProperty}
- {Binding Path = SomeListProperty [1]}
параметры
параметр | подробности |
---|---|
Дорожка | Указывает путь для привязки. Если не указано, привязывается к самому DataContext. |
UpdateSourceTrigger | Указывает, когда источник привязки обновлен. По умолчанию для LostFocus . Наиболее используемым значением является PropertyChanged . |
Режим | Обычно OneWay или TwoWay . Если это не указано в привязке, по умолчанию используется значение OneWay если целевой объект привязки не запрашивает его как TwoWay . Произошла ошибка, когда TwoWay используется для привязки к свойству readonly, например, OneWay должен быть явно установлен при привязке свойства readonly string к TextBox.Text . |
Источник | Позволяет использовать StaticResource в качестве источника привязки вместо текущего DataContext. |
RelativeSource | Позволяет использовать другой элемент XAML в качестве источника привязки вместо текущего DataContext. |
ElementName | Позволяет использовать именованный элемент XAML в качестве источника привязки вместо текущего DataContext. |
FallbackValue | Если привязка не выполняется, это значение предоставляется целевой привязке. |
TargetNullValue | Если значение источника привязки равно null , это значение указывается в целевой привязке. |
конвертер | Указывает преобразователь StaticResource который используется для преобразования значения привязки, например, конвертировать логическое значение в элемент перечисления Visibility . |
ConverterParameter | Задает необязательный параметр, который должен быть предоставлен преобразователю. Это значение должно быть статическим и не может быть связано. |
StringFormat | Указывает строку формата, которая будет использоваться при отображении связанного значения. |
задержка | (WPF 4.5+) Задает задержка в milliseconds для привязки для обновления BindingSource в ViewModel . Это необходимо использовать с Mode=TwoWay и UpdateSourceTrigger=PropertyChanged для вступления в силу. |
замечания
UpdateSourceTrigger
По умолчанию WPF обновляет источник привязки, когда управление теряет фокус. Однако, если есть только один элемент управления, который может получить фокус - что-то общее в примерах - вам нужно будет указать UpdateSourceTrigger=PropertyChanged
для обновлений, которые будут работать.
Вы захотите использовать PropertyChanged
в качестве триггера для многих двусторонних привязок, если обновление источника привязки при каждом нажатии клавиши не является дорогостоящим, или проверка достоверности данных нежелательна.
Использование LostFocus
имеет неприятный побочный эффект: нажав enter, чтобы отправить форму, используя кнопку, отмеченную IsDefault
, не обновляет свойство, поддерживающее вашу привязку, эффективно отменяя ваши изменения. К счастью, существуют некоторые обходные пути .
Также обратите внимание, что в отличие от UWP, WPF (4.5+) также имеет свойство Delay
в привязках, которого может быть достаточно для некоторых привязок с локальными или просто небольшими настройками интеллекта, такими как некоторые проверки TextBox
.
Преобразование значения типа boolean в значение видимости
В этом примере скрывается красная рамка (граница), если флажок не проверяется с помощью IValueConverter
.
Примечание . BooleanToVisibilityConverter
используемый в приведенном ниже примере, представляет собой встроенный преобразователь значений, расположенный в пространстве имен 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>
Определение DataContext
Чтобы работать со связями в WPF, вам необходимо определить DataContext . DataContext сообщает привязки, где по умолчанию получают свои данные.
<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>
Вы также можете установить DataContext с помощью кода, но стоит отметить, что XAML IntelliSense несколько придирчив: в XAML для IntelliSense должен быть установлен строго типизированный DataContext, чтобы предлагать свойства, доступные для привязки.
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new HelloWorldViewModel();
}
}
Хотя существуют рамки, которые помогут вам более точно определить ваш DataContext (например, MVVM Light имеет локатор viewmodel, который использует инверсию управления ), мы используем быстрый и грязный метод для целей этого руководства.
Вы можете определить DataContext практически для любого визуального элемента в WPF. DataContext обычно унаследован от предков в визуальном дереве, если он явно не переопределен, например, внутри ContentPresenter.
Внедрение INotifyPropertyChanged
INotifyPropertyChanged
- это интерфейс, используемый источниками привязки (то есть DataContext), чтобы пользовательский интерфейс или другие компоненты знали, что свойство было изменено. WPF автоматически обновляет пользовательский интерфейс для вас, когда он видит событие PropertyChanged
. Желательно, чтобы этот интерфейс реализован в базовом классе, который могут наследовать все ваши модели просмотра.
В C # 6 это все, что вам нужно:
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
Это позволяет вам вызывать NotifyPropertyChanged
двумя разными способами:
-
NotifyPropertyChanged()
, который поднимет событие для вызывающего устройства, которое вызывает его, благодаря атрибуту CallerMemberName . -
NotifyPropertyChanged(nameof(SomeOtherProperty))
, который поднимет событие для SomeOtherProperty.
Для .NET 4.5 и выше с использованием C # 5.0 это можно использовать вместо этого:
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));
}
}
}
В версиях .NET до 4.5 вам нужно определить имена свойств как строковые константы или решение с использованием выражений .
Примечание. Можно привязать свойство «обычного старого объекта C #» (POCO), которое не реализует INotifyPropertyChanged
и наблюдать, что привязки работают лучше, чем ожидалось. Это скрытая функция в .NET, и ее, вероятно, следует избегать. Тем более , что это приведет к утечке памяти , когда связывание - х Mode
не OneTime
(см здесь ).
Почему обновление привязки не реализует INotifyPropertyChanged?
Привязать к свойству другого именованного элемента
Вы можете привязать свойство к именованному элементу, но именованный элемент должен быть в области.
<StackPanel>
<CheckBox x:Name="MyCheckBox" IsChecked="True" />
<TextBlock Text="{Binding IsChecked, ElementName=MyCheckBox}" />
</StackPanel>
Привязать к собственности предка
Вы можете привязать свойство предка в визуальном дереве с помощью привязки RelativeSource
. Ближайший элемент управления, расположенный выше в визуальном дереве, который имеет тот же тип или получен из указанного вами типа, будет использоваться в качестве источника привязки:
<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>
В этом примере Button1 имеет серый фон, поскольку ближайший предок Grid
имеет серый фон. Button2 имеет белый фон, потому что ближайшим предком, полученным из FrameworkElement
является белый StackPanel
.
Связывание нескольких значений с помощью MultiBinding
MultiBinding позволяет привязать несколько значений к одному и тому же свойству. В следующем примере несколько значений привязаны к свойству Text текстового поля и отформатированы с использованием свойства StringFormat.
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="User.Forename"/>
<Binding Path="User.Surname"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
Помимо StringFormat
, IMultiValueConverter
также может использоваться для преобразования значений из привязок в одно значение для цели MultiBinding.
Однако MultiBindings не может быть вложенным.