在线程池线程上创建的ObservableCollection不会过滤

时间:2017-09-22 15:55:31

标签: c# wpf collectionviewsource

我正在处理的应用程序基于WPF和MVVMLightToolkit。我知道我没有为你提供mcve,但整个应用程序非常复杂,很难提供这样的例子。我希望有人能够帮助全局。

在该应用程序中,一个操作需要花费大量时间(初始化内容),因此我在任务中运行它以不冻结UI:

public class MainViewModel : ViewModelBase
{
    public ICommand HeavyActionCommand {get; private set;}
    public MainViewModel()
    {
        this.HeavyActionCommand = new RelayCommand(this.HeavyAction);
    }
    private async void HeavyAction()
    {
        var subViewModel = new SubViewModel();
        await Task.Run(async () => await subViewModel.ActualHeavyAction());
    }
}

如果我没有将ActualHeavyAction包裹在Task.Run方法中,则UI会冻结。这样做,据我所知,ActualHeavyAction不是在UI线程上运行,而是在线程池线程上运行(如果我错了,请纠正我)。

除其他事项ActualHeavyAction初始化我需要过滤一些用户实时输入的ObservableCollection(在以下类中,属性UserInput绑定到{{1} })。我有类似的东西:

TextBox

直到这里,我没有任何麻烦。稍后会出现问题,当另一个操作在UI线程上运行时修改该集合。我得到了经常性的事情:

  

此类型的CollectionView不支持从与Dispatcher线程不同的线程更改其SourceCollection

要解决此问题,我尝试添加.NET 4.5 public class SubViewModel: ViewModelBase { private _userInput; public string UserInput { get { return _userInput; } set { if (_userInput != value) { _userInput = value; this.RaisePropertyChanged(); // Run the filter on the collection when the user enters new inputs CollectionViewSource.GetDefaultView(this.MyCollection).Refresh(); } } } public ObservableCollection MyCollection {get; private set;} public async Task ActualHeavyAction() { /// lots of heavy stuff var myCollection = await _context.Objects.GetCollectionAsync(); this.MyCollection = new ObservableCollection(myCollection); this.RaisePropertyChanged(nameof(this.MyCollection)); CollectionViewSource.GetDefaultView(this.MyCollection).Filter = MyFilter; /// some other heavy stuff } public bool MyFilter(object obj) { // Blah blah blah } } 功能:

EnableCollectionSynchronization

我尝试在调用之前和之后添加它:BindingOperations.EnableCollectionSynchronization(this.MyCollection, lockObject); // lockObject is a static new object() defined in the SubViewModel class

这样做,我在修改CollectionViewSource.GetDefaultView时没有收到异常,但在MyCollection上调用Refresh()并未运行CollectionView方法(完全相同的代码)处理未在线程池线程上初始化的其他ViewModel。)

您是否知道我的代码有什么问题?

1 个答案:

答案 0 :(得分:1)

应该在UI线程上调用function getOneSignalToken() { window.bridge.post('onesignaltoken', {}, function(results, error){ $('#onesignal_token').html(results.token); }); } 方法。所以你需要创建BindingOperations.EnableCollectionSynchronization并在之前在UI线程上调用此方法,然后尝试从后台线程访问该集合。

但是ObservableCollection中应该在后台线程上调用的唯一方法是ActualHeavyAction()方法。

调用此方法的任务完成后,您可以创建GetCollectionAsync()并将过滤器应用回UI线程。或者只是从任务中返回已经过滤的列表。

使用ObservableCollection属性过滤ICollectionView是一种灵活但非常慢的操作,因此如果您的源集合包含大量项目,这可能不是实现过滤的最佳选择。