建议的重复线程没有解决我的问题
所以这是我的理解,WPF应用程序处理所有与UI相关的事情,按钮按下,通过dispatcher线程更新到可观察集合,这可以通过application . current . dispatcher调用。调用(Update UI element here
),而对模型和数据的更改通常可以由后台线程处理。
我不明白的是为什么你需要调用调度程序说更新一个可观察集合绑定到一个组合框,但是当我想要更新进度条或文本框中的文本,或者如果一个按钮是启用的,我不需要调用调度程序。我读到的所有内容都说调度程序用于处理和更新UI。文本框、进度条的状态以及按钮是否启用都不是UI吗?
可观察对象集合和文本/进度条之间有什么区别,使得不需要调用调度程序?
几乎所有对WPF UI元素的调用都应该发生在应用程序的主线程上。这通常是通过与该线程关联的Dispatcher的方法完成的。分派器可以从任何UI元素中获得,但通常是从应用程序中获得:
如果你不直接给UI元素的属性赋值,而是使用绑定来赋值,那么绑定机制会在UI元素的流中内置封送值处理。因此,INotifyPropertyChanged。PropertyChanged事件可以在任何线程上引发。
当可观察集合发生变化时,INotifyCollectionChanged。引发CollectionChanged事件。它不提供自动封送到UI线程。但是集合可以与BindingOperations同步。EnableCollection(…)方法。然后可以在任何线程中更改它(使用同步)。如果没有执行这样的同步,则只能在UI线程中更改。
除了这些事件之外,还有iccommand . canexecutechange。没有为它提供额外的封送处理或同步方法。因此,它只能在UI线程中引发。这通常内置于iccommand的WPF实现中,程序员不需要担心它。但是在简单的(主要是教育性的)实现中,没有这样的封送处理。因此,当使用它们时,程序员自己必须负责转换到UI线程以引发此事件。
所以基本上在MVVM实践中无论如何你都必须使用调度程序来使用
BindingOperations.EnableCollectionSynchronization(fooCollection, _mylock));
,对吗?
是的。对于集合的应用,您的理解是正确的。
这里只出现了View和ViewModel功能分离的问题。你只能调用EnableCollectionSynchronization"在View或主UI线程上。但是您是在ViewModel中实现集合。此外,为了不堵塞内存,在删除集合时(用另一个集合替换它,清除使用它的绑定,替换ViewModel实例等),您需要使用"DisableCollectionSynchronization (collection)"删除已创建的同步。方法。
在这种情况下,如果在整个应用程序会话中使用ViewModel的单个实例,则使用"EnableCollectionSynchronization ()"是最简单的解决方法。的例子:
public class MainViewModel
{
public ObservableCollection<int> Numbers { get; }
= new ObservableCollection<int>();
protected static readonly Dispatcher Dispatcher = Application.Current.Dispatcher;
public MainViewModel()
{
if (Dispatcher.CheckAccess())
{
BindingOperations.EnableCollectionSynchronization(Numbers, ((ICollection)Numbers).SyncRoot);
}
else
{
Dispatcher.Invoke(()=>BindingOperations.EnableCollectionSynchronization(Numbers, ((ICollection)Numbers).SyncRoot));
}
}
}
但是如果使用许多VM实例,相互嵌套和动态添加和删除(例如,这可能是在实现树并在TreeView中查看它时的情况),则使用"EnableCollectionSynchronization ()"变得不琐碎。如果您按照我在上面的示例中所展示的那样做,那么由于对同步对象和集合的引用将被保存,它们将不会从内存中删除,因此,不必要的ViewModel实例将不会被删除。这将导致内存泄漏。因此,在实践中,经常使用对UI线程的集合更改进行封送处理。
也可以嵌入到INotifyCollectionChanged实现中,以及封送到UI线程,并调用"EnableCollectionSynchronization ()/DisableCollectionSynchronization()";同时订阅/取消订阅CollectionChanged事件。ObservableCollection的实现没有这个功能,但是在实现类似功能的各种包中有可观察集合的自定义实现。它们的使用将程序员从创建例行的、特定的、重复的代码中解放出来。
不幸的是,我不能确切地告诉您包中包含所需的实现。我更喜欢使用我自己的实现。