В Universal Windows Platform привязка данных представляет взаимодействие двух объектов: источника и приемника. Объект-приемник создает привязку к определенному свойству объекта-источника. При изменении этого свойства в объекте-источнике, объект-приемник также будет модифицирован. Возьмем простейший пример:
<Page x:Class="BindingApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:BindingApp" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <TextBox x:Name="textBox" Height="30" /> <TextBlock x:Name="textBlock" Text="{Binding ElementName=textBox,Path=Text}" Height="30" /> </StackPanel> </Page>
В данном случае элемент TextBlock устанавливает привязку к свойству Text элемента TextBox. То есть элемент TextBlock будет приемником привязки, а элемент TextBox - ее источником. И все изменения свойства Text в TextBox вызовут изменения свойства Text элемента TextBlock.
Для определения привязки используется элемент Binding, который представляет объект класса Windows.UI.Xaml.Data.Binding. В общем случае привязка выглядит следующим образом:
{Binding ElementName=Имя_объекта-источника, Path=Свойство_объекта-источника}
Параметры ElementName
и Path
представляют свойства класса Binding. Всего у данного класса можно выделить следующие свойства:
ElementName: имя элемента, к которому создается привязка
Path: свойство элемента, к которому создается привязка
Mode: режим или направление привязки
Source: объект-источник привязки, который необязательно является элементом управления UWP
TargetNullValue: устанавливает значение по умолчанию, если привязанное свойство источника привязки имеет значение null
Для создания привязки в коде C# мы можем воспользоваться методами и свойствами класса Windows.UI.Xaml.Data.Binding:
Binding binding = new Binding(); binding.ElementName = "textBox"; // элемент-источник binding.Path = new PropertyPath("Text"); // свойство элемента-источника textBlock.SetBinding(TextBlock.TextProperty, binding); // установка привязки для элемента-приемника
В данном случае эффект будет тот же, что и при установке привязки в xaml.
Свойство Mode объекта Binding, которое представляет режим привязки, может принимать следующие значения:
OneTime
: привязка устанавливается только один раз, и после однократной установки привязки она уже не действует
OneWay
: действует по умолчанию и предполагает автоматическое изменение значения свойства у одного объекта при изменении у другого
TwoWay
: мы можем изменять свойства обоих объектов, и автоматически будет меняться свойство любого из связанных объектов, то есть двусторонняя привязка
Применение режима привязки:
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <TextBox x:Name="textBox1" Height="30" /> <TextBox x:Name="textBox2" Height="30" Text="{Binding ElementName=textBox1, Path=Text, Mode=TwoWay}" /> </StackPanel>
Выше использованная двусторонняя привязка имеет некоторые ограничения. Так, при изменении источника привязки приемник изменяется мгновенно. А вот при изменении приемника привязки изменения в источнике происходит не моментально, а лишь после потери фокуса текстовым полем-приемником. На характер обновления источника при изменении приемника оказывает влияние свойство UpdateSourceTrigger. Оно может принимать следующие значения:
PropertyChanged
: источник привязки обновляется сразу после обновления свойства в приемнике
Explicit
: источник не обновляется до тех пор, пока не будет вызван метод BindingExpression.UpdateSource()
Default
: действие по умолчанию. Для большинства элементов это значение PropertyChanged
То есть, чтобы решить проблему с немедленным обновлением источника после изменения приемника, нам надо использовать значение PropertyChanged
:
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <TextBox x:Name="textBox1" Height="30" /> <TextBox x:Name="textBox2" Height="30" Text="{Binding ElementName=textBox1, Path=Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> </StackPanel>
Свойство Source позволяет установить привязку даже к тем объектам, которые не являются элементами управления в Universal Windows Platform. Например, определим класс Phone:
public class Phone { public string Title { get; set; } public string Company { get; set; } public int Price { get; set; } }
Теперь создадим объект этого класса и определим к нему привязку:
<Page x:Class="BindingApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:BindingApp" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Page.Resources> <local:Phone x:Key="lumiaPhone" Title="Lumia 950" Company="Microsoft" Price="40000" /> </Page.Resources> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid.RowDefinitions> <RowDefinition Height="50" /> <RowDefinition /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <TextBlock Text="Модель:"/> <TextBlock x:Name="titleTextBlock" Text="{Binding Source={StaticResource lumiaPhone}, Path=Title}" Grid.Column="1"/> <TextBlock Text="Цена:" Grid.Row="1"/> <TextBlock x:Name="priceTextBlock" Text="{Binding Source={StaticResource lumiaPhone}, Path=Price}" Grid.Column="1" Grid.Row="1"/> </Grid> </Page>
На случай, если свойство в источнике привязки вдруг имеет значение null, то есть оно не установлено, мы можем задать некоторое значение по умолчанию. Например:
<Page.Resources> <local:Phone x:Key="lumiaPhone" Company="Microsoft" Price="40000" /> </Page.Resources> <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <TextBlock x:Name="titleTextBlock" Text="{Binding Source={StaticResource lumiaPhone}, Path=Title, TargetNullValue=Текст по умолчанию}" /> </StackPanel>
Здесь у ресурса lumiaPhone не установлено свойство Title, поэтому текстовый блок будет выводить значение по умолчанию, указанное в параметре TargetNullValue.