Режимы привязки

33

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

private void Button_Click(object sender, RoutedEventArgs e)
        {
            sld.Value += 5;
        }

Этот код перемещает значение ползунка на 5 единиц, который, в свою очередь, изменяет размер шрифта текста через привязку данных. Это то же самое, как если бы вы двигали ползунок вручную. В этом и заключается основная сила привязки элементов.

Программная модификация источника данных

Интересно, что существует способ заставить данные перемещаться в обоих направлениях: от источника к цели и от цели к источнику. Трюк заключается в установке свойства Mode объекта Binding. Ниже приведена усовершенствованная двунаправленная привязка, которая позволяет применять значения либо к источнику, либо к цели, и заставит противоположную часть привязки обновлять себя автоматически:

<TextBlock Margin="5" Text="Какой-то текст" 
      FontSize="{Binding ElementName=sld, Path=Value, Mode=TwoWay}"></TextBlock>

В рассматриваемом примере нет причин применять двунаправленную привязку (которая требует больше накладных расходов), поскольку эту проблему можно решить с помощью кода. Однако рассмотрим вариант этого примера, включающий текстовое поле, в котором пользователь может точно устанавливать размер шрифта. Этому текстовому полю понадобится двунаправленная привязка, чтобы оно могло как применять пользовательские изменения, так и отражать последнее значение размера, когда оно изменяется другим путем.

При установке свойства Binding.Mode можно использовать одно из пяти значений перечисления System.Windows.Data.BindingMode. Ниже приведен их полный список:

OneWay

Целевое свойство обновляется при изменениях исходного свойства

TwoWay

Целевое свойство обновляется при изменениях исходного свойства, а исходное свойство обновляется при изменении целевого свойства

OneTime

Целевое свойство устанавливается изначально на основе значения исходного свойства. Однако с этого момента изменения игнорируются (если только привязка не устанавливается на совершенно другой объект или не вызывается BindingExpression.UpdateTarget()). Обычно этот режим используется для сокращения накладных расходов, если известно, что целевое свойство не изменится

OneWayToSource

Подобно OneWay, но действует в обратном направлении. Исходное свойство обновляется, когда изменяется целевое свойство (что может показаться несколько странным), но целевое свойство никогда не обновляется

Default

Этот тип привязки зависит от целевого свойства. Это либо TwoWay (для устанавливаемых пользователем свойств, таких как TextBox.Text), либо OneWay (для всего остального). Все привязки используют данный подход, если только не указано иное

На рисунке демонстрируется разница. Вы уже видели OneWay и TwoWay. Значение OneTime достаточно очевидно. Оставшиеся два варианта требуют ряда дополнительных исследований.

Различные направления привязки свойств

Может возникнуть вопрос: зачем нужны две опции — и OneWay, и OneWayToSource? В конце концов, оба значения создают однонаправленную привязку, которая работает одинаковым образом. Единственное отличие в том, куда помещено выражение привязки. По сути, OneWayToSource позволяет поменять местами источник и цель, поместив выражение в то, что обычно считается источником привязки.

Наиболее общая причина использования этого трюка состоит в установке свойства, которое не является свойством зависимости. Как упоминалось, выражения привязки могут применяться только для установки свойств зависимости. Однако с помощью OneWayToSource это ограничение можно обойти, предоставляя в качестве свойства, поставляющего значение, свойство зависимости.

Изначально кажется логичным предположить, что все привязки однонаправленные, если только явно не указано иное. (В конце концов, именно так работает простой пример с ползунком.) Но на самом деле это не так. Чтобы убедиться в этом, вернемся к примеру с привязанным текстовым полем и позволим редактировать текущий размер шрифта. Если убрать установку Mode=TwoWay, этот пример все равно будет работать точно также. Причина в том, что WPF использует разные значения Mode по умолчанию, в зависимости от привязываемого свойства. (Формально в каждом свойстве зависимости присутствует фрагмент метаданных — флаг FrameworkPropertyMetadata.BindsTwoWayByDefault, который указывает, какую привязку должно использовать свойство: однонаправленную или двунаправленную).

Часто значение по умолчанию — именно то, что и нужно. Тем не менее, можно представить пример с текстовым полем только для чтения, которое пользователь не может изменять. В этом случае удается слегка сократить накладные расходы, установив режим однонаправленной привязки.

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

Пройди тесты
Лучший чат для C# программистов