[英]How to bind to a model in ListView instead of property in WinUI3?
I am trying to directly bind to a model ( similar to the situation here ), instead of the property on that model, but it is not working.我试图直接绑定到 model( 类似于这里的情况),而不是 model 上的属性,但它不起作用。 I previously asked a question about this , and the answer had worked in UWP.
我之前问过一个关于这个的问题,答案在 UWP 中有效。 I am now working in WinUI3 (packaged UWP) and am not sure if the same solution applies.
我现在在 WinUI3(打包的 UWP)中工作,不确定是否适用相同的解决方案。
I have a class:我有一个 class:
public class Message
{
public string Title { get; set; }
public string Content { get; set; }
}
I have a UserControl that displays that class:我有一个显示 class 的 UserControl:
public sealed partial class MessageControl : UserControl
{
/// <summary>
/// The message to display.
/// </summary>
public Message Message { get; set; }
public MessageControl()
{
this.InitializeComponent();
}
}
With XAML:使用 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>
Now, I have a Window I am displaying that control on, inside of a list view:现在,我有一个 Window 我在列表视图中显示该控件:
<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>
And the code behind for the Window is: 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();
}
}
When I run this code (which compiles and runs), I get a window with the expected number of items in the ListView
(10), but they are all blank.当我运行此代码(编译并运行)时,我得到一个 window ,其中包含
ListView
中的预期项目数(10),但它们都是空白的。 There are also no XAML binding failures being reported (via the new feature in Visual Studio 2022).也没有报告 XAML 绑定失败(通过 Visual Studio 2022 中的新功能)。 In an attempt to investigate this, I added in a textblock inside of the listview (denoted as TEST 1 in the comments) bound to the
Title
property of the Message
.为了对此进行调查,我在列表视图(在注释中表示为 TEST 1)内添加了一个文本块,该文本块绑定到
Message
的Title
属性。 This worked as expected, displaying the correct titles for the 10 messages.这按预期工作,显示了 10 条消息的正确标题。 I then added a single
MessageControl
to the Window
outside of the ListView
(denoted as TEST 2 in the comments) bound to a single Message
property on the Window
.然后,我将单个
MessageControl
添加到ListView
之外的Window
(在评论中表示为 TEST 2 )绑定到Window
上的单个Message
属性。 This also worked exactly as expected.这也完全按预期工作。
Am I missing something?我错过了什么吗? Why does the specific case of binding to a model directly (as opposed to a property on that model - ie a binding with no path) not work, when the data is there and works with other binding configurations?
为什么直接绑定到 model 的特定情况(而不是 model 上的属性 - 即没有路径的绑定)不起作用,当数据在那里并且与其他绑定配置一起使用时?
Turns out this specific case exposes some of the ordering of how bindings work in XAML.事实证明,这个特定案例揭示了绑定在 XAML 中如何工作的一些顺序。 To understand what is happening here:
要了解这里发生了什么:
Window
is being initialized, which initializes its UI, including the ListView
. Window
正在初始化,它会初始化其 UI,包括ListView
。Message
models are then retrieved and added to the ObservableCollection
.Message
模型并将其添加到ObservableCollection
中。Message
is added to the ObservableCollection
, the ListView
using that ObservableCollection
as its ItemsSource
then creates a new Item
using the ItemTemplate
specified in the XAML, and then initializes and binds the newly initialized MessageControl
to the Message
.Message
添加到ObservableCollection
时,使用该ObservableCollection
作为其ItemsSource
的ListView
然后使用 XAML 中指定的ItemTemplate
创建一个新Item
,然后初始化并将新初始化的MessageControl
绑定到Message
。 The TEST 1 verifies this is happening. The problem here is in step 3: The MessageControl
s are initialized AND THEN bound to.这里的问题出在第 3 步:
MessageControl
被初始化然后绑定到。 When the binding happens, the UI is never notified that it needs to update the binding.绑定发生时,UI 永远不会收到需要更新绑定的通知。 This is why adding
Mode=OneWay
to the {x:Bind}
doesn't fix the issue.这就是为什么将
Mode=OneWay
添加到{x:Bind}
并不能解决问题的原因。 The OneWay
mode tells the binding to update whenever the model updates... but the XAML is still never aware the model was updated. OneWay
模式告诉绑定在 model 更新时更新……但 XAML 仍然不知道 model 已更新。
I am not entirely sure why this is different than the other two bindings (the TEST 1 and TEST 2 comments), but this seems to be an issue with user-defined types (classes) specifically, and NOT with primitive or built-in type properties (such as string
and int
).我不完全确定为什么这与其他两个绑定(TEST 1 和 TEST 2 注释)不同,但这似乎是用户定义类型(类)的问题,而不是原始类型或内置类型属性(例如
string
和int
)。
The fix is to enable the model to inform (or "notify") the UI that is has been updated.修复是让 model 通知(或“通知”)已更新的 UI。 This is done be implementing the
INotifyPropertyChanged
interface.这是通过实现
INotifyPropertyChanged
接口完成的。 Update the MessageControl
to:将
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();
}
}
A final note: implementing INotifyPropertyChanged
MUST be done on the MessageControl
for this to work.最后一点:必须在
MessageControl
上实现INotifyPropertyChanged
才能使其正常工作。 Implementing INotifyPropertyChanged
on the Message
model would allow for the MessageControl
(or any other data bound UI, such as the commented TEST 1) to update if a particular property of the Message
model updates, but does not fix the issue of the Message
model iself on the MessageControl
being updated. Implementing
INotifyPropertyChanged
on the Message
model would allow for the MessageControl
(or any other data bound UI, such as the commented TEST 1) to update if a particular property of the Message
model updates, but does not fix the issue of the Message
model iself on MessageControl
正在更新。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.