Большую роль при работе с данными играет механизм привязки. Ранее в одной из прошлых тем рассматривалась привязка элементов и их свойств. В этой же теме сделаем больший упор на привязку данных.
Для создания привязки применяется элемент Binding и его свойства:
ElementName: имя элемента, к которому идет привязка. Если мы говорим о привязке данных, то данное свойство задействуется редко за исключением тех случаев, когда данные определены в виде свойства в определенном элементе управления
Path: ссылка на свойство объекта, к которому идет привязка
Source: ссылка на источник данных, который не является элементом управления
Свойства элемента Binding помогают установить источник привязки. Для установки источника или контекста данных в элементах управления WPF предусмотрено свойство DataContext. Рассмотрим на примерах их использование.
Пусть у нас в проекте определен следующий класс Phone:
public class Phone { public string Name { get; set; } public Company Company { get; set; } public decimal Price { get; set; } } public class Company { public string Title { get; set; } }
Это сложный класс, который включает кроме простых данных типа string и decimal также и сложный объект Company.
Определим в классе окна MainWindow свойство, которое будет представлять объект Phone:
public partial class MainWindow : Window { public Phone MyPhone { get; set; } public MainWindow() { InitializeComponent(); MyPhone = new Phone { Name = "Lumia 630", Company = new Company { Title = "Microsoft" }, Price = 1000 }; this.DataContext = MyPhone; } }
Здесь установлено свойство DataContext
класса MainWindow, после чего мы сможем получить значения из MyPhone в любом элементе в пределах MainWindow:
<Window x:Class="DataApp.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:DataApp" mc:Ignorable="d" Title="MainWindow" Height="250" Width="300"> <StackPanel> <TextBlock Text="{Binding Path=Name}" /> <TextBlock DataContext="{Binding Path=Company}" Text="{Binding Path=Title}" /> </StackPanel> </Window>
Причем контекст данных переходит от корневых элементов к вложенным вниз по логическому дереву. Так, мы установили в качестве контекста для всего окна объект MyPhone. Однако элементы внутри окна могут конкретизировать контекст, взять какую-то его часть:
<TextBlock DataContext="{Binding Path=Company}" Text="{Binding Path=Title}" />
Данный текстовый блок устанавливает в качестве контекста объект Company из общего контекста MyPhone:
В тоже время нам необязательно конкретизировать контекст для текстового блока, вместо этого мы могли бы с помощью нотации точки обратиться к вложенным свойствам:
<TextBlock Text="{Binding Path=Company.Title}" />
При этом надо учитывать, что когда мы определяем простое свойство объекта в коде c#, то установить в качестве контекста данных мы можем его только там же в коде C#, как, например, выше контекст данных устанавливается в конструкторе окна. Однако если мы вместо простого свойства определим свойство зависимостей, тогда мы сможем устанавливать контекст данных и в коде xaml:
public partial class MainWindow : Window { public static readonly DependencyProperty PhoneProperty; public Phone Phone { get { return (Phone)GetValue(PhoneProperty); } set { SetValue(PhoneProperty, value); } } static MainWindow() { PhoneProperty = DependencyProperty.Register( "Phone", typeof(Phone), typeof(MainWindow)); } public MainWindow() { InitializeComponent(); Phone = new Phone { Name = "Lumia 630", Company = new Company { Title = "Microsoft" }, Price = 1000 }; } }
В данном случае контекст данных уже не устанавливается, а вместо обычного свойства определено свойство зависимостей. Тогда в коде xaml мы можем обратиться к этому свойству следующим образом:
<Window x:Class="DataApp.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:DataApp" mc:Ignorable="d" Title="MainWindow" Height="250" Width="300" Name="mainWindow"> <StackPanel> <TextBlock Text="{Binding ElementName=mainWindow, Path=Phone.Name}" /> <TextBlock Text="{Binding ElementName=mainWindow, Path=Phone.Company.Title}" /> </StackPanel> </Window>
Для ссылки на свойство необходимо установить имя окна: Name="mainWindow"
. Также мы могли бы сделать то же самое, используя контекст данных:
<StackPanel DataContext="{Binding ElementName=mainWindow, Path=Phone}"> <TextBlock Text="{Binding Path=Name}" /> <TextBlock DataContext="{Binding Path=Company}" Text="{Binding Path=Title}" /> </StackPanel>
Также в качестве контекста данных можно установить какой-нибудь ресурс. Например:
<Window x:Class="DataApp.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:DataApp" mc:Ignorable="d" xmlns:sys="clr-namespace:System;assembly=mscorlib" Title="MainWindow" Height="250" Width="300" Name="mainWindow"> <Window.Resources> <local:Company x:Key="googleCompany" Title="Google" /> <local:Phone x:Key="nexusPhone" Name="Nexus X5" Price="25000" Company="{StaticResource googleCompany}" /> </Window.Resources> <StackPanel DataContext="{StaticResource nexusPhone}"> <TextBlock Text="{Binding Path=Name}" /> <TextBlock DataContext="{Binding Path=Company}" Text="{Binding Path=Title}" /> </StackPanel> </Window>