我有一个带有两个ICollectionView
的ViewModel,它们被ItemsSource
绑定到两个不同的ListBox
es。两者都包含相同的ObservableCollection
,但使用不同的过滤器。最初一切正常,两个ListBox都显示正确填充。
但是,当我更改ObservableCollection中的项目并修改与过滤相关的属性时,ListBoxes不会更新。在调试器中,我发现两个ICollectionVIews的SourceCollection都为null,尽管我的ObservableCollection仍在那里。
这是我修改项目的方法,确保通过删除和添加相同的项目来更新ICollectionViews:
private void UnassignTag(TagViewModel tag)
{
TrackChangedTagOnCollectionViews(tag, t => t.IsAssigned = false);
}
private void TrackChangedTagOnCollectionViews(TagViewModel tag, Action<TagViewModel> changeTagAction)
{
_tags.Remove(tag);
changeTagAction.Invoke(tag);
_tags.Add(tag);
}
该机制适用于我使用同一类的另一个上下文。
此外,我意识到如果我在ICollectionViews的CollectionChanged事件上注册侦听器,问题就会消失。我确保从GUI线程创建和修改它们并怀疑垃圾收集是问题所在,但目前我被卡住了......想法?
更新
调试时我意识到在我托管UserControl的WinForms表单上调用ShowDialog()
之前,SourceCollections仍然存在。显示对话框后,它们就消失了。
我像这样创建ICollectionViews:
AvailableTags = new CollectionViewSource { Source = _tags }.View;
AssignedTags = new CollectionViewSource { Source = _tags }.View;
以下是我如何绑定其中一个(另一个非常相似):
<ListBox Grid.Column="0" ItemsSource="{Binding AvailableTags}" Style="{StaticResource ListBoxStyle}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Style="{StaticResource ListBoxItemBorderStyle}">
<DockPanel>
<Button DockPanel.Dock="Right" ToolTip="Assign" Style="{StaticResource IconButtonStyle}"
Command="{Binding Path=DataContext.AssignSelectedTagCommand, RelativeSource={RelativeSource AncestorType={x:Type tags:TagsListView}}}"
CommandParameter="{Binding}">
<Image Source="..."/>
</Button>
<TextBlock Text="{Binding Name}" Style="{StaticResource TagNameTextBlockStyle}"/>
</DockPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
我在我的ViewModel中使用MvvmLight的RelayCommand<T>
作为ICommand
实现:
AssignSelectedTagCommand = new RelayCommand<TagViewModel>(AssignTag);
答案 0 :(得分:11)
我也有这个问题,有类似的用例。当我更新基础集合时,我会在所有过滤后的视图上调用Refresh()
。有时,这会导致在NullReferenceException
内抛出ListCollectionView.PrepareLocalArray()
,因为SourceCollection
为空。
问题是您不应该绑定到CollectionView
,而应绑定到CollectionViewSource.View
属性。
我是这样做的:
public class ViewModel {
// ...
public ViewModel(ObservableCollection<ItemViewModel> items)
{
_source = new CollectionViewSource()
{
Source = items,
IsLiveFilteringRequested = true,
LiveFilteringProperties = { "FilterProperty" }
};
_source.Filter += (src, args) =>
{
args.Accepted = ((ItemViewModel) args.Item).FilterProperty == FilterField;
};
}
// ...
public ICollectionView View
{
get { return _source.View; }
}
// ...
}
答案 1 :(得分:3)
您遇到问题的原因是CollectionViewSource
正在收集垃圾。