如何创建主线程对象并从其他线程添加到集合?

时间:2018-04-19 12:52:45

标签: c# .net wpf multithreading

编辑:好的,在构建了一个重现错误的最小示例后,我必须承认它正在工作(在Timer.Elapsed中创建自定义对象,通过Invoke在ViewModel中更新集合,并通过DataTemplate中的DataPiping单向绑定readonly GUI依赖属性到ViewModel。所有这些都没有冻结新创建的对象)。 然而,我的真实应用程序无法正常工作,我必须在其他地方找到错误。

编辑2:好的,我找到了基本问题。我的自定义对象包含一个Brush属性,它是一个DependencyObject,需要在主线程上创建。我想我可以通过冻结画笔或者只是不在我的自定义对象中使用DependencyObject来解决这个问题。再次感谢大家,我们学到了很多东西!

谢谢大家推动我创建这个最小的例子,我真的认为这是某种设计/模式问题,我不知道。当我在我的实际应用程序中发现实际问题并且无法自行解决时,我会回来 - 使用代码示例:D

我有一个基本的问题,我找不到答案。

我基本上想做的是:

我有一个带有ObservableCollection自身对象的ViewModel。此ObservableCollection绑定到ItemsControl,并且基于多个DataTemplates显示Items。其中一些DataTemplates正在使用Dmitry Tashkinov的DataPiping方法(Pushing read-only GUI properties back into ViewModel)将UIElement依赖属性推送到ViewModel。所有这一切都很好。

现在我在按下LeftMouseButton时尝试将对象添加到ObservableCollecion(基本上根据鼠标位置复制/粘贴所选对象)。起初我使用了OnMouseMove事件,但由于在添加/显示对象和/或刷新鼠标位置时似乎存在一些延迟,因此“鼠标比复制对象更快”并且我需要稍微移动鼠标保持该事件的目标位置,直到粘贴初始位置和目标位置之间的所有对象为止。基本上这也有效但用户体验不好。

在按下我找到的按键时执行某些操作的所有方法都是基于某种方式的线程。我试图使用一个在LeftMouseDown上启动并在LeftMouseUp上停止的Timer。进入Timer.Elapsed事件我创建了新的Object并尝试将其添加到ObservableCollection中。

问题是Timer.Elapsed方法和ObservableCollection在不同的线程上运行,我无法直接添加新对象。如果我从第二个线程调用collection.add方法来添加对象我正在创建一个XAMLParseException,说明需要在同一个线程上创建DependencySource和DependencyObject。同时冻结对象也不是一种选择,因为它们将在以后编辑。

在使用invoke添加对象之前,有没有办法复制主线程上的对象?或者还有其他常见模式可以解决这个基本问题吗?

1 个答案:

答案 0 :(得分:-1)

  

问题是Timer.Elapsed方法和ObservableCollection在不同的线程上运行,我无法直接添加新对象。如果我从第二个线程调用collection.add方法来添加对象我正在创建一个XAMLParseException,说需要在同一个线程上创建DependencySource和DependencyObject

解决方案是使用调度程序将对ObservableCollection的{​​{1}}方法的调用编组到UI线程:

Add

...或使用BindingOperations.EnableCollectionSynchronization方法启用多个线程访问private void Timer_Elapsed(object sender, ElapsedEventArgs e) { //... Application.Current.Dispatcher.BeginInvoke(new Action(() => { //this code gets executed on the UI thread yourCollection.Add(...); })); }

Best/cleanest strategy to update an ObservableCollection from another thread

相关问题