深入了解数据绑定

重要 API

注释

本主题详细介绍了数据绑定功能。 有关简短的实际简介,请参阅 数据绑定概述

本主题介绍驻留在 Windows.UI.Xaml.Data 命名空间中的 API 的数据绑定。

数据绑定是应用 UI 显示数据的一种方法,还可以选择与该数据保持同步。 通过数据绑定,可以将数据关注与 UI 的关注区分开,这会导致更简单的概念模型,以及应用的可读性、可测试性和可维护性。

首次显示 UI 时,可以使用数据绑定来仅显示数据源中的值,但不能响应这些值中的更改。 这是一种称为 “一次性”的绑定模式,它适用于运行时不会更改的值。 或者,可以选择“观察”值并在它们更改时更新 UI。 此模式称为 单向模式,适用于只读数据。 最终,可以选择同时观察和更新,以便用户对 UI 中的值所做的更改会自动推送回数据源。 此模式称为 双向模式,适用于读写数据。 下面是一些示例。

  • 可以使用一次性模式将 图像 绑定到当前用户的照片。
  • 可以使用单向模式将 ListView 绑定到按报纸分区分组的实时新闻文章集合。
  • 可以使用双向模式将 TextBox 绑定到表单中的客户名称。

与模式无关,有两种类型的绑定,它们通常在 UI 标记中声明。 可以选择使用 {x:Bind} 标记扩展{Binding} 标记扩展。 你甚至可以在同一个应用中使用两者混合使用,即使在相同的 UI 元素上也是如此。 {x:Bind} 是 Windows 10 的新增功能,具有更好的性能。 本主题中所述的所有详细信息都适用于这两种类型的绑定,除非我们明确说明。

演示 {x:Bind} 的示例应用

演示 {Binding} 的示例应用

每个绑定都涉及这些部分

  • 绑定源。 这是绑定的数据源,它可以是具有要在 UI 中显示的值的任何类的实例。
  • 绑定目标。 这是 UI 中显示数据的 FrameworkElementDependencyProperty
  • 绑定对象。 这是将数据值从源传输到目标以及从目标传回源的片段。 绑定对象是在 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 的实现仅适用于一次性绑定。 但是单向绑定和双向绑定非常常见,在这些类型的绑定中,UI 会自动更新以响应绑定源的数据值的变化。 为了使这些类型的绑定正常工作,需要使绑定源“可观察”到绑定对象。 因此,在我们的示例中,如果想要单向或双向绑定到 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#,则无需实现上面显示的模式,则只需从 QuizGame 示例(在“Common”文件夹中)中找到的 BindableBase 基类派生。 下面是该外观的示例。

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,在应用程序中声明的任何从基类派生的运行时类称为 可组合 类。 可组合类存在约束。 要使应用程序通过 Visual Studio 和 Microsoft 应用商店使用的 Windows 应用认证工具包 测试来验证提交(因此,应用程序能够成功引入到 Microsoft 应用商店),可组合类最终必须派生自 Windows 基类。 这意味着继承层次结构的根目录的类必须是源自 Windows.* 命名空间的类型。 如果需要从基类派生运行时类(例如,要为所有要派生的视图模型实现 BindableBase 类),则可以从 Windows.UI.Xaml.DependencyObject 派生。

使用 String.Emptynull 参数引发 PropertyChanged 事件表示应重新读取对象上的所有非索引器属性。 可以引发该事件以指示对象上的索引器属性已更改,方法是对特定索引器使用“Item[indexer]”参数(其中 索引器 是索引值),或为所有索引器使用“Item[]”的值。

绑定源可以视为一个对象,其属性包含数据或作为对象的集合。 在 C# 和 Visual Basic 代码中,可以一次性绑定到实现 List(Of T) 的对象,以显示运行时不会更改的集合。 对于可观测集合(观察何时向集合中添加和删除项),请改为单向绑定到 ObservableCollection(Of T)。 在 C++/CX 代码中,可以同时绑定到可观测集合和非可观测集合的 向量<T,C++> /WinRT 具有其自己的类型。 若要绑定到自己的集合类,请使用下表中的指南。

Scenario C# 和 VB (CLR) C++/WinRT C++/CX
绑定到对象。 可以是任何对象。 可以是任何对象。 对象必须具有 BindableAttribute 或实现 ICustomPropertyProvider
从绑定对象获取属性更改通知。 对象必须实现 INotifyPropertyChanged 对象必须实现 INotifyPropertyChanged 对象必须实现 INotifyPropertyChanged
绑定到集合。 List(Of T) IInspectableIBindableObservableVectorIVector。 请参阅 XAML 项控件;使用 C++/WinRT 绑定到 C++/WinRT 集合集合 矢量<T>
从绑定集合获取集合更改通知。 ObservableCollection(Of T) IInspectableIObservableVector。 例如 ,winrt::single_threaded_observable_vector<T> IObservableVector<T>. 向量<T> 实现此接口。
实现支持绑定的集合。 扩展列表(Of T)或实现 IList、IListOf Object)、IEnumerableIEnumerable(Of Object)。 不支持绑定到泛型 IList(Of T)IEnumerable(Of T)。 实现 IInspectableIVector。 请参阅 XAML 项控件;使用 C++/WinRT 绑定到 C++/WinRT 集合集合 实现 IBindableVectorIBindableIterableIVector<Object^>、 IIterable<Object^>、 IVector<IInspectable*>或 IIterable<IInspectable*>。 不支持绑定到泛型 IVector<T>IIterable<T>
实现支持集合更改通知的集合。 扩展 ObservableCollection(Of T) 或实现 (非泛型) IListINotifyCollectionChanged 实现 IInspectableIBindableObservableVector 的 IObservableVector 实现 IBindableVectorIBindableObservableVector
实现支持增量加载的集合。 扩展 ObservableCollection(Of T) 或实现 (非泛型) IListINotifyCollectionChanged。 此外,实现 ISupportIncrementalLoading 实现 IInspectableIBindableObservableVector 的 IObservableVector 此外,实现 ISupportIncrementalLoading 实现 IBindableVectorIBindableObservableVectorISupportIncrementalLoading

可以使用增量加载将列表控件绑定到任意大型数据源,但仍能实现高性能。 例如,可以将列表控件绑定到必应图像查询结果,而无需同时加载所有结果。 相反,只需立即加载一些结果,并根据需要加载其他结果。 若要支持增量加载,必须在支持集合更改通知的数据源上实现 ISupportIncrementalLoading 。 当数据绑定引擎请求更多数据时,数据源必须发出相应的请求,集成结果,然后发送相应的通知以更新 UI。

绑定目标

在下面的两个示例中, Button.Content 属性是绑定目标,其值设置为声明绑定对象的标记扩展。 首先显示 {x:Bind} ,然后显示 {Binding}。 在标记中声明绑定是一种常见情况(方便、可读和可工具)。 但是,如果需要,可以避免标记和命令性地(以编程方式)创建 Binding 类的实例。

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

如果使用的是 C++/WinRT 或 Visual C++ 组件扩展(C++/CX),则需要将 BindableAttribute 属性添加到要使用的 {Binding} 标记扩展的任何运行时类。

重要

如果使用的是 C++/WinRT,则已安装 Windows SDK 版本 10.0.17763.0(Windows 10 版本 1809 或更高版本), 则 BindableAttribute 属性可用。 如果没有该属性,则需要实现 ICustomPropertyProviderICustomProperty 接口才能使用 {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 指定的值。 此值在页面本身的上下文中进行解释,在本例中,路径首先引用刚刚添加到 MainPage 页面的 ViewModel 属性。 该属性返回 HostViewModel 实例,因此我们可以点入该对象以访问 HostViewModel.NextButtonText 属性。 我们指定 Mode,以替代一次性 {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 失去焦点时,对 TextBox.Text 的更改将发送到双向绑定源,而不是在每个用户击键之后。

DataTemplate 和 x:DataType

DataTemplate (无论是用作项模板、内容模板还是标头模板), 路径 的值不会在页面的上下文中解释,而是在正在模板化的数据对象的上下文中解释。 在数据模板中使用 {x:Bind} 时,以便在编译时验证其绑定(以及为其生成的高效代码), DataTemplate 需要使用 x:DataType 声明其数据对象的类型。 下面给出的示例可用作绑定到 SampleDataGroup 对象的集合的项控件的 ItemTemplate

<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>

Path 中的弱类型对象

例如,假设你有一个名为 SampleDataGroup 的类型,该类型实现名为 Title 的字符串属性。 并且你有一个属性 MainPage.SampleDataGroupAsObject,该属性的类型为对象,但实际上返回 SampleDataGroup 的实例。 绑定 <TextBlock Text="{x:Bind SampleDataGroupAsObject.Title}"/> 将导致编译错误,因为类型对象上找不到 Title 属性。 这样做的补救措施是向路径语法添加强制转换,如下所示: <TextBlock Text="{x:Bind ((data:SampleDataGroup)SampleDataGroupAsObject).Title}"/> 下面是另一个示例,其中 Element 声明为对象,但实际上是 TextBlock: <TextBlock Text="{x:Bind Element.Text}"/>。 演员纠正了这个问题: <TextBlock Text="{x:Bind ((TextBlock)Element).Text}"/>

如果数据以异步方式加载

支持 {x:Bind} 的代码在页面的分部类中在编译时生成。 可以在文件夹中obj找到这些文件,其名称类似于(对于 C#)。 <view name>.g.cs 生成的代码包括页面 的 Loading 事件的处理程序,该处理程序在表示页面绑定的生成的类上调用 Initialize 方法。 依次初始化Update 以开始在绑定源和目标之间移动数据。 加载 在页面或用户控件的第一个度量值传递之前引发。 因此,如果数据以异步方式加载,在调用 Initialize 时可能无法准备就绪。 因此,加载数据后,可以通过调用 this.Bindings.Update();强制初始化一次性绑定。 如果只需要异步加载数据的一次性绑定,那么以这种方式初始化它们比采用单向绑定和侦听更改要便宜得多。 如果数据未进行精细更改,并且可能作为特定作的一部分进行更新,则可以一次性进行绑定,并随时通过调用更新强制手动 更新

注释

{x:Bind} 不适合后期绑定方案,例如导航 JSON 对象的字典结构,也不适合鸭子键入。 “鸭子键入”是基于属性名称的词法匹配的弱形式(如,“如果它像鸭子一样行走,游泳和夸克,那么它是鸭子)。” 使用鸭子键入时,对 Age 属性的绑定同样满足 于 PersonWine 对象(假设这些类型各自具有 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,则已安装 Windows SDK 版本 10.0.17763.0(Windows 10 版本 1809 或更高版本), 则 BindableAttribute 属性可用。 如果没有该属性,则需要实现 ICustomPropertyProviderICustomProperty 接口才能使用 {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} 默认的单向工作在这里有效。

UI 元素的 DataContext 默认值是其父元素的继承值。 当然,可以通过显式设置 DataContext 来替代该默认设置,后者又由子级默认继承。 如果要具有使用同一源的多个绑定,则显式设置元素上的 DataContext 非常有用。

绑定对象具有 Source 属性,该属性默认为声明绑定的 UI 元素的 DataContext 。 可以通过在绑定上显式设置 SourceRelativeSourceElementName 来替代此默认值(有关详细信息,请参阅 {Binding} )。

DataTemplate 中, DataContext 会自动设置为正在模板化的数据对象。 以下示例可用作绑定到具有名为 TitleDescription 的字符串属性的任意类型的集合的项控件的 ItemTemplate

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

注释

默认情况下,当 TextBox 失去焦点时,TextBox.Text 的更改将发送到双向绑定源。 若要在每个用户击键后发送更改,请将 UpdateSourceTrigger 设置为标记中的绑定上的 PropertyChanged 。 还可以通过将 UpdateSourceTrigger 设置为 Explicit 来完全控制何时将更改发送到源。 然后处理文本框(通常是 TextBox.TextChanged)上的事件,对目标调用 GetBindingExpression 以获取 BindingExpression 对象,最后调用 BindingExpression.UpdateSource 以编程方式更新数据源。

Path 属性支持各种语法选项,用于绑定到嵌套属性、附加属性和整数和字符串索引器。 有关详细信息,请参阅 属性路径语法。 绑定到字符串索引器可提供绑定到动态属性的效果,而无需实现 ICustomPropertyProvider ElementName 属性对于元素到元素绑定非常有用。 RelativeSource 属性有多个用途,其中一个是 ControlTemplate 中模板绑定的更强大的替代方法。 有关其他设置,请参阅 {Binding} 标记扩展Binding 类。

如果源和目标的类型不相同,该怎么办?

如果要基于布尔属性的值控制 UI 元素的可见性,或者想要呈现具有数值范围或趋势函数的颜色的 UI 元素,或者如果要在需要字符串的 UI 元素属性中显示日期和时间值,则 然后,需要将值从一种类型转换为另一种类型。 在某些情况下,正确的解决方案是从绑定源类公开正确类型的另一个属性,并使转换逻辑封装并在那里可测试。 但是,当你拥有大量源和目标属性或大型组合时,这并不灵活,也不可缩放。 在这种情况下,可以选择以下几个选项:

  • 如果使用 {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}}"/>

如果为绑定定义了 Converter 参数,绑定引擎将调用 ConvertConvertBack 方法。 从源传递数据时,绑定引擎将调用 Convert 并将返回的数据传递到目标。 从目标(对于双向绑定)传递数据时,绑定引擎将调用 ConvertBack 并将返回的数据传递给源。

转换器还具有可选参数: ConverterLanguage,它允许指定转换中使用的语言,以及允许传递转换逻辑的参数的 ConverterParameter。 有关使用转换器参数的示例,请参阅 IValueConverter

注释

如果转换中有错误,请不要引发异常。 相反,返回 DependencyProperty.UnsetValue,这将停止数据传输。

若要在无法解析绑定源时显示要使用的默认值,请在标记中的绑定对象上设置 FallbackValue 属性。 这可用于处理转换和格式设置错误。 绑定到异类类型的绑定集合中可能不存在的所有对象的源属性也很有用。

如果将文本控件绑定到不是字符串的值,数据绑定引擎会将该值转换为字符串。 如果值为引用类型,数据绑定引擎将通过调用 ICustomPropertyProvider.GetStringRepresentation 或 IStringable.ToString 来检索字符串值(如果可用),否则将调用 Object.ToString 但是,请注意,绑定引擎将忽略隐藏基类实现的任何 ToString 实现。 子类实现应替代基类 ToString 方法。 同样,在本机语言中,所有托管对象似乎都实现了 ICustomPropertyProviderIStringable。 但是,对 GetStringRepresentationIStringable.ToString 的所有调用都路由到 Object.ToString 或该方法的重写,并且永远不会路由到隐藏基类实现的新 ToString 实现。

注释

从 Windows 10 版本 1607 开始,XAML 框架提供内置布尔值到 Visibility 转换器。 转换器将 true 映射到 Visible 枚举值, 将 false 映射到 Collapsed ,以便无需创建转换器即可将 Visibility 属性绑定到布尔值。 若要使用内置转换器,应用的最低目标 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>

在可重用样式中混合 {x:Bind} 和 {Binding}

虽然在 DataTemplates 中使用 {x:Bind} 显示上一个示例,但还可以创建可重用样式,这些样式结合了 {x:Bind} 和 {Binding} 标记扩展。 如果要使用 {x:Bind} 将某些属性绑定到编译时已知值,并将其他属性绑定到使用 {Binding} 的运行时 DataContext 值,这非常有用。

以下示例演示如何创建使用两种绑定方法的可重用按钮样式:

TemplatesResourceDictionary.xaml

<ResourceDictionary
    x:Class="ExampleNamespace.TemplatesResourceDictionary"
    .....
    xmlns:examplenamespace="using:ExampleNamespace">
    
    <!-- DataTemplate using x:Bind -->
    <DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
        <Grid>
            <TextBlock Text="{x:Bind Name}"/>
        </Grid>
    </DataTemplate>
    
    <!-- Style that mixes x:Bind and Binding -->
    <Style x:Key="CustomButtonStyle" TargetType="Button">
        <Setter Property="Background" Value="{Binding ButtonBackgroundBrush}"/>
        <Setter Property="Foreground" Value="{Binding ButtonForegroundBrush}"/>
        <Setter Property="FontSize" Value="16"/>
        <Setter Property="Margin" Value="4"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border x:Name="RootBorder"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            CornerRadius="4">
                        <StackPanel Orientation="Horizontal" 
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center">
                            <!-- x:Bind to a static property or page-level property -->
                            <Ellipse Width="8" Height="8" 
                                     Fill="{x:Bind DefaultIndicatorBrush}" 
                                     Margin="0,0,8,0"/>
                            <!-- Binding to DataContext -->
                            <ContentPresenter x:Name="ContentPresenter"
                                              Content="{TemplateBinding Content}"
                                              Foreground="{TemplateBinding Foreground}"
                                              FontSize="{TemplateBinding FontSize}"/>
                        </StackPanel>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="PointerOver">
                                    <VisualState.Setters>
                                        <!-- Binding to DataContext for hover color -->
                                        <Setter Target="RootBorder.Background" 
                                                Value="{Binding ButtonHoverBrush}"/>
                                    </VisualState.Setters>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <VisualState.Setters>
                                        <!-- x:Bind to a compile-time known resource -->
                                        <Setter Target="RootBorder.Background" 
                                                Value="{x:Bind DefaultPressedBrush}"/>
                                    </VisualState.Setters>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

TemplatesResourceDictionary.xaml.cs

using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
 
namespace ExampleNamespace
{
    public partial class TemplatesResourceDictionary
    {
        public TemplatesResourceDictionary()
        {
            InitializeComponent();
        }
        
        // Properties for x:Bind - these are compile-time bound
        public SolidColorBrush DefaultIndicatorBrush { get; } = 
            new SolidColorBrush(Colors.Green);
            
        public SolidColorBrush DefaultPressedBrush { get; } = 
            new SolidColorBrush(Colors.DarkGray);
    }
}

MainPage.xaml 中提供运行时值的 ViewModel 中的用法:

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

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

    <StackPanel Margin="20">
        <!-- This button uses the mixed binding style -->
        <Button Content="Save" Style="{StaticResource CustomButtonStyle}"/>
        <Button Content="Cancel" Style="{StaticResource CustomButtonStyle}"/>
    </StackPanel>
</Page>

ButtonThemeViewModel.cs(提供运行时绑定值的 DataContext):

using System.ComponentModel;
using Windows.UI;
using Windows.UI.Xaml.Media;

namespace ExampleNamespace
{
    public class ButtonThemeViewModel : INotifyPropertyChanged
    {
        private SolidColorBrush _buttonBackgroundBrush = new SolidColorBrush(Colors.LightBlue);
        private SolidColorBrush _buttonForegroundBrush = new SolidColorBrush(Colors.DarkBlue);
        private SolidColorBrush _buttonHoverBrush = new SolidColorBrush(Colors.LightCyan);

        public SolidColorBrush ButtonBackgroundBrush
        {
            get => _buttonBackgroundBrush;
            set
            {
                _buttonBackgroundBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonBackgroundBrush)));
            }
        }

        public SolidColorBrush ButtonForegroundBrush
        {
            get => _buttonForegroundBrush;
            set
            {
                _buttonForegroundBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonForegroundBrush)));
            }
        }

        public SolidColorBrush ButtonHoverBrush
        {
            get => _buttonHoverBrush;
            set
            {
                _buttonHoverBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonHoverBrush)));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

在本示例中:

  • {Binding} 用于依赖于 DataContext 的属性(ButtonBackgroundBrush、ButtonForegroundBrush、ButtonHoverBrush)
  • {x:Bind} 用于编译时已知且属于 ResourceDictionary 本身的属性(DefaultIndicatorBrush、DefaultPressedBrush)
  • 该样式是可重用的,可应用于任何按钮
  • 运行时主题可以通过 DataContext 实现,同时仍受益于静态元素 {x:Bind} 的性能

事件绑定和 ICommand

{x:Bind} 支持称为事件绑定的功能。 使用此功能,可以使用绑定为事件指定处理程序,这是使用代码隐藏文件中的方法处理事件的附加选项。 假设你在 MainPage 类上有一个 RootFrame 属性。

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

然后,可以将按钮的 Click 事件绑定到 RootFrame 属性返回的 Frame 对象上的方法,如下所示。 请注意,我们还将按钮的 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} 都使用命令。 因此,无需多次实现命令模式,可以使用 QuizGame 示例(在“Common”文件夹中)中找到的 DelegateCommand 帮助程序类。

绑定到文件夹或文件的集合

可以使用 Windows.Storage 命名空间中的 API 检索文件夹和文件数据。 但是,各种 GetFilesAsyncGetFoldersAsyncGetItemsAsync 方法不会返回适合绑定到列表控件的值。 相反,必须绑定到 FileInformationFactory 类的 GetVirtualizedFilesVectorGetVirtualizedFoldersVectorGetVirtualizedItemsVector 方法的返回值。 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 属性与组的键匹配。

通常,若要显示集合,可以将项控件(如 ListViewGridView)的 ItemsSource 直接绑定到返回集合的属性。 如果这是项的平面集合,则无需执行任何特殊作。 但是,如果它是组对象的集合(就像绑定到分组数据时一样),则需要一个名为 CollectionViewSource 的中间对象的服务,该对象位于项控件和绑定源之间。 将 CollectionViewSource 绑定到返回分组数据的属性,并将项控件绑定到 CollectionViewSourceCollectionViewSource 的额外增值是它跟踪当前项,因此可以通过将它们全部绑定到同一 CollectionViewSource 来保持多个项控件同步。 还可以通过 CollectionViewSource.View 属性返回对象的 ICollectionView.CurrentItem 属性以编程方式访问当前项。

若要激活 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”模式。 一种方法是创作自己的组类。 从 List<T> 派生类(其中 T 是项的类型)。 例如,public class Author : List<BookSku>。 第二种方法是使用 LINQ 表达式从 BookSku 项的属性值等方式动态创建组对象(和组类)。 此方法(仅维护一个平面列表并动态将它们分组在一起)是访问云服务数据的应用的典型方法。 你可以灵活地按作者或流派(例如)对书籍进行分组,而无需特殊的组类,例如 作者流派

下面的示例演示了使用 LINQ 的“is-a-group”模式。 这一次,我们按流派对书籍进行分组,并在组标题中以流派名称显示。 这由对组键值的引用中的“ 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。 在该应用中,可以查看按作者分组的书籍列表(放大视图),也可以缩小以查看作者的跳转列表(缩小视图)。 跳转列表提供比滚动浏览书籍列表更快得多的导航。 放大缩小视图和缩小视图实际上是绑定到同一 CollectionViewSource的 ListViewGridView 控件。

SemanticZoom 的插图

绑定到分层数据(如类别中的子类别)时,可以选择使用一系列项控件在 UI 中显示分层级别。 一个项目控件中的选定内容决定了后续项控件的内容。 可以通过将每个列表绑定到其自己的 CollectionViewSource 并将 CollectionViewSource 实例绑定在链中来使列表保持同步。 这称为大纲/详细信息(或列表/详细信息)视图。 有关详细信息,请参阅 如何绑定到分层数据并创建主视图/详细信息视图

诊断和调试数据绑定问题

绑定标记包含属性的名称(对于 C#,有时为字段和方法)。 因此,重命名属性时,还需要更改引用它的任何绑定。 忘记这样做会导致数据绑定 bug 的典型示例,你的应用要么无法编译,要么无法正确运行。

由 {x:Bind}{Binding} 创建的绑定对象基本上是等效的。 但 {x:Bind} 具有绑定源的类型信息,并在编译时生成源代码。 使用 {x:Bind} 可以得到与其余代码相同的问题检测。 这包括绑定表达式的编译时验证,以及在作为页面分部类生成的源代码中设置断点进行调试。 可以在文件夹中obj的文件中找到这些类,名称如下(对于 C#)。 <view name>.g.cs 如果绑定出现问题,请在 Microsoft Visual Studio 调试器中打开 “中断未处理的异常 ”。 调试器将在该时间点中断执行,然后可以调试出问题所在。 {x:Bind} 生成的代码遵循绑定源节点图的每个部分的相同模式,你可以使用 “调用堆栈 ”窗口中的信息来帮助确定导致问题的调用序列。

{Binding} 没有绑定源的类型信息。 但是,当你在附加调试器的情况下运行应用时,任何绑定错误都会显示在 Visual Studio 的 “输出 ”窗口中。

在代码中创建绑定

注意 此部分仅适用于 {Binding},因为无法在代码中创建 {x:Bind} 绑定。 但是,可以使用 DependencyObject.RegisterPropertyChangedCallback 实现 {x:Bind} 的某些相同优势,这使你可以注册任何依赖属性上的更改通知。

还可以使用过程代码而不是 XAML 将 UI 元素连接到数据。 为此,请创建新的 Binding 对象,设置相应的属性,然后调用 FrameworkElement.SetBindingBindingOperations.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。
Indexer {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}}
转换器必须在 Page/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}
转换器必须在 Page/ResourceDictionary 的根目录或 App.xaml 中声明。
TargetNullValue {x:Bind Name, TargetNullValue=0}
-
{Binding Name, TargetNullValue=0}
当绑定表达式的叶为 null 时使用。 对字符串值使用单引号。
FallbackValue {x:Bind Name, FallbackValue='empty'}
-
{Binding Name, FallbackValue='empty'}
当绑定路径的任何部分(叶除外)为 null 时使用。
ElementName {x:Bind slider1.Value}
-
{Binding Value, ElementName=slider1}
使用 {x:Bind} 可以绑定到字段;路径默认植根于 Page,因此可以通过其字段访问任何命名元素。
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}}
ControlTemplate 上的 {x:Bind} TargetType 表示绑定到模板父级。 对于 {Binding} 常规模板绑定,可在控件模板中用于大多数用途。 但是,使用 TemplatedParent 需要在其中使用转换器或双向绑定。<
来源 {x:Bind} 不需要
-
<ListView ItemsSource="{Binding Orders, Source={StaticResource MyData}}"/>
对于 {x:Bind},可以直接使用命名元素,使用属性或静态路径。
Mode {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} 对除 TextBox.Text 以外的所有情况使用 PropertyChanged 行为,其中它使用 LostFocus 行为。