Поделиться через


Подробно о привязке данных

Важные API

Примечание.

В этом разделе подробно описаны функции привязки данных. Краткое практическое введение см. в обзоре привязки данных.

В этом разделе описывается привязка данных для API, которые находятся в пространстве имен Windows.UI.Xaml.Data.

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

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

  • Можно использовать одноразовый режим для привязки объекта Image к фотографии текущего пользователя.
  • Односторонняя привязка позволяет привязать объект ListView к коллекции актуальных новостных статей, сгруппированных по разделу газеты.
  • С помощью двусторонней привязки вы можете привязать объект TextBox к имени пользователя в форме.

Независимо от режима существует два типа привязки, для объявления которых обычно используется разметка пользовательского интерфейса. Вы можете использовать расширение разметки {x:Bind} или расширение разметки {Binding}. И вы даже можете использовать смесь двух в одном приложении, даже в одном элементе пользовательского интерфейса. Расширение разметки {x:Bind}, которое впервые появилось в Windows 10, отличается повышенной производительностью. Все сведения, описанные в этом разделе, применяются к обоим типам привязки, если мы явно не говорим в противном случае.

Примеры приложений с расширением разметки {x:Bind}

Примеры приложений с расширением разметки {Binding}

Каждая привязка включает в себя эти части

  • Источник привязки. Это источник данных для привязки, и он может быть экземпляром любого класса, имеющего элементы, значения которых необходимо отобразить в пользовательском интерфейсе.
  • Целевой объект привязки. Это зависимостьProperty FrameworkElement в пользовательском интерфейсе, отображающая данные.
  • Объект привязки. Это часть, которая передает значения данных из источника в целевой объект и при необходимости из целевого объекта обратно в источник. Объект привязки создается во время загрузки XAML из расширения разметки {x:Bind} или {Binding} .

В следующих разделах мы рассмотрим источник привязки, целевой объект привязки и объект привязки. И мы свяжит разделы вместе с примером привязки содержимого кнопки к строковому свойству с именем NextButtonText, который принадлежит классу HostViewModel.

Источник привязки

Вот очень рудиментная реализация класса, который мы могли бы использовать в качестве источника привязки.

Если вы используете C++/WinRT, добавьте в проект новые элементы MIDL-файла (.idl) с именем, как показано в приведенном ниже примере кода C++/WinRT. Замените содержимое этих новых файлов на код MIDL 3.0, показанный в описании, выполните сборку проекта, чтобы создать HostViewModel.h и .cpp, а затем добавьте код в созданные файлы для соответствия описанию. Дополнительные сведения о созданных файлах и их копировании в проект см. в статье Элементы управления XAML; привязка к свойству C++/WinRT.

public class HostViewModel
{
    public HostViewModel()
    {
        this.NextButtonText = "Next";
    }

    public string NextButtonText { get; set; }
}
// HostViewModel.idl
namespace DataBindingInDepth
{
    runtimeclass HostViewModel
    {
        HostViewModel();
        String NextButtonText;
    }
}

// HostViewModel.h
// Implement the constructor like this, and add this field:
...
HostViewModel() : m_nextButtonText{ L"Next" } {}
...
private:
    std::wstring m_nextButtonText;
...

// HostViewModel.cpp
// Implement like this:
...
hstring HostViewModel::NextButtonText()
{
    return hstring{ m_nextButtonText };
}

void HostViewModel::NextButtonText(hstring const& value)
{
    m_nextButtonText = value;
}
...

Эта реализация HostViewModel и его свойство NextButtonText подходят только для однократной привязки. Но односторонняя и двусторонняя привязка крайне распространена, и в этих типах привязка пользовательского интерфейса автоматически обновляется в ответ на изменения значений данных источника привязки. Чтобы эти типы привязки работали правильно, необходимо сделать источник привязки наблюдаемым для объекта привязки. Поэтому в нашем примере, если мы хотим выполнить одностороннюю или двустороннюю привязку к свойству NextButtonText , все изменения, которые происходят во время выполнения, к значению этого свойства необходимо сделать наблюдаемым для объекта привязки.

Один из способов сделать это — наследовать класс, представляющий источник привязки из DependencyObject, и предоставить значение данных через DependencyProperty. Вот как платформа FrameworkElement становится наблюдаемой. FrameworkElements — это хорошие источники привязки прямо из поля.

Более упрощенный способ создания наблюдаемого класса (и необходимого для классов, у которых уже есть базовый класс), — реализовать System.ComponentModel.INotifyPropertyChanged. Это действительно просто включает реализацию одного события с именем PropertyChanged. Ниже приведен пример использования HostViewModel .

...
using System.ComponentModel;
using System.Runtime.CompilerServices;
...
public class HostViewModel : INotifyPropertyChanged
{
    private string nextButtonText;

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    public HostViewModel()
    {
        this.NextButtonText = "Next";
    }

    public string NextButtonText
    {
        get { return this.nextButtonText; }
        set
        {
            this.nextButtonText = value;
            this.OnPropertyChanged();
        }
    }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        // Raise the PropertyChanged event, passing the name of the property whose value has changed.
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
// HostViewModel.idl
namespace DataBindingInDepth
{
    runtimeclass HostViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
    {
        HostViewModel();
        String NextButtonText;
    }
}

// HostViewModel.h
// Add this field:
...
    winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler);
    void PropertyChanged(winrt::event_token const& token) noexcept;

private:
    winrt::event<Windows::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged;
...

// HostViewModel.cpp
// Implement like this:
...
void HostViewModel::NextButtonText(hstring const& value)
{
    if (m_nextButtonText != value)
    {
        m_nextButtonText = value;
        m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"NextButtonText" });
    }
}

winrt::event_token HostViewModel::PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
{
    return m_propertyChanged.add(handler);
}

void HostViewModel::PropertyChanged(winrt::event_token const& token) noexcept
{
    m_propertyChanged.remove(token);
}
...

Теперь наблюдаемое свойство NextButtonText. При создании односторонняя или двусторонняя привязка к свойству (мы покажем, как позже), результирующий объект привязки подписывается на событие PropertyChanged . При возникновении этого события обработчик объекта привязки получает аргумент, содержащий имя измененного свойства. Вот как объект привязки знает, какое значение свойства следует идти и читать снова.

Чтобы не реализовывать приведенный выше шаблон по несколько раз, при использовании C# вы можете просто выполнить наследование от базового класса BindableBase, доступного в примере QuizGame (в папке Common). Ниже приведен пример того, как это выглядит.

public class HostViewModel : BindableBase
{
    private string nextButtonText;

    public HostViewModel()
    {
        this.NextButtonText = "Next";
    }

    public string NextButtonText
    {
        get { return this.nextButtonText; }
        set { this.SetProperty(ref this.nextButtonText, value); }
    }
}
// Your BindableBase base class should itself derive from Windows::UI::Xaml::DependencyObject. Then, in HostViewModel.idl, derive from BindableBase instead of implementing INotifyPropertyChanged.

Примечание.

Для C++/WinRT любой класс среды выполнения (объявленный в приложении), который является производным от базового класса, называется составным. На составные классы накладываются определенные ограничения. Чтобы приложение прошло тесты комплекта сертификации приложений для Windows, используемые Visual Studio и Microsoft Store для проверки отправляемого кода (и, следовательно, чтобы оно было успешно принято в Microsoft Store), составляемый класс в конечном счете должен быть производным от базового класса Windows. Это означает, что класс с самого корня иерархии наследования должен иметь тип, полученный в пространстве имен Windows.*. Если вам нужно создать класс среды выполнения, производный от базового класса (например, чтобы реализовать класс BindableBase для всех моделей представления для создания производных объектов), то он может быть производным от Windows.UI.Xaml.DependencyObject.

Вызов события PropertyChanged с аргументом String.Empty или NULL указывает, что все свойства, отличные от индексатора в объекте, должны быть повторно считываются. Это событие можно вызвать для указания того, что свойства индексатора в объекте изменены, с помощью аргумента "Item[indexer]" для конкретных индексаторов (где indexer — это значение индекса) или значения "Item[]" для всех индексаторов.

Источник привязки можно рассматривать как один объект, свойства которого содержат данные или как коллекцию объектов. В коде C# и Visual Basic вы можете выполнить одноразовую привязку к объекту, реализующему класс List(Of T), чтобы отобразить коллекцию, которая не изменяется во время выполнения. Для наблюдаемой коллекции (наблюдая, когда элементы добавляются и удаляются из коллекции), односторонняя привязка к ObservableCollection(Of T) вместо этого. В коде C++/CX вы можете выполнить привязку к классу Vector<T> как для отслеживаемых, так и для неотслеживаемых коллекций. C++/WinRT имеет собственные типы. Чтобы выполнить привязку к собственным классам коллекции, используйте инструкции в следующей таблице.

Сценарий C# и VB (CLR) C++/WinRT C++/CX
Привязка к объекту. Может быть любым объектом. Может быть любым объектом. Объект должен иметь BindableAttribute или реализовать ICustomPropertyProvider.
Получение уведомлений об изменении свойств от привязанного объекта Объект должен реализовывать INotifyPropertyChanged. Объект должен реализовывать INotifyPropertyChanged. Объект должен реализовывать INotifyPropertyChanged.
Привязка к коллекции. List(Of T) IVector от IInspectable или IBindableObservableVector. Дополнительные сведения см. в статьях Элементы управления XAML; привязка к коллекции C++/WinRT и Коллекции с C++/WinRT. Vector<T>
Получение уведомлений об изменениях коллекции от привязанной коллекции. ObservableCollection(Of T) IObservableVector от IInspectable. Например, winrt::single_threaded_observable_vector<T>. IObservableVector<T>. Vector<T> реализует данный интерфейс.
Реализуйте коллекцию, поддерживающую привязку. Расширение списка (T) или реализация IList, IList(of Object), IEnumerable или IEnumerable(Of Object). Привязка к универсальным IList(Of T) и IEnumerable(Of T) не поддерживается. Реализуйте IVector от IInspectable. Дополнительные сведения см. в статьях Элементы управления XAML; привязка к коллекции C++/WinRT и Коллекции с C++/WinRT. Реализуйте IBindableVector, IBindableIterable, IVector<Object^>, IIterable<Object^>, IVector<IInspectable*> или IIterable<IInspectable*>. Привязка к универсальному IVector<T> и IIterable<T> не поддерживается.
Реализация коллекции, которая поддерживает уведомления о ее изменении Расширение ObservableCollection(Of T) или реализация (не универсального) IList и INotifyCollectionChanged. Реализуйте IObservableVector от IInspectable или IBindableObservableVector. Реализуйте IBindableVector и IBindableObservableVector.
Реализуйте коллекцию, которая поддерживает добавочную загрузку. Расширение ObservableCollection(Of T) или реализация (не универсального) IList и INotifyCollectionChanged. Кроме того, реализуйте ISupportIncrementalLoading. Реализуйте IObservableVector от IInspectable или IBindableObservableVector. Кроме того, реализуйте ISupportIncrementalLoading Реализуйте IBindableVector, IBindableObservableVector и ISupportIncrementalLoading.

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

Цель привязки

В двух примерах ниже свойство Button.Content представляет собой целевой объект привязки, и в качестве его значения устанавливается расширение разметки, которое объявляет объект привязки. Сначала отображается {x:Bind} , а затем {Binding}. Объявление привязок в разметке является обычным случаем (удобно, доступно для чтения и инструментирования). Но при необходимости можно избежать разметки и императивно (программно) создать экземпляр класса Binding .

<Button Content="{x:Bind ...}" ... />
<Button Content="{Binding ...}" ... />

Если вы используете расширения компонентов C++/WinRT или Visual C++ (C++/CX), необходимо добавить атрибут BindableAttribute в любой класс среды выполнения, с которым вы хотите использовать расширение разметки {Binding}.

Внимание

Если вы используете C++/WinRT, то атрибут BindableAttribute доступен, если вы установили Windows SDK версии 10.0.17763.0 (Windows 10, версии 1809) или более поздней. Без этого атрибута необходимо реализовать интерфейсы ICustomPropertyProvider и ICustomProperty, чтобы иметь возможность использовать расширение разметки {Binding}.

Объект привязки, объявленный с помощью {x:Bind}

Перед созданием разметки {x:Bind} необходимо выполнить один шаг. Нам нужно предоставить исходный класс привязки из класса, представляющего страницу разметки. Для этого следует добавить свойство (типа HostViewModel в этом случае) к нашему классу страницы MainPage.

namespace DataBindingInDepth
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            this.ViewModel = new HostViewModel();
        }
    
        public HostViewModel ViewModel { get; set; }
    }
}
// MainPage.idl
import "HostViewModel.idl";

namespace DataBindingInDepth
{
    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
    {
        MainPage();
        HostViewModel ViewModel{ get; };
    }
}

// MainPage.h
// Include a header, and add this field:
...
#include "HostViewModel.h"
...
    DataBindingInDepth::HostViewModel ViewModel();

private:
    DataBindingInDepth::HostViewModel m_viewModel{ nullptr };
...

// MainPage.cpp
// Implement like this:
...
MainPage::MainPage()
{
    InitializeComponent();

}

DataBindingInDepth::HostViewModel MainPage::ViewModel()
{
    return m_viewModel;
}
...

Это сделано, теперь можно более подробно взглянуть на разметку, которая объявляет объект привязки. В приведенном ниже примере используется тот же целевой объект привязки Button.Content , который мы использовали в разделе "Целевой объект привязки" ранее и показывает, что он привязан к свойству HostViewModel.NextButtonText .

<!-- MainPage.xaml -->
<Page x:Class="DataBindingInDepth.Mainpage" ... >
    <Button Content="{x:Bind Path=ViewModel.NextButtonText, Mode=OneWay}" ... />
</Page>

Обратите внимание на значение, которое мы указываем для Path. Это значение интерпретируется в контексте самой страницы. В этом случае в начале пути указывается ссылка на свойство ViewModel, которое мы только что добавили на страницу MainPage. Это свойство возвращает экземпляр HostViewModel и поэтому мы можем указать этот объект для доступа к свойству HostViewModel.NextButtonText . И мы указываем режим, чтобы переопределить значение по умолчанию {x:Bind} однократно.

Свойство Path поддерживает различные варианты синтаксиса привязки к вложенным свойствам, присоединенным свойствам и целым числам и строковым индексаторам. Дополнительные сведения см. в разделе "Синтаксис пути свойства". Привязка к строковым индексаторам дает эффект привязки к динамическим свойствам без реализации ICustomPropertyProvider. Сведения о других параметрах см. в разделе {x:Bind}.

Чтобы продемонстрировать, что свойство HostViewModel.NextButtonText действительно является наблюдаемым, добавьте для кнопки обработчик событий Click и обновите значение HostViewModel.NextButtonText. Выполните сборку и запуск, а затем нажмите кнопку, чтобы увидеть значение обновления кнопки Содержимое.

// MainPage.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
    this.ViewModel.NextButtonText = "Updated Next button text";
}
// MainPage.cpp
void MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
    ViewModel().NextButtonText(L"Updated Next button text");
}

Примечание.

Изменения, внесенные в свойство TextBox.Text, отправляются в источник двусторонней привязки, когда фокус переключается с класса TextBox, а не после каждого нажатия клавиши пользователем.

DataTemplate и x:DataType

Внутри DataTemplate (используется ли в качестве шаблона элемента, шаблона содержимого или шаблона заголовка), значение Path не интерпретируется в контексте страницы, но в контексте шаблона объекта данных. При использовании {x:Bind} в шаблоне данных, чтобы его привязки можно было проверить (и эффективный код, созданный для них) во время компиляции, DataTemplate должен объявить тип объекта данных с помощью x:DataType. Приведенный ниже пример можно использовать в качестве элемента управления ItemTemplate элемента управления, привязанного к коллекции объектов SampleDataGroup .

<DataTemplate x:Key="SimpleItemTemplate" x:DataType="data:SampleDataGroup">
    <StackPanel Orientation="Vertical" Height="50">
      <TextBlock Text="{x:Bind Title}"/>
      <TextBlock Text="{x:Bind Description}"/>
    </StackPanel>
  </DataTemplate>

Слабо типизированные объекты в пути

Рассмотрим, например, что у вас есть тип SampleDataGroup, который реализует строковое свойство Title. Также у вас есть свойство MainPage.SampleDataGroupAsObject объекта типа, которое фактически возвращает экземпляр SampleDataGroup. Привязка <TextBlock Text="{x:Bind SampleDataGroupAsObject.Title}"/> приведет к ошибке компиляции, так как свойство Title не найдено в объекте типа. Исправление этого заключается в добавлении приведения к синтаксису Path, как показано ниже <TextBlock Text="{x:Bind ((data:SampleDataGroup)SampleDataGroupAsObject).Title}"/>. Вот еще один пример, в котором элемент объявлен как объект, но на самом деле является TextBlock: <TextBlock Text="{x:Bind Element.Text}"/> И приведение средств устранения проблемы: <TextBlock Text="{x:Bind ((TextBlock)Element).Text}"/>

Если данные загружаются асинхронно

Код для поддержки {x:Bind} создается во время компиляции в частичных классах для страниц. Эти файлы можно найти в папке obj с такими именами, как <view name>.g.cs (для C#). Созданный код включает обработчик события загрузки страницы, а обработчик вызывает метод Initialize в созданном классе, представляющем привязки страницы. Инициализация в свою очередь вызывает Update , чтобы начать перемещение данных между источником привязки и целевым объектом. Загрузка возникает непосредственно перед первым прохождением меры страницы или пользовательского элемента управления. Таким образом, если данные загружаются асинхронно, к моменту вызова инициализации может не быть готово. Таким образом, после загрузки данных можно принудительно инициализировать однократные привязки путем вызова this.Bindings.Update();. Если вам нужны одноразовые привязки только для асинхронно загружаемых данных, намного эффективнее инициализировать их так, чем создать односторонние привязки и ожидать изменений. Если данные не проходят детализированные изменения, и если они, скорее всего, будут обновлены в рамках определенного действия, вы можете выполнить однократные привязки и принудительно обновить вручную при вызове обновления.

Примечание.

{x:Bind} не подходит для сценариев с поздним связыванием, таких как навигация по структуре словаря объекта JSON или "утиная типизация". "Утиная типизация" — это слабая форма типизации, основанная на лексических соответствиях имен свойств ("если ходит, плавает и крякает как утка — это утка"). С утиной типизацией привязка к свойству Age одинаково удовлетворяется объектом Person или Wine (предполагая, что каждый из этих типов имеет свойство Age). В этих сценариях используйте расширение разметки {Binding}.

Объект привязки, объявленный с помощью {Binding}

Если вы используете расширения компонентов C++/WinRT или Visual C++ (C++/CX), то для использования расширения разметки {Binding} необходимо добавить атрибут BindableAttribute в любой класс среды выполнения, к которому требуется привязаться. Чтобы использовать {x:Bind}, этот атрибут не требуется.

// HostViewModel.idl
// Add this attribute:
[Windows.UI.Xaml.Data.Bindable]
runtimeclass HostViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
...

Внимание

Если вы используете C++/WinRT, то атрибут BindableAttribute доступен, если вы установили Windows SDK версии 10.0.17763.0 (Windows 10, версии 1809) или более поздней. Без этого атрибута необходимо реализовать интерфейсы ICustomPropertyProvider и ICustomProperty, чтобы иметь возможность использовать расширение разметки {Binding}.

{Binding} Предполагает, что по умолчанию вы привязываетесь к DataContext страницы разметки. Поэтому мы задали DataContext нашей страницы как экземпляр исходного класса привязки (типа HostViewModel в данном случае). В приведенном ниже примере показана разметка, которая объявляет объект привязки. Мы используем тот же целевой объект привязки Button.Content , который мы использовали в разделе "Целевой объект привязки" ранее, и мы привязываемся к свойству HostViewModel.NextButtonText .

<Page xmlns:viewmodel="using:DataBindingInDepth" ... >
    <Page.DataContext>
        <viewmodel:HostViewModel x:Name="viewModelInDataContext"/>
    </Page.DataContext>
    ...
    <Button Content="{Binding Path=NextButtonText}" ... />
</Page>
// MainPage.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
    this.viewModelInDataContext.NextButtonText = "Updated Next button text";
}
// MainPage.cpp
void MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
    viewModelInDataContext().NextButtonText(L"Updated Next button text");
}

Обратите внимание на значение, которое мы указываем для Path. Это значение интерпретируется в контексте DataContext страницы, в котором в этом примере устанавливается экземпляр HostViewModel. Путь ссылается на свойство HostViewModel.NextButtonText . Мы можем опустить режим, так как {Binding} по умолчанию используется односторонняя работа.

Значение dataContext по умолчанию для элемента пользовательского интерфейса является унаследованным значением родительского элемента. Конечно, можно переопределить это по умолчанию , установив DataContext явным образом, который, в свою очередь, наследуется дочерними элементами по умолчанию. Параметр DataContext явно используется для элемента, если требуется иметь несколько привязок, использующих один и тот же источник.

Объект привязки имеет свойство Source, которое по умолчанию использует dataContext элемента пользовательского интерфейса, для которого объявлена привязка. Этот параметр по умолчанию можно переопределить, задав source, RelativeSource или ElementName явно в привязке (дополнительные сведения см. в разделе {Binding}).

В классе DataTemplate для свойства DataContext автоматически устанавливается шаблонный объект данных. Приведенный ниже пример можно использовать в качестве элемента управления ItemTemplate элемента управления, привязанного к коллекции любого типа, имеющего строковые свойства с именем Title и Description.

<DataTemplate x:Key="SimpleItemTemplate">
    <StackPanel Orientation="Vertical" Height="50">
      <TextBlock Text="{Binding Title}"/>
      <TextBlock Text="{Binding Description"/>
    </StackPanel>
  </DataTemplate>

Примечание.

По умолчанию изменения, внесенные в свойство TextBox.Text, отправляются в источник двусторонней привязки, когда фокус переключается с класса TextBox. Чтобы вызвать отправку изменений после каждого нажатия клавиш пользователей, задайте для СвойстваSourceTrigger значение PropertyChanged в разметке привязки. Вы также можете полностью контролировать, когда изменения отправляются в источник, задав UpdateSourceTrigger значение "Явный". Затем вы обрабатываете события в текстовом поле (обычно TextBox.TextChanged), вызываете GetBindingExpression в целевом объекте, чтобы получить объект BindingExpression, и, наконец, вызовите BindingExpression.UpdateSource для программного обновления источника данных.

Свойство Path поддерживает различные варианты синтаксиса привязки к вложенным свойствам, присоединенным свойствам и целым числам и строковым индексаторам. Дополнительные сведения см. в разделе "Синтаксис пути свойства". Привязка к строковым индексаторам дает эффект привязки к динамическим свойствам без реализации ICustomPropertyProvider. Свойство ElementName полезно для привязки элемента к элементу. Свойство RelativeSource имеет несколько вариантов использования, один из которых является более мощной альтернативой привязке шаблона внутри ControlTemplate. Сведения о других параметрах см. в разделе "Расширение разметки {Binding} и класс Binding".

Что делать, если источник и целевой объект не совпадают с типом?

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

  • При использовании {x:Bind} можно привязать непосредственно к функции для этого преобразования.
  • Или можно указать преобразователь значений, который является объектом, предназначенным для выполнения преобразования.

Преобразователи значений

Вот преобразователь значений, подходящий для однократной или односторонняя привязка, которая преобразует значение DateTime в строковое значение, содержащее месяц. Класс реализует IValueConverter.

public class DateToStringConverter : IValueConverter
{
    // Define the Convert method to convert a DateTime value to 
    // a month string.
    public object Convert(object value, Type targetType, 
        object parameter, string language)
    {
        // value is the data from the source object.
        DateTime thisdate = (DateTime)value;
        int monthnum = thisdate.Month;
        string month;
        switch (monthnum)
        {
            case 1:
                month = "January";
                break;
            case 2:
                month = "February";
                break;
            default:
                month = "Month not found";
                break;
        }
        // Return the value to pass to the target.
        return month;
    }

    // ConvertBack is not implemented for a OneWay binding.
    public object ConvertBack(object value, Type targetType, 
        object parameter, string language)
    {
        throw new NotImplementedException();
    }
}
// See the "Formatting or converting data values for display" section in the "Data binding overview" topic.

И вот как вы используете этот преобразователь значений в разметке объекта привязки.

<UserControl.Resources>
  <local:DateToStringConverter x:Key="Converter1"/>
</UserControl.Resources>
...
<TextBlock Grid.Column="0" 
  Text="{x:Bind ViewModel.Month, Converter={StaticResource Converter1}}"/>
<TextBlock Grid.Column="0" 
  Text="{Binding Month, Converter={StaticResource Converter1}}"/>

Подсистема привязки вызывает методы Convert и ConvertBack, если параметр Converter определен для привязки. При передаче данных из источника подсистема привязки вызывает преобразование и передает возвращенные данные в целевой объект. При передаче данных из целевого объекта (для двусторонней привязки) подсистема привязки вызывает ConvertBack и передает возвращенные данные источнику.

Преобразователь также имеет необязательные параметры: ConverterLanguage, который позволяет указывать язык, используемый в преобразовании, и ConverterParameter, что позволяет передавать параметр для логики преобразования. Пример использования параметра преобразователя см. в разделе IValueConverter.

Примечание.

Если в преобразовании возникает ошибка, не вызывайте исключение. Вместо этого возвращает значение DependencyProperty.UnsetValue, которое остановит передачу данных.

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

Если привязать текстовый элемент управления к значению, которое не является строкой, подсистема привязки данных преобразует значение в строку. Если значение является ссылочным типом, подсистема привязки данных извлекает строковое значение путем вызова ICustomPropertyProvider.GetStringRepresentation или IStringable.ToString, если оно доступно, и в противном случае вызовет Object.ToString. Обратите внимание, что подсистема привязки будет игнорировать любую реализацию ToString , которая скрывает реализацию базового класса. Реализации подклассов должны переопределить метод ToString базового класса. Аналогичным образом, на собственных языках все управляемые объекты, как представляется, реализуют ICustomPropertyProvider и IStringable. Однако все вызовы GetStringRepresentation и IStringable.ToString направляются в Object.ToString или переопределение этого метода, и никогда не в новую реализацию ToString, которая скрывает реализацию базового класса.

Примечание.

Начиная с Windows 10 версии 1607 платформа XAML предоставляет встроенный логический преобразователь видимости. Преобразователь сопоставляется со значением перечисления Visible и false с свернутым, чтобы можно было привязать свойство Видимости к логическому объекту без создания преобразователя. Для использования встроенного преобразователя минимальная версия целевого пакета SDK вашего приложения должна быть 14393 или более поздней. Вы не сможете использовать преобразователь, если ваше приложение предназначено для более ранних версий Windows 10. Дополнительные сведения о целевых версиях см. в статье Адаптивный к версии код.

Привязка функции в {x:Bind}

{x:Bind} позволяет окончательному шагу в пути привязки быть функцией. Это можно использовать для выполнения преобразований и выполнения привязок, зависящих от нескольких свойств. Дополнительные сведения см. в статье Функции в x:Bind.

Привязка между элементами

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

<TextBox x:Name="myTextBox" />
<TextBlock Text="{x:Bind myTextBox.Text, Mode=OneWay}" />

Внимание

Сведения о необходимом рабочем процессе для привязки между элементами с использованием C++/WinRT см. здесь.

Словари ресурсов с {x:Bind}

Расширение разметки {x:Bind} зависит от создания кода, поэтому для инициализации созданного кода требуется файл программной части, содержащий конструктор, вызывающий InitializeComponent (для инициализации созданного кода). Вы повторно используете словарь ресурсов, создав экземпляр своего типа (так что вызывается InitializeComponent ), а не ссылаясь на его имя файла. Ниже приведен пример того, что делать, если у вас есть существующий словарь ресурсов, и вы хотите использовать {x:Bind} в нем.

TemplatesResourceDictionary.xaml

<ResourceDictionary
    x:Class="ExampleNamespace.TemplatesResourceDictionary"
    .....
    xmlns:examplenamespace="using:ExampleNamespace">
    
    <DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
        <Grid>
            <TextBlock Text="{x:Bind Name}"/>
        </Grid>
    </DataTemplate>
</ResourceDictionary>

TemplatesResourceDictionary.xaml.cs

using Windows.UI.Xaml.Data;
 
namespace ExampleNamespace
{
    public partial class TemplatesResourceDictionary
    {
        public TemplatesResourceDictionary()
        {
            InitializeComponent();
        }
    }
}

MainPage.xaml

<Page x:Class="ExampleNamespace.MainPage"
    ....
    xmlns:examplenamespace="using:ExampleNamespace">

    <Page.Resources>
        <ResourceDictionary>
            .... 
            <ResourceDictionary.MergedDictionaries>
                <examplenamespace:TemplatesResourceDictionary/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Page.Resources>
</Page>

Привязка событий и ICommand

{x:Bind} поддерживает функцию, называемую привязкой событий. С помощью этой функции можно указать обработчик события с помощью привязки, которая является дополнительным параметром поверх обработки событий с помощью метода в файле кода программной части. Предположим, что у вас есть свойство RootFrame в классе MainPage .

public sealed partial class MainPage : Page
{
    ...
    public Frame RootFrame { get { return Window.Current.Content as Frame; } }
}

Затем можно привязать событие click кнопки к методу объекта Frame, возвращаемого свойством RootFrame, как показано ниже. Обратите внимание, что мы также привязываем свойство IsEnabled кнопки к другому члену того же кадра.

<AppBarButton Icon="Forward" IsCompact="True"
IsEnabled="{x:Bind RootFrame.CanGoForward, Mode=OneWay}"
Click="{x:Bind RootFrame.GoForward}"/>

Перегруженные методы нельзя использовать для обработки события с помощью этого метода. Кроме того, если метод, обрабатывающий событие, имеет параметры, они должны быть назначены из типов всех параметров события соответственно. В этом случае Frame.GoForward не перегружен и не имеет параметров (но он по-прежнему будет допустимым, даже если он принял два параметра объекта). Метод Frame.GoBack перегружен, поэтому мы не можем использовать этот метод данным способом.

Метод привязки событий аналогичен реализации и потреблению команд (команда — это свойство, возвращающее объект, реализующий интерфейс ICommand ). Как {x:Bind}, так и {Binding} работают с командами. Так что вам не нужно реализовать шаблон команды несколько раз, можно использовать вспомогательный класс ДелегатCommand , который вы найдете в примере QuizGame (в папке Common).

Привязка к коллекции папок или файлов

API в пространстве имен Windows.Storage можно использовать для получения данных папок и файлов. Однако различные методы GetFilesAsync, GetFoldersAsync и GetItemsAsync не возвращают значения, которые подходят для привязки к элементам управления списком. Вместо этого необходимо привязать к возвращаемым значениям методов GetVirtualizedFilesVector, GetVirtualizedFoldersVector и GetVirtualizedItemsVector класса FileInformationFactory. В следующем примере кода из примера StorageDataSource и GetVirtualizedFilesVector показан типичный шаблон использования. Не забудьте объявить функцию picturesLibrary в манифесте пакета приложения и убедиться, что в папке библиотеки изображений есть изображения.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    var library = Windows.Storage.KnownFolders.PicturesLibrary;
    var queryOptions = new Windows.Storage.Search.QueryOptions();
    queryOptions.FolderDepth = Windows.Storage.Search.FolderDepth.Deep;
    queryOptions.IndexerOption = Windows.Storage.Search.IndexerOption.UseIndexerWhenAvailable;

    var fileQuery = library.CreateFileQueryWithOptions(queryOptions);

    var fif = new Windows.Storage.BulkAccess.FileInformationFactory(
        fileQuery,
        Windows.Storage.FileProperties.ThumbnailMode.PicturesView,
        190,
        Windows.Storage.FileProperties.ThumbnailOptions.UseCurrentScale,
        false
        );

    var dataSource = fif.GetVirtualizedFilesVector();
    this.PicturesListView.ItemsSource = dataSource;
}

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

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

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

Привязка к данным, сгруппированных по ключу

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

  • ключ;
  • коллекция элементов, свойство которых соответствует этому ключу.

Если вернуться к примеру с книгами, при группировании книг по имени автора будет получена коллекция групп с именами автора, причем у каждой группы будет:

  • ключ (в этом случае — имя автора);
  • коллекция элементов BookSku, свойство AuthorName которых соответствует ключу группы.

Как правило, для отображения коллекции привязывается элемент управления ItemsSource элемента управления (например , ListView или GridView) непосредственно к свойству, возвращающего коллекцию. Если это плоская коллекция элементов, вам не нужно делать ничего специального. Но если это коллекция объектов группы (как и при привязке к группируемым данным), то вам нужны службы промежуточного объекта с именем CollectionViewSource , который находится между элементом управления элементами и источником привязки. Вы привязываете CollectionViewSource к свойству, возвращающее сгруппированные данные, и привязываете элемент управления items к CollectionViewSource. Дополнительная надстройка CollectionViewSource заключается в том, что она отслеживает текущий элемент, поэтому вы можете сохранить несколько элементов управления в синхронизации, привязав их ко всем тем же CollectionViewSource. Вы также можете получить доступ к текущему элементу программным способом с помощью свойства ICollectionView.CurrentItem объекта, возвращаемого свойством CollectionViewSource.View.

Чтобы активировать объект группировки объекта CollectionViewSource, задайте для IsSourceGrouped значение true. Необходимо ли также задать свойство ItemsPath , зависит от того, как создавать объекты группы. Существует два способа создания объекта группы: шаблона is-a-group и шаблона has-a-group. В шаблоне "is-a-group" объект группы является производным от типа коллекции (например, List<T>), поэтому объект группы фактически является группой элементов. С помощью этого шаблона вам не нужно задавать ItemsPath. В шаблоне "has-a-group" объект группы имеет одно или несколько свойств типа коллекции (например , List<T>), поэтому группа "имеет" группу элементов в виде свойства (или несколько групп элементов в виде нескольких свойств). С помощью этого шаблона необходимо задать ItemsPath имя свойства, содержащего группу элементов.

В приведенном ниже примере показан шаблон "has-a-group". Класс страницы имеет свойство ViewModel, которое возвращает экземпляр модели представления. CollectionViewSource привязывается к свойству Author модели представления (Авторы — это коллекция объектов группы), а также указывает, что это свойство Author.BookSkus, содержащее сгруппированные элементы. Наконец, GridView привязан к CollectionViewSource и имеет свой стиль группы, чтобы он смог отобразить элементы в группах.

<Page.Resources>
    <CollectionViewSource
    x:Name="AuthorHasACollectionOfBookSku"
    Source="{x:Bind ViewModel.Authors}"
    IsSourceGrouped="true"
    ItemsPath="BookSkus"/>
</Page.Resources>
...
<GridView
ItemsSource="{x:Bind AuthorHasACollectionOfBookSku}" ...>
    <GridView.GroupStyle>
        <GroupStyle
            HeaderTemplate="{StaticResource AuthorGroupHeaderTemplateWide}" ... />
    </GridView.GroupStyle>
</GridView>

Вы можете реализовать шаблон "is-a-group" одним из двух способов. Одним из способов является создание собственного класса группы. Наследуйте класс из списка<T> (где T является типом элементов). Например, public class Author : List<BookSku>. Второй способ — использовать выражение LINQ для динамического создания объектов группы (и класса группы) из таких значений свойств элементов BookSku . Такой подход — обслуживание только плоского списка элементов и группирование их вместе на лету — обычно это приложение, которое обращается к данным из облачной службы. Вы получаете гибкость для группирования книг по автору или по жанру (например), не нуждаясь в специальных классах группы, таких как автор и жанр.

В приведенном ниже примере показан шаблон "is-a-group" с помощью LINQ. На этот раз мы группируем книги по жанру, отображаемым с именем жанра в заголовках группы. Это означает путь свойства Key в ссылке на значение ключа группы.

using System.Linq;
...
private IOrderedEnumerable<IGrouping<string, BookSku>> genres;

public IOrderedEnumerable<IGrouping<string, BookSku>> Genres
{
    get
    {
        if (this.genres == null)
        {
            this.genres = from book in this.bookSkus
                          group book by book.genre into grp
                          orderby grp.Key
                          select grp;
        }
        return this.genres;
    }
}

Помните, что при использовании {x:Bind} с шаблонами данных необходимо указать тип, к которому привязан тип, задав значение x:DataType . Если тип является универсальным, мы не можем выразить это в разметке, поэтому вместо этого необходимо использовать {Binding} в шаблоне заголовка стиля группы.

    <Grid.Resources>
        <CollectionViewSource x:Name="GenreIsACollectionOfBookSku"
        Source="{x:Bind Genres}"
        IsSourceGrouped="true"/>
    </Grid.Resources>
    <GridView ItemsSource="{x:Bind GenreIsACollectionOfBookSku}">
        <GridView.ItemTemplate x:DataType="local:BookTemplate">
            <DataTemplate>
                <TextBlock Text="{x:Bind Title}"/>
            </DataTemplate>
        </GridView.ItemTemplate>
        <GridView.GroupStyle>
            <GroupStyle>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Key}"/>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
            </GroupStyle>
        </GridView.GroupStyle>
    </GridView>

Элемент управления SemanticZoom — отличный способ просмотра и навигации пользователей сгруппированных данных. Пример приложения Bookstore2 иллюстрирует использование SemanticZoom. В этом приложении можно просмотреть список книг, сгруппированных по автору (увеличенное представление) или просмотреть список переходов авторов (увеличенное представление). Список переходов обеспечивает гораздо более быструю навигацию, чем прокрутка по списку книг. Представления с увеличением и увеличением масштаба фактически являются элементами управления ListView или GridView, привязанными к одному и тому же объекту CollectionViewSource.

Иллюстрация семантики

При привязке к иерархическим данным, таким как подкатегории в категориях, можно выбрать отображение иерархических уровней в пользовательском интерфейсе с рядом элементов управления. Выбор в одном элементе управления элементами определяет содержимое последующих элементов управления. Списки можно синхронизировать, привязав каждый список к собственному CollectionViewSource и привязав экземпляры CollectionViewSource вместе в цепочке. Это называется представлением master/details (или list/details). Дополнительные сведения см. в разделе "Как привязать к иерархическим данным" и создать представление master/details.

Диагностика и отладка проблем привязки данных

Разметка привязки содержит имена свойств (и для C#, иногда поля и методы). Поэтому при переименовании свойства также потребуется изменить любую привязку, которая ссылается на нее. Забыли это сделать, что приводит к типичному примеру ошибки привязки данных, и ваше приложение либо не будет компилироваться, либо не будет работать правильно.

Как правило, объекты привязки, создаваемые с помощью расширений разметки {x:Bind} и {Binding}, выполняют аналогичные функции. Но {x:Bind} содержит сведения о типе источника привязки, и он создает исходный код во время компиляции. При использовании {x:Bind} вы получаете то же самое обнаружение проблем, которое вы получаете с остальным кодом. Это включает проверку во время компиляции выражений привязки и отладку путем задания точек останова в исходном коде, созданного в качестве частичного класса для страницы. Эти классы можно найти в файлах в obj папке с такими именами, как (для C#). <view name>.g.cs Если у вас возникли проблемы с привязкой, включите необработанные исключения в отладчике Microsoft Visual Studio. Отладчик разорвит выполнение на этом этапе, и вы можете отладить то, что произошло неправильно. Код, созданный {x:Bind}, следует одному и тому же шаблону для каждой части графа исходных узлов привязки, и вы можете использовать сведения в окне стека вызовов, чтобы определить последовательность вызовов, которые привели к проблеме.

{Binding} не содержит сведений о типе источника привязки. Но при запуске приложения с присоединенным отладчиком все ошибки привязки отображаются в окне вывода в Visual Studio.

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

Примечание. Этот раздел относится только к {Binding}, потому что невозможно создать привязки {x:Bind} в коде. Однако некоторые из одних и того же преимущества {x:Bind} можно достичь с помощью DependencyObject.RegisterPropertyChangedCallback, что позволяет зарегистрировать уведомления об изменениях для любого свойства зависимостей.

Вы также можете подключить элементы пользовательского интерфейса к данным с помощью процедурного кода вместо XAML. Для этого создайте объект Binding, задайте соответствующие свойства, а затем вызовите FrameworkElement.SetBinding или BindingOperations.SetBinding.SetBinding. Создание привязок программным способом полезно при выборе значений свойств привязки во время выполнения или совместного использования одной привязки между несколькими элементами управления. Обратите внимание, что после вызова SetBinding нельзя изменить значения свойств привязки.

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

<TextBox x:Name="MyTextBox" Text="Text"/>
// Create an instance of the MyColors class 
// that implements INotifyPropertyChanged.
MyColors textcolor = new MyColors();

// Brush1 is set to be a SolidColorBrush with the value Red.
textcolor.Brush1 = new SolidColorBrush(Colors.Red);

// Set the DataContext of the TextBox MyTextBox.
MyTextBox.DataContext = textcolor;

// Create the binding and associate it with the text box.
Binding binding = new Binding() { Path = new PropertyPath("Brush1") };
MyTextBox.SetBinding(TextBox.ForegroundProperty, binding);
' Create an instance of the MyColors class 
' that implements INotifyPropertyChanged. 
Dim textcolor As New MyColors()

' Brush1 is set to be a SolidColorBrush with the value Red. 
textcolor.Brush1 = New SolidColorBrush(Colors.Red)

' Set the DataContext of the TextBox MyTextBox. 
MyTextBox.DataContext = textcolor

' Create the binding and associate it with the text box.
Dim binding As New Binding() With {.Path = New PropertyPath("Brush1")}
MyTextBox.SetBinding(TextBox.ForegroundProperty, binding)

Сравнение функций {x:Bind} и {Binding}

Функция {x:Bind} в сравнении с {Binding} Примечания.
Путь — это свойство по умолчанию {x:Bind a.b.c}
-
{Binding a.b.c}
Свойство Path {x:Bind Path=a.b.c}
-
{Binding Path=a.b.c}
В x:Bind путь коренится на странице по умолчанию, а не DataContext.
Индексатор {x:Bind Groups[2].Title}
-
{Binding Groups[2].Title}
Привязывается к указанному элементу в коллекции. Поддерживаются только целые индексы.
Вложенные свойства {x:Bind Button22.(Grid.Row)}
-
{Binding Button22.(Grid.Row)}
Присоединенные свойства задаются с помощью скобок. Если свойство не объявляется в пространстве имен XAML, префиксируйте его с пространством имен XML, которое должно быть сопоставлено с пространством имен кода в начале документа.
Приведение {x:Bind groups[0].(data:SampleDataGroup.Title)}
-
Не требуется для {Binding}.
Приведения задаются с помощью круглых скобок. Если свойство не объявляется в пространстве имен XAML, префиксируйте его с пространством имен XML, которое должно быть сопоставлено с пространством имен кода в начале документа.
Преобразователь {x:Bind IsShown, Converter={StaticResource BoolToVisibility}}
-
{Binding IsShown, Converter={StaticResource BoolToVisibility}}
Преобразователи должны быть объявлены в корне страницы или resourceDictionary или в App.xaml.
ConverterParameter, ConverterLanguage {x:Bind IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr}
-
{Binding IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr}
Преобразователи должны быть объявлены в корне страницы или resourceDictionary или в App.xaml.
TargetNullValue {x:Bind Name, TargetNullValue=0}
-
{Binding Name, TargetNullValue=0}
Используется, когда конечная часть выражения привязки имеет значение NULL. Используйте одинарные кавычки для строкового значения.
Резервное значение {x:Bind Name, FallbackValue='empty'}
-
{Binding Name, FallbackValue='empty'}
Используется, если любая часть пути для привязки (за исключением конечной) имеет значение NULL.
ElementName {x:Bind slider1.Value}
-
{Binding Value, ElementName=slider1}
При использовании {x:Bind} вы привязываетесь к полю; Путь коренится на странице по умолчанию, поэтому любой именованный элемент можно получить через его поле.
RelativeSource: Self <Rectangle x:Name="rect1" Width="200" Height="{x:Bind rect1.Width}" ... />
-
<Rectangle Width="200" Height="{Binding Width, RelativeSource={RelativeSource Self}}" ... />
При помощи {x:Bind}назовите элемент и используйте его имя в Path.
RelativeSource: TemplatedParent Не требуется для {x:Bind}
-
{Binding <path>, RelativeSource={RelativeSource TemplatedParent}}
Если используется расширение разметки {x:Bind}, TargetType для ControlTemplate указывает на привязку к родительскому шаблону. Для {Binding} обычную привязку шаблонов можно использовать в шаблонах элементов управления в большинстве сценариев. Однако используйте TemplatedParent, если вам требуется преобразователь или двусторонняя привязка.<
Исходный код Не требуется для {x:Bind}
-
<ListView ItemsSource="{Binding Orders, Source={StaticResource MyData}}"/>
Для {x:Bind} можно напрямую использовать именованный элемент, свойство или статический путь.
Режим {x:Bind Name, Mode=OneWay}
-
{Binding Name, Mode=TwoWay}
Режим может быть OneTime, OneWay или TwoWay. {x:Bind} по умолчанию используется oneTime; {Binding} по умолчанию имеет значение OneWay.
UpdateSourceTrigger {x:Bind Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
-
{Binding UpdateSourceTrigger=PropertyChanged}
У UpdateSourceTrigger может быть значение Default, LostFocus или PropertyChanged. {x:Bind} не поддерживает UpdateSourceTrigger=Explicit. В расширении разметки {x:Bind} поведение PropertyChanged используется во всех случаях, кроме TextBox.Text, для которого используется поведение LostFocus.