这种类型的CollectionView不支持从线程中更改其SourceCollection ...使用调度程序时?

时间:2017-06-08 08:54:27

标签: c# wpf multithreading mvvm-light dispatcher

所以我正在开发一个带有在应用程序(主应用程序)中使用的UI的插件。为了在主应用程序工作时使我的UI响应,我将在其单独的线程中启动我的UI,如下所示:

    public  void ShowDialog(IIFCConverter ifcConverter)
    {

        thread = new Thread(x =>
        {
            thread.Name = "UI-thread";
            window = new MainWindow();
            var mainViewModel = ServiceLocator.Current.GetInstance<MainWindowViewModel>();
            mainViewModel.SetIFCConverter(x as IIFCConverter);
            ViewModelLocator.MainWindow = window;
            window.ShowDialog();



        });
        thread.SetApartmentState(ApartmentState.STA);

        thread.Start(ifcConverter);

    }

我第一次启动插件时一切正常。第二次我启动它并尝试引发事件(比如OnCollectionChanged)我得到一个带有消息的NotSupportedException:“这种类型的CollectionView不支持从不同于Dispatcher线程的线程更改其SourceCollection”

这是我的方法之一:

    private void AddNewFile(AddNewFileMessage obj)
    {
        if (!(obj.Sender is ButtonViewModel)) return;

        if (string.IsNullOrEmpty(obj.Path)) return;



        var ifcFileViewModel = new IFCFileViewModel(new Common.Model.IFCFile { Path = obj.Path, Active = true });
        DispatcherHelper.CheckBeginInvokeOnUI(() =>
        {
            ListBoxItems.Insert(ListBoxItems.Count - 1, ifcFileViewModel);
        });

    }

我得到了这个事件,尽管我正在使用MVVM灯的DispatcherHelper。 我尝试使用“普通”调度程序,但这给了我相同的结果。

首先,我很想知道它为什么这样做的机制? 我检查了我的线程,我可以看到从我的UI线程调用OnOllectionChanged。 我似乎无法找到第一次运行(有效)和以下之间的线程结构的任何差异。

OnCollectionChanged called on UI-thread, right?

其次,我该怎么办呢?

我测试的东西没有帮助:

  1. 我使用MVVM灯中的IoC容器并将其注册为LocatorProvider,但每次初始化UI并将该实例设置为LocatorProvider时,我都会创建一个新的IoC容器。
  2. 我在窗口的构造函数中初始化DispatcherHelper。所以这应该在正确的线程上。
  3. 实际上有效的方法是将动作包装在try Catch-block中,如下所示:

    private void AddNewFile(AddNewFileMessage obj)
    {
    if (!(obj.Sender is ButtonViewModel)) return;
    
    if (string.IsNullOrEmpty(obj.Path)) return;
    
    
    
    var ifcFileViewModel = new IFCFileViewModel(new Common.Model.IFCFile { Path = obj.Path, Active = true });
    
    DispatcherHelper.CheckBeginInvokeOnUI(() =>
    {
        try
        {
            ListBoxItems.Insert(ListBoxItems.Count - 1, ifcFileViewModel);
        }
        catch(Exception ex)
        {
    
        }
    });
    

    }

  4. 然而,我觉得这很难看,想避免它,为什么这样做呢?当我将所有动作包装在try Catch-blocks中时,一切似乎都能正常工作。

2 个答案:

答案 0 :(得分:2)

好的,所以我找到了真正的问题。 视图模型确实是在与我的插件UI相同的线程上创建的。

但是:我正在使用MVVMLight工具包中可用的Messenger来处理视图模型之间的通信,而我忘记在我的窗口关闭时取消注册视图模型。所以我第二次打开窗口并开始在我的视图模型之间发送消息。第一个视图模型做出反应,这就是导致问题的原因。 这也是try-Catch-block工作的原因,因为有正确的线程进行了第二次调用。 我在viewmodel的构造函数中添加了一个datetime,并且确实调用了两个不同的viewmodel。我不明白为什么我得到那个例外。如果有的话,第一个视图模型应该通过datacontext连接到第一个视图。它就像视图已经连接到两个不同视图模型的事件。

无论如何,它现在有效:我只是在我的窗口关闭时从消息服务取消注册视图模型,它就像一个魅力。

答案 1 :(得分:0)