Общие сведения об объявлении привязок (WPF .NET)

Как правило, разработчики объявляют привязки непосредственно в разметке XAML элементов пользовательского интерфейса, к которым они хотят привязать данные. Однако привязки также можно объявить в коде. В этой статье описано, как объявлять привязки как в XAML, так и в коде.

Необходимые компоненты

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

В этой статье не рассматриваются понятия привязки данных. Описание концепции привязки данных см. в разделе Общие сведения о привязке данных.

Объявление привязки в XAML

Binding является расширением разметки. Если для объявления привязки вы используете расширение привязки, то объявление состоит из ряда предложений, следующих за ключевым словом Binding и разделенных запятыми (,). Предложения в объявлении привязки могут следовать в любом порядке, и существует множество различных комбинаций. Эти предложения имеют формат имя=значение, где имя — это имя свойства Binding, а значение — это значение, которое устанавливается для этого свойства.

При создании строк объявления привязки в разметке они должны быть присоединены к конкретному свойству зависимостей целевого объекта. В следующем примере показано, как привязать свойство TextBox.Text с помощью расширения привязки, указав свойства Source и Path.

<TextBlock Text="{Binding Source={StaticResource myDataSource}, Path=Name}"/>

Таким образом можно указать большую часть свойств класса Binding. Дополнительные сведения о расширении привязки, а также список свойств класса Binding, которые невозможно задать с помощью расширения привязки, см. в обзорной статье Привязка расширения разметки (.NET Framework).

Синтаксис объектных элементов

Синтаксис объектных элементов является альтернативой созданию объявления привязки. В большинстве случаев нет каких-то особых преимуществ в использовании либо расширения разметки, либо синтаксиса объектных элементов. Но когда расширение разметки не подходит конкретно для вашего сценария (например, если значение свойства имеет нестроковый тип, для которого не существует преобразования), то следует использовать синтаксис объектных элементов.

В предыдущем разделе показано, как выполнить привязку к расширению XAML. В следующем примере показано выполнение той же привязки, но используется синтаксис объектных элементов:

<TextBlock>
    <TextBlock.Text>
        <Binding Source="{StaticResource myDataSource}" Path="Name"/>
    </TextBlock.Text>
</TextBlock>

Дополнительные сведения о различных терминах см. в разделе Подробное описание синтаксиса XAML (.NET Framework).

Классы MultiBinding и PriorityBinding

MultiBinding и PriorityBinding не поддерживают синтаксис расширения XAML. Поэтому вы должны использовать синтаксис объектных элементов, если объявляете MultiBinding или PriorityBinding в XAML.

Создание привязки в коде

Задать привязку можно и другим способом, установив значения свойств объекта Binding непосредственно в коде, а затем назначив привязку свойству. В следующем примере показано создание объекта Binding в коде.

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    // Make a new data source object
    var personDetails = new Person()
    {
        Name = "John",
        Birthdate = DateTime.Parse("2001-02-03")
    };

    // New binding object using the path of 'Name' for whatever source object is used
    var nameBindingObject = new Binding("Name");

    // Configure the binding
    nameBindingObject.Mode = BindingMode.OneWay;
    nameBindingObject.Source = personDetails;
    nameBindingObject.Converter = NameConverter.Instance;
    nameBindingObject.ConverterCulture = new CultureInfo("en-US");

    // Set the binding to a target object. The TextBlock.Name property on the NameBlock UI element
    BindingOperations.SetBinding(NameBlock, TextBlock.TextProperty, nameBindingObject);
}
Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)

    ' Make a new data source object
    Dim personDetails As New Person() With {
        .Name = "John",
        .Birthdate = Date.Parse("2001-02-03")
    }

    ' New binding object using the path of 'Name' for whatever source object is used
    Dim nameBindingObject As New Binding("Name")

    ' Configure the binding
    nameBindingObject.Mode = BindingMode.OneWay
    nameBindingObject.Source = personDetails
    nameBindingObject.Converter = NameConverter.Instance
    nameBindingObject.ConverterCulture = New CultureInfo("en-US")

    ' Set the binding to a target object. The TextBlock.Name property on the NameBlock UI element
    BindingOperations.SetBinding(NameBlock, TextBlock.TextProperty, nameBindingObject)

End Sub

Предыдущий код задает для привязки следующее:

  • Путь к свойству для объекта источника данных.
  • Режим привязки.
  • Источник данных, в данном случае это простой экземпляр объекта, представляющий человека.
  • Необязательный преобразователь, обрабатывающий значение, поступающее из объекта источника данных, до его назначения целевому свойству.

Если объект, который вы привязываете, является FrameworkElement или FrameworkContentElement, можно вызвать метод SetBinding непосредственно в объекте, а не использовать BindingOperations.SetBinding. Пример см. в разделе Практическое руководство. Создание привязки в коде.

В предыдущем примере используется простой тип объекта данных Person. Ниже приведен код для этого объекта:

class Person
{
    public string Name { get; set; }
    public DateTime Birthdate { get; set; }
}
Public Class Person

    Public Property Name As String
    Public Property Birthdate As DateTime
    
End Class

Синтаксис пути привязки

Используйте свойство Path, чтобы указать исходное значение, к которому необходимо выполнить привязку:

  • В простейшем случае значением свойства Path является имя свойства исходного объекта, которое используется для привязки, например, Path=PropertyName.

  • Подсвойства какого-либо свойства можно задавать, используя синтаксис, схожий с синтаксисом C#. Например, предложение Path=ShoppingCart.Order задает привязку к подсвойству Order объекта или свойства ShoppingCart.

  • Для привязки присоединенного свойства заключите его в скобки. Например, для привязки к присоединенному свойству DockPanel.Dock используется синтаксис Path=(DockPanel.Dock).

  • Индексаторы свойства можно указать в квадратных скобках после имени свойства, для которого применяется индексатор. Например, предложение Path=ShoppingCart[0] задает привязку к индексу, который соответствует способу, который внутренняя индексация свойства использует для обработки символьной строки "0". Также поддерживаются вложенные индексаторы.

  • Индексаторы и вложенные свойства могут сочетаться в предложении Path, например, Path=ShoppingCart.ShippingInfo[MailingAddress,Street].

  • Индексаторы могут иметь несколько внутренних параметров, разделенных запятыми (,). Тип каждого параметра указывается в скобках. Например, вы можете задать предложение Path="[(sys:Int32)42,(sys:Int32)24]", где sys сопоставляется с пространством имен System.

  • Если источником является представление коллекции, текущий элемент можно указать с косой чертой (/). Например, предложение Path=/ задает привязку к текущему элементу в представлении. Если источником является коллекция, этот синтаксис задает текущий элемент представления коллекции по умолчанию.

  • Имена свойств и косые черты можно объединять для обхода свойств, которые являются коллекциями. Например, предложение Path=/Offices/ManagerName задает текущий элемент коллекции источников, где свойство Offices также является коллекцией. Текущий элемент этой коллекции — объект, содержащий свойство ManagerName.

  • При необходимости для привязки к текущему источнику можно использовать путь в виде точки (.). Например, выражение Text="{Binding}" будет эквивалентно Text="{Binding Path=.}".

Механизм экранирования

  • Внутри индексаторов ([ ]) знак крышки (^) задает экранирование следующего символа.

  • Если свойство Path задается в коде XAML, также необходимо экранировать (с помощью специальных символов XML) некоторые специфические символы, присутствующие в определении языка XML:

    • Используйте &amp; для экранирования символа &.

    • Используйте &gt; в качестве escape-символа для закрывающего тега «>».

  • Кроме того, если вы задаете всю привязку в атрибуте, используя синтаксис расширения разметки, необходимо экранировать (с помощью обратной косой черты \) символы, которые являются специфическими для синтаксического анализатора расширения разметки WPF:

    • Обратная косая черта (\) сама по себе является escape-символом.

    • Знак равенства (=) разделяет имя и значение свойства.

    • Запятая (,) разделяет свойства.

    • Закрывающая фигурная скобка (}) — это конец расширения разметки.

Направление привязки

Используйте свойство Binding.Mode для указания направления привязки. Ниже перечислены доступные режимы для обновлений привязки:

Режим привязки Description
BindingMode.TwoWay Обновляет целевое свойство или свойство источника при изменении целевого свойства или свойства источника.
BindingMode.OneWay Обновляет целевое свойство только при изменении свойства источника.
BindingMode.OneTime Обновляет целевое свойство только при запуске приложения или при изменении DataContext.
BindingMode.OneWayToSource Обновляет исходное свойство при изменении целевого свойства.
BindingMode.Default Вызывает использование значения по умолчанию Mode целевого свойства.

Дополнительные сведения см. в описании перечисления BindingMode.

В следующем примере показано, как задать свойство Mode:

<TextBlock Name="IncomeText" Text="{Binding Path=TotalIncome, Mode=OneTime}" />

Чтобы обнаружить изменения источника (применимые к привязкам OneWay и TwoWay), источник должен реализовать подходящий механизм уведомления об изменении свойств, например INotifyPropertyChanged. Дополнительные сведения см. в статье Предоставление уведомлений об изменениях.

Для привязок TwoWay или OneWayToSource можно управлять временем обновлений источника, задав свойство UpdateSourceTrigger. Дополнительные сведения см. в разделе UpdateSourceTrigger.

Поведение по умолчанию

Поведение по умолчанию выглядит следующим образом, если не указано в объявлении:

  • Создается преобразователь по умолчанию, который пытается выполнить преобразование типов между значением источника привязки и значением целевого объекта привязки. Если преобразование не удается выполнить, преобразователь по умолчанию возвращает значение null.

  • Если вы не задаете ConverterCulture, подсистема привязки использует свойство Language целевого объекта привязки. В языке XAML это свойство по умолчанию имеет значение en-US или наследует свое значение от корневого элемента (или любого элемента) страницы, если оно было задано явным образом.

  • При условии, что привязка уже имеет контекст данных (например, контекст данных, наследуемый от родительского элемента), а элемент или коллекция, возвращаемые этим контекстом, подходят для привязки без необходимости дополнительного изменения пути, объявление привязки может вообще не иметь предложений: {Binding}. Таким способом привязка часто задается для стилей данных, где привязка воздействует на коллекцию. Дополнительные сведения см. в разделе Использование всего объекта в качестве источника привязки.

  • По умолчанию Mode может быть как односторонним, так и двусторонним, в соответствии со свойством зависимостей, для которого осуществляется привязка. Режим привязки всегда можно объявить явным образом, чтобы обеспечить требуемое поведение привязки. В целом свойства доступных для редактирования пользователями элементов управления, таких как TextBox.Text и RangeBase.Value, по умолчанию имеют двухсторонние привязки, в то время как большинство других свойств по умолчанию имеет односторонние привязки.

  • Значение по умолчанию UpdateSourceTrigger может быть равно PropertyChanged или LostFocus, что также определяется привязанным свойством зависимостей. Значение по умолчанию для большинства свойств зависимостей — PropertyChanged, а свойство TextBox.Text имеет значение по умолчанию LostFocus.

См. также