ICollectionView的SourceCollection为null [英] ICollectionView's SourceCollection is null
问题描述
我有一个带有两个 ICollectionView
的ViewModel,它们作为 ItemsSource
s绑定到两个不同的 ListBox
es.两者都包装相同的 ObservableCollection
,但具有不同的过滤器.最初一切正常,并且两个ListBox都显示正确填充.
I have a ViewModel with two ICollectionView
s which are bound as ItemsSource
s to two different ListBox
es. Both wrap the same ObservableCollection
, but with different filters. Everything works fine initially and both ListBoxes appear properly filled.
但是,当我更改ObservableCollection中的一项并修改与过滤相关的属性时,ListBoxes不会更新.在调试器中,我发现两个ICollectionVIews的SourceCollection为null,尽管我的ObservableCollection仍然存在.
However when I change an item in the ObservableCollection and modify a property which is relevant for filtering, the ListBoxes don't get updated. In the debugger I found that SourceCollection for both ICollectionVIews is null although my ObservableCollection is still there.
这是我修改项目的方式,以确保通过删除和添加相同的项目来更新ICollectionView:
This is how I modify an item making sure that the ICollectionViews are updated by removing and adding the same item:
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);
}
该机制在另一个使用相同类的上下文中起作用.
The mechanism works in another context where I use the same class.
我还意识到,如果我在ICollectionViews的CollectionChanged事件上注册侦听器,问题将消失.我确定我是从GUI线程创建和修改它们的,并且怀疑是否存在垃圾回收问题,但是目前我陷入了困境……想法?
Also I realized that the problem disappears if I register listeners on the ICollectionViews' CollectionChanged events. I made sure that I create and modify them from the GUI thread and suspect that garbage collection is the problem, but currently I'm stuck... Ideas?
更新:
在调试时,我意识到在我的UserControl所在的WinForms窗体上调用 ShowDialog()
之前,SourceCollections仍然存在.显示对话框后,它们消失了.
While debugging I realized that the SourceCollections are still there right before I call ShowDialog()
on the WinForms Form in which my UserControl is hosted. When the dialog is shown they're gone.
我这样创建ICollectionViews:
I create the ICollectionViews like this:
AvailableTags = new CollectionViewSource { Source = _tags }.View;
AssignedTags = new CollectionViewSource { Source = _tags }.View;
这是我绑定两者之一的方式(另一个非常相似):
Here's how I bind one of the two (the other one is pretty similar):
<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
实现:
I use MvvmLight's RelayCommand<T>
as ICommand
implementation in my ViewModel:
AssignSelectedTagCommand = new RelayCommand<TagViewModel>(AssignTag);
推荐答案
在类似的用例中,我也遇到了这个问题.更新基础集合时,我将在所有过滤的视图上调用 Refresh()
.有时,这会导致从 ListCollectionView.PrepareLocalArray()
内部抛出 NullReferenceException
,因为 SourceCollection
为null.
I had this issue too, with a similar use-case. When I updated the underlying collection, I would call Refresh()
on all the filtered views. Sometimes, this would result in a NullReferenceException
thrown from within ListCollectionView.PrepareLocalArray()
because SourceCollection
is null.
问题在于您不应该绑定到 CollectionView
,而应该绑定到 CollectionViewSource.View
属性.
The problem is that you shouldn't be binding to the CollectionView
, but to the CollectionViewSource.View
property.
这是我的操作方式:
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; }
}
// ...
}
这篇关于ICollectionView的SourceCollection为null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!