[英]Cannot update subitems ListBox
我有两个ListBox
。 一个ListBox
显示一些项目。 每个项目都有一个子项目列表。 第二个ListBox
显示第一个ListBox
中当前项的子项。 典型的项目/子项目场景。 当我向子项列表添加一个值时,我无法让第二个ListBox
更新。 如何强制第二个ListBox
更新我的子项?
我的简化 XAML 和视图 model 如下。 请注意,我的观点 model 继承自 Prism 的BindableBase
。 在我看来 model 我有一种方法可以将值添加到子项列表并使用RaisePropertyChanged
更新Items
属性。
<ListBox Name="Items" ItemsSource="{Binding Items}" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding ItemValue, Mode=TwoWay}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Name="SubItems" ItemsSource="{Binding Items.CurrentItem.SubItems}" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
class Item
{
public int ItemValue { get; set; }
public List<int> SubItems { get; set; }
}
class MyViewModel : BindableBase
{
private ObservableCollection<Item> _items = new ObservableCollection<Item>();
public MyViewModel()
{
List<Item> myItems = new List<Item>() { /* a bunch of items */ };
_items = new ObservableCollection<Item>(myItems);
Items = new ListCollectionView(_items);
}
public ICollectionView Items { get; private set; }
private void AddNewSubItem(object obj)
{
Item currentItem = Items.CurrentItem as Item;
currentItem.SubItems.Add(123);
RaisePropertyChanged("Items");
}
}
class Item
{
public int ItemValue { get; set; }
public ObservableCollection<int> SubItems { get;}
= new ObservableCollection<int>();
}
class MyViewModel : BindableBase
{
publc ObservableCollection<Item> Items {get;}
= new ObservableCollection<Item>();
public MyViewModel()
{
List<Item> myItems = new List<Item>() { /* a bunch of items */ };
myItems.ForEach(item => Items.Add(item));
}
private Item _currentItem;
private Item CurrentItem
{
get => _currentItem;
set
{
if(Equals(_currentItem, value))
return;
_currentItem = value;
RaisePropertyChanged(nameof(CurrentItem));
}
}
private void AddNewSubItem(object obj)
{
CurrentItem.SubItems.Add(123);
}
}
<ListBox ItemsSource="{Binding Items}"
SelectedItem="{Binding CurrentItem}">
********
********
</ListBox>
<ListBox ItemsSource="{Binding CurrentItem.SubItems}" >
********
********
</ListBox>
问题是您的Item
类型包含一个List<int>
,它不会通知集合更改,因为它没有实现INotifyCollectionChanged
接口。 因此,当集合被修改时,绑定不会在用户界面中收到更新其值的通知。 使用实现此接口的集合,例如ObservableCollection<int>
将解决该问题。
顺便说一句,这同样适用于ItemValue
和SubItems
属性以及INotifyPropertyChanged
。 这两个属性都有设置器,这意味着它们可以被重新分配,但绑定也不会得到通知。 由于您使用BindableBase
,因此您可以使用带有支持字段的SetProperty
方法在设置属性时自动引发PropertyChanged
事件。
public class Item : BindableBase
{
private int _itemValue;
private ObservableCollection<int> _subItems;
public int ItemValue
{
get => _itemValue;
set => SetProperty(ref _itemValue, value);
}
public ObservableCollection<int> SubItems
{
get => _subItems;
set => SetProperty(ref _subItems, value);
}
}
关于您的项目的评论。 您尝试做的是分层数据的主从视图。 由于您已经公开了ICollectionView
,因此您不必显式使用CurrentItem
。
当源是集合视图时,可以用斜杠 (/) 指定当前项。 例如,子句 Path=/ 将绑定设置为视图中的当前项。 当源是集合时,此语法指定默认集合视图的当前项。
有一种特殊的绑定语法,您可以在其中使用/
来指示当前项,例如:
<ListBox Grid.Row="1" Name="SubItems" ItemsSource="{Binding Items/SubItems}">
另外,关于您查看 model 代码的一些评论。
_items
字段初始值设定项是无用的,因为无论如何您都在构造函数中重新分配了该字段。_items
,则可以在构造函数中使用局部变量。Items
的私有 setter,您可以将其移除。Items.CurrentItem
直接转换为Item
以获得一个无效的转换异常,该异常比 null 引用异常更具体,您稍后在访问使用as
和获取null
的值时会得到该异常。 如果您希望该值可能不是Item
,您可以在as
之后检查null
或使用模式匹配来适当地处理成功和错误这两种情况( CurrentItem
不是Item
类型)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.