Работа с данными

Привязка данных и контекст данных

Последнее обновление: 26.02.2016

Большую роль при работе с данными играет механизм привязки. Ранее в одной из прошлых тем рассматривалась привязка элементов и их свойств. В этой же теме сделаем больший упор на привязку данных.

Для создания привязки применяется элемент 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:

Контекст данных для элементов WPF

В тоже время нам необязательно конкретизировать контекст для текстового блока, вместо этого мы могли бы с помощью нотации точки обратиться к вложенным свойствам:

<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>
Ресурсы и DataContext в WPF
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850