我相信这是ListView
工作方式的一个怪癖。我已经包括了我认为正在发生的问题描述,以及我的问题:我该怎么办?
问题描述
我有一个ListView
,在ItemTemplate
中指定了一个ComboBox
。ComboBox
显示ListView
中显示的项目的可编辑属性。
根据official documentation中的“提示”(在标题“项目选择”下),我正在处理Loaded
事件以初始化ComboBox
中的SelectedItem
属性。(我这样做是因为数据是从异步源中提取的,可能无法立即使用-我无法单独使用XAML中的数据绑定)。
当页面第一次加载时,它可以完美地工作。然而,当我尝试在之后向集合中添加项时-我得到一些意外的行为...尽管使用相同的函数(下面示例中的SetItems()
)来执行两次更新。使用下面示例中的print语句,我已经确认当页面第一次加载时,输出是预期的:列表中的每个项目都有一个输出行,并且每个ComboBox
中的SelectedValue
(在下面的示例中显示每个项目的Status
属性)是正确的。
但是,当我稍后更新列表时(在页面和ListView
初始加载之后),通过调用相同的SetItem()
函数(可能在向列表添加一个项之后),来自相同的print语句的输出不是预期的。只出现一个print语句,并从列表中打印一个看似随机的项,沿着不正确的Status
。这是意外的,因为我正在清除ObservableCollection
,并重新添加所有项目(包括新项目)。
在页面XAML中:
<ListView ItemsSource="{x:Bind MyCollection}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:MyDataType">
<!-- Some things omitted for brevity -->
<ComboBox x:Name="MyComboBox"
Tag="{x:Bind ID}"
SelectedValuePath="Status"
Loaded="MyComboBox_Loaded"></ComboBox>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
字符串
集合、事件处理程序和集合变更代码背后的代码:
// The collection.
public ObservableCollection<MyDataType> MyCollection { get; set; }
// The ComboBox Loaded event handler.
private void MyComboBox_Loaded(object sender, RoutedEventArgs e)
{
// Get the ID of the item this CombBox is for.
ComboBox comboBox = sender as ComboBox;
string id = comboBox.Tag as string;
// Get a reference to the item in the collection.
MyDataType item = this.MyCollection.Where(i => i.ID == id).FirstOrDefault();
// Initialize the ComboBox based on the item's property.
comboBox.SelectedValue = item.Status;
// Wire up the Selection Changed event (doing this after initialization prevents the handler from running on initialization).
comboBox.SelectionChanged += this.MyComboBox_SelectionChanged;
// Print statement for debugging.
System.Diagnostics.Debug.WriteLine("ComboBox for item " + item.ID + " loaded and set to " + item.Status);
}
// The function used to update the observable collection (and thus bound listview).
public void SetItems(List<MyDataType> items)
{
// Clear the collection and add the given items.
this.MyCollection.Clear();
items.ForEach(i => this.MyCollection.Add(i));
}
型
我所想的
我相信这是ListView
工作原理的一个怪癖。我记得在过去的某个地方阅读到过.NET的不同部分中的项目重复器的经验,每个项目的UI实际上可能不是每次都创建新的;出于效率原因,UI项可以被回收和重用。我猜这里发生的事情是相似的;并且“重用”的项不触发Loaded
事件,因为它们从未被重新加载。
那么,我如何绕过它,并强制ComboBox在每次集合更改时更新,就像页面首次加载时一样?
更新
print语句的意外输出似乎不是随机的-它似乎始终是ListView
中的最后一项。因此,每当调用SetItem()
函数时(在页面加载的初始时间之后),只有ListView
中最后一项的ComboBox
才会触发其Loaded
事件。其他物品上的ComboBox
是乱序的,但是……几乎就像他们都被向上移动了一个(所以有ListView
中的下一个项目的Status
,而不是他们所在的项目)。
2条答案
按热度按时间zf2sa74q1#
您不需要使用
Loaded
来实现此目的。让我给你看一个简单的例子:
MainPage.xaml
字符串
MainPage.xaml.cs
型
gpfsuwkq2#
听起来您需要使用SelectionChanged事件处理程序而不是加载。如果我没记错的话,你可以两个都用,但没有必要。您可以在页面的方法中使用一行代码(它具有“this.Initialize();“),它将在启动时加载您想要的任何内容。
我不是100%确定你的程序是做什么的。请尝试添加其他事件处理程序;有几个是可以适用。