跳到主要内容

WinUI 3 数据绑定:如何让 UI 自动更新?

· 阅读需 4 分钟
作者:小烨App

1. 什么是 UI 自动更新​

想象一个最常见的场景:

你在一个输入框里打字,屏幕另一边的文字标签同步变化,不需要你点任何“保存”或“刷新”按钮。

这就是 UI 自动更新。

没有数据绑定的做法​

数据变化的地方越多,这种“手动搬运”的代码就越多。改一个字段漏掉一个地方,界面就会显示不一致。

有数据绑定的做法​

中间两步完全由框架完成。你只需要做一件事:告诉 UI 和数据之间是什么关系。

下图展示了一个可输入文本框和一个展示文字的文本标签,当在文本框输入文字时,文字自动传递给绑定变量,然后又反向绑定到文本标签,实现了实时自动更新。


2. 让 UI 自动更新的两个核心​

2.1 数据绑定:建立连接​

在 XAML 中声明“这个控件的这个属性,等于那个数据的那个属性”。

比如:

<TextBlock Text="{x:Bind 用户姓名}" />

这行代码的意思:这个 TextBlock 显示的内容,永远等于“用户姓名”这个数据。

不需要写任何 C# 代码来赋值。

2.2 INotifyPropertyChanged:发送通知​

这是初学者最容易踩的坑。

普通 C# 属性变化时,WinUI 不会自动感知。你必须让数据类主动说一声“我变了”。

public string 用户姓名 { get; set; }

private string _用户姓名;
public string 用户姓名
{
get => _用户姓名;
set
{
_用户姓名 = value;
通知UI我变了();
}
}

通知的方式有多种:

方式一:原生 INotifyPropertyChanged

继承 INotifyPropertyChanged,实现 OnPropertyChanged 接口,并在绑定变量变化时调用通知接口。

public event PropertyChangedEventHandler PropertyChanged;

private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

方式二:借助 CommunityToolkit.Mvvm

使用现成的 .NET 库来简化通知过程。


3. 基本示例:制作一个简单的应用启动器​

用一个实际项目来串起所有概念。界面很简单:

  • GridView 网格展示应用列表(图标 + 名称)
  • 点击某个应用后,启动该应用

3.1 项目结构​

这里简化结构,主要包含两大部分:

  • ViewModel(视图模型):包含了数据定义,并负责通知
  • MyAppsPage(界面):XAML,负责显示

3.2 数据模型​

定义每个 App 应用长什么样,主要信息包含:图标、名称、描述。

3.3 视图模型​

这是整个数据绑定的中枢。

这里主要暴露一个应用列表,用 ObservableCollection 类型,这样增删应用时 UI 会自动刷新。

public class AppLauncherViewModel : ObservableObject
{
public static ObservableCollection<AppInfo> AppItems;
}

3.4 界面 XAML​

核心绑定写法:

XAML 中的写法含义
ItemsSource="{x:Bind AppItems}"GridView 的数据来源是 ViewModel 里的 Apps 列表
Text="{x:Bind Icon}"DataTemplate 内部绑定到当前项的 Icon 图标
Text="{x:Bind Name}"DataTemplate 内部绑定到当前项的 Name

3.5 运行效果​

最终运行起来如下所示:

  • 界面展示一行应用图标和名称
  • 鼠标点击任意应用,启动对应 App

全程没有写任何“点击 → 找控件 → 赋值”的代码。


4. 小结​

如果发现绑定未生效,最可能的原因主要如下:

现象可能的原因
数据变了,UI 不动属性没实现 INotifyPropertyChanged
列表新增了数据,GridView 不显示用了 List 而不是 ObservableCollection

WinUI 3 的数据绑定,主要就是两件事:

  1. 声明关系:XAML 里用绑定语法
  2. 发出通知:ViewModel 实现 INotifyPropertyChanged

理解这套关系后,写 UI 就变成“描述数据长什么样”,而不是“搬运数据”。代码量减少,bug 也减少。