Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Windows Presentation Foundation.docx
Скачиваний:
12
Добавлен:
13.08.2019
Размер:
1.13 Mб
Скачать

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

Построим примерразметки XAML, в котором привязка соединяет два свойства разных элементов управления.Для привязки данных определено расширения разметки {Binding}, что позволяет настроить привязку декларативно.Сделаем так, чтобы при перемещении ползунка слайдера автоматически менялся размер строки текста1:

<StackPanel>

<Slider Name="slider" Margin="3" Minimum="1" Maximum="40" />

<TextBlock Margin="10" Text="Sample Text" Name="lblText"

FontSize="{Binding ElementName=slider, Path=Value}"/>

</StackPanel>

Рис. 36. Привязка для элементов управления.

Привязку можно выполнить не только декларативно, но и программно (а в некоторых ситуациях это единственный вариант). Нижеприведёнкодпрограммнойпривязки, эквивалентной примеру разметки XAML:

Binding binding = newBinding();

binding.Source = slider;

binding.Path = newPropertyPath("Value");

lblText.SetBinding(TextBlock.FontSizeProperty, binding);

Заданную привязку можно удалить в коде, используя два статических метода класса BindingOperations. Метод ClearBinding() принимает ссылку на свойство зависимостей, которое имеет привязку, подлежащую удалению, аClearAllBindings() удаляет все привязки элемента:

BindingOperations.ClearAllBindings(lblText);

Следующий пример XAMLдемонстрирует двунаправленную привязку: при перемещении ползунка слайдера меняется текст в TextBox, акорректное изменение текста (допустимы вещественные числа) ведёт к перемещению ползунка. Обратите внимание на установкуUpdateSourceTrigger=PropertyChanged.Это обеспечивает мгновенные изменения позиции ползунка прямо при вводе текста.

<StackPanel>

<Slider Name="slider" Minimum="1" Maximum="40" Value="10" />

<TextBox Name="txtSize"

Text="{Binding ElementName=slider, Path=Value,

Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

</StackPanel>

ЕслиUpdateSourceTriggerустановитьвUpdateSourceTrigger.Explicit, требуетсянаписатькод, вызывающийдляобновленияметодUpdateSource()уобъектаBindingExpression, связанногосэлементом:

// получить выражение привязки для текстового поля

BindingExpression binding =

txtSize.GetBindingExpression(TextBox.TextProperty);

// обновитьсвязанныйисточник (Slider)

binding.UpdateSource();

Рассмотрим сценарии, в которых источником привязки является не элемент WPF, а обычный объект. В этом случае вместо ElementName используется одно из описанных ниже свойств:

  • Source– свойство привязки, указывающее на объект-источник.

  • RelativeSource– свойство привязки, которое указывает на источник относительно текущего элемента. Это подход, часто применяемый при разработке шаблонов элементов управления и шаблонов данных.

  • DataContext– наследуемое свойство FrameworkElement.Если источник не указан через Source или RelativeSource, WPF выполняет поиск по дереву элементов, начиная с текущего элемента. В качестве источника данных будет использоваться первый DataContext, не равный null.

Следующий пример разметки XAMLдемонстрирует использование свойства Sourceдля связывания с объектом класса Person. Так как объект-источник должен существовать на момент выполнения привязки, этот объект помещается в словарь ресурсов окна.

<Window x:Class="WpfApplication.MainWindow"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:local="clr-namespace:WpfApplication">

<Window.Resources>

<local:Person x:Key="person" Name="Mr. Smith" Age="27.3" />

</Window.Resources>

<StackPanel>

<TextBox Text="{Binding Source={StaticResource person},

Path=Name}"/>

</StackPanel>

</Window>

publicclassPerson

{

publicstring Name { get; set; }

publicdouble Age { get; set;}

publicstring Address { get; set; }

}

Модификация примера использует для размещения объекта привязки свойство DataContext у контейнера StackPanel:

<!--пропущена настройка окна и объявление ресурса1-->

<StackPanel DataContext="{StaticResource person}">

<TextBox Text="{BindingName}"/>

</StackPanel>

Свойство привязки RelativeSource позволяет указать объект-источник на основе его отношения к целевому объекту. Например, можно использовать RelativeSource для привязки элемента к самому себе или к родительскому элементу, находящемуся на неизвестное число шагов вверх по дереву элементов.Для установки свойства Binding.RelativeSourceиспользуется объект класса RelativeSource. При этом можно использовать как специальное расширение разметки, так и синтаксис, основанный на элементах-свойствах.

<!--используем элемент-свойствоXAML-->

<TextBlock>

<TextBlock.Text>

<Binding Path="Title">

<Binding.RelativeSource>

<RelativeSource Mode="FindAncestor"

AncestorType="{x:Type Window}" />

</Binding.RelativeSource>

</Binding>

</TextBlock.Text>

</TextBlock>

<!--используемрасширениеразметки -->

<TextBlock Text="{Binding Path=Title,

RelativeSource={RelativeSource FindAncestor,

AncestorType={x:Type Window}}}" />

В табл. 13 перечислены четыре возможных режима для RelativeSource.

Таблица 13

Значения перечисления RelativeSourceMode

Имя

Описание

Self

Выражение привязывает к другому свойству того же элемента

FindAncestor

Выражение привязывает к родительскому элементу. WPF будет производить поиск вверх по дереву элементов, пока не найдёт нужного роди­теля. Чтобы специфицировать родителя, необходимо также установить свойство AncestorType для указания типа родительского элемента. Можно использовать свойство AncestorLevel, чтобы пропустить определённое число вхождений указанного элемента

PreviousData

Выражение привязывает к предыдущему элементу данных в списке

TemplatedParent

Выражение привязывает к элементу, к которому применён шаблон. Этот режим работает, только если привязка расположена внутри шаблона элемента управления или шаблона данных

Если при привязке к объекту .NETнеобходимо, чтобы привязка отслеживала изменения в объекте, можно поступить одним из следующих способов:

  • Сделать отслеживаемые свойства объекта-источника свойствами зависимостей, а сам объект наследовать от DependencyObject.

  • Инициировать при изменении свойства события ИмяСвойстваChanged.

  • Реализовать в объекте-источникеинтерфейс INotifyPropertyChanged, содержащий событиеPropertyChanged. Это событие нужно инициировать всякий раз, когда свойство изменяется, передавая имя свойства.

Ниже приведена реализация класса Person, использующая третий подход:

publicclassPerson : INotifyPropertyChanged

{

publiceventPropertyChangedEventHandler PropertyChanged;

protectedvirtualvoid OnPropertyChanged(string propertyName)

{

if (PropertyChanged != null)

PropertyChanged(this,

newPropertyChangedEventArgs(propertyName));

}

privatestring _name;

publicstring Name

{

get {return _name}

set{

if (value != _name)

{

_name = value;

OnPropertyChanged("Name");

}

}

} // остальные свойства надо реализовать аналогично

}