如何绑定到 ListView 中的模型而不是 WinUI3 中的属性?
Posted
技术标签:
【中文标题】如何绑定到 ListView 中的模型而不是 WinUI3 中的属性?【英文标题】:How to bind to a model in ListView instead of property in WinUI3? 【发布时间】:2021-12-31 21:39:54 【问题描述】:我正在尝试直接绑定到模型 (similar to the situation here),而不是该模型上的属性,但它不起作用。 I previously asked a question about this,答案在 UWP 中有效。我现在在 WinUI3(打包的 UWP)中工作,不确定是否适用相同的解决方案。
我有一堂课:
public class Message
public string Title get; set;
public string Content get; set;
我有一个显示该类的 UserControl:
public sealed partial class MessageControl : UserControl
/// <summary>
/// The message to display.
/// </summary>
public Message Message get; set;
public MessageControl()
this.InitializeComponent();
使用 XAML:
<UserControl
x:Class="MessageClient.Controls.EmailControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MessageClient.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<StackPanel>
<!-- Displays the title of the message. -->
<TextBlock Name="HeaderTextBlock"
Text="x:Bind Message.Title, Mode=OneWay"></TextBlock>
<!-- Displays the content of the message. -->
<TextBlock Name="ContentPreviewTextBlock"
Text="x:Bind Message.Content, Mode=OneWay"></TextBlock>
</StackPanel>
</Grid>
</UserControl>
现在,我有一个在列表视图内显示该控件的窗口:
<Window
x:Class="MessageClient.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:EmailClient"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:MessageClient.Controls" xmlns:models="using:MessageClient.Models"
mc:Ignorable="d">
<Grid>
<!-- The list of messages. -->
<ListView x:Name="MessagesListView"
ItemsSource="x:Bind Messages">
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:Message">
<controls:MessageControl Margin="5"
Message="x:Bind Mode=OneWay"></controls:MessageControl>
<!-- TEST 1 -->
<!--<TextBlock Text="x:Bind Title"></TextBlock>-->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!-- TEST 2 -->
<!--<controls:MessageControl Message="x:Bind TestMessage, Mode=OneWay"></controls:MessageControl>-->
</Grid>
</Window>
Window 后面的代码是:
public sealed partial class MainWindow : Window
public ObservableCollection<Message> Messages;
public Message TestMessage;
public MainWindow()
this.InitializeComponent();
// Populate the test message.
this.PopulateTestMessages();
private void PopulateTestMessages()
// The TestDataGenerator just returns a staticaly defined list of test messages.
this.Messages = new ObservableCollection<Message>(TestDataGenerator.GetTestMessages(10));
this.TestMessage = this.Messages.First();
当我运行此代码(编译并运行)时,我得到一个窗口,其中包含 ListView
(10) 中的预期项目数,但它们都是空白的。也没有报告 XAML 绑定失败(通过 Visual Studio 2022 中的新功能)。为了对此进行调查,我在列表视图(在 cmets 中表示为 TEST 1)内添加了一个文本块,该文本块绑定到 Message
的 Title
属性。这按预期工作,显示了 10 条消息的正确标题。然后,我将单个MessageControl
添加到ListView
之外的Window
(在cmets 中表示为TEST 2)绑定到Window
上的单个Message
属性。这也完全符合预期。
我错过了什么吗?当数据存在并与其他绑定配置一起使用时,为什么直接绑定到模型的特定情况(而不是该模型上的属性 - 即没有路径的绑定)不起作用?
【问题讨论】:
【参考方案1】:事实证明,这个特定案例揭示了绑定在 XAML 中如何工作的一些顺序。要了解这里发生了什么:
Window
正在初始化,这将初始化其 UI,包括 ListView
。
然后检索 Message
模型并将其添加到 ObservableCollection
。
当每个Message
被添加到ObservableCollection
时,使用ObservableCollection
作为其ItemsSource
的ListView
然后使用XAML 中指定的ItemTemplate
创建一个新的Item
,然后初始化并将新初始化的MessageControl
绑定到Message
。 TEST 1 验证这是否正在发生。
这里的问题在于第 3 步:MessageControl
s 已初始化,然后绑定到。绑定发生时,UI 永远不会收到需要更新绑定的通知。这就是为什么将Mode=OneWay
添加到x:Bind
并不能解决问题的原因。 OneWay
模式告诉绑定在模型更新时更新......但 XAML 仍然永远不会知道模型已更新。
我不完全确定为什么这与其他两个绑定(TEST 1 和 TEST 2 cmets)不同,但这似乎是用户定义类型(类)的问题,而不是原始类型或构建的问题-in 类型属性(例如string
和int
)。
修复是使模型能够通知(或“通知”)已更新的 UI。这是通过实现INotifyPropertyChanged
接口完成的。将MessageControl
更新为:
public sealed partial class MessageControl : UserControl, INotifyPropertyChanged
private Message _message;
/// <summary>
/// The message to display.
/// </summary>
public Message Message
get return this._message;
set
this._message = value;
this.RaisePropertyChanged("Message");
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string name)
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
public EmailControl()
this.InitializeComponent();
最后一点:实现INotifyPropertyChanged
必须在MessageControl
上完成才能工作。在 Message
模型上实现 INotifyPropertyChanged
将允许 MessageControl
(或任何其他数据绑定 UI,例如注释的 TEST 1)在 Message
模型的特定属性更新但不修复时更新Message
模型本身在 MessageControl
上的问题正在更新。
【讨论】:
如果您已经解决了您的问题,请mark它被接受 我会的! Github 不允许我在 48 小时后接受我自己的答案。以上是关于如何绑定到 ListView 中的模型而不是 WinUI3 中的属性?的主要内容,如果未能解决你的问题,请参考以下文章
如何指定一个请求参数绑定到某个控制器方法参数而不是Spring MVC中的模型属性?
如何在 ListView 中绑定 Label 的 FontSize