1.出现的问题
1、报错代码和位置
Message "该类型的 CollectionView 不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改。"
2.我的思路
1、解决背景
在MainViewModel 中 有一个 DataGrid 的 ItemSource 类型为 以下
private ObservableCollection<Log> _Logs;
public ObservableCollection<Log> Logs
{
get { return _Logs; }
set { SetProperty(ref _Logs, value); }
}
在下面这个类里面我定义了 一个事件 、事件触发方法,并且事件传递 事件数据Log。
namespace WSTVirtualRobot.Common.Log
{
public class LogOperate
{
public event PubLogDelegate LogEvent;
public void UpdateLog(object sender, Log log)
{
LogEvent?.Invoke(sender, log);
}
}
public delegate void PubLogDelegate(object obj, Log log);
}
在App.xaml 中我注册了 LogOperate,以便项目中其他类需要记录日志,通过构造函数获取LogOperate 实例,调用方法 UpdateLog,触发事件。以下所示
在MinViewModel 的构造函数中 获取 LogOperate 实例,并且我订阅了 日志事件,如下:
编写事件处理方法AddLog, 在AddLog 方法里面,我对集合 DataGrid 的 ItemSource 类型的bservableCollection Logs 进行元素添加。这里我期望实现的功能是,其他类想要记录日志的时候,都会将日志 通过 LogEvent 发送给事件处理程序 AddLog, 将新出现的日志显示到主界面。
到这里我所有的类和方法都基本实现了,接下来就是在其他类里面记录日志,看是否会在界面显示了。
在我的TCPServer 类里面 ,有一个监听线程里面,记录了日志
运行结果出现了开头的错误。错误如下:Message “该类型的 CollectionView 不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改。”
2、解决方式1
出现了问题 当然得解决呀,WPF 框架里面专门有一个Dispatcher 类 专门有用来管理和调度UI线程。
于是我想获取当前应用程序的Dispatcher 来 更新Log。于是我将调用Dispater的方法调用在监听线程里面,去调度UI。
问题记录
报错位置和类型,报错出现在 App基类上。报:System.InvalidOperationException
HResult=0x80131509
Message=某个 ItemsControl 与它的项源不一致。\n请参见内部异常以获取更多信息。
Source=PresentationFramework
StackTrace:
在 System.Windows.Controls.ItemContainerGenerator.Verify()
在 System.Windows.Controls.VirtualizingStackPanel.MeasureChild(IItemContainerGenerator& generator, IContainItemStorage& itemStorageProvider, IContainItemStorage& parentItemStorageProvider, Object& parentItem, Boolean& hasUniformOrAverageContainerSizeBeenSet, Double& computedUnif
ItemsControl 数据项与他的位置不一致。
3、解决方式2
网上查了各种,都是上面的解决方式,我的头都要大了!!!
后来我一个一个打断点调式,发现: 在哪个线程触发的事件,哪个线程就处理订阅了该事件的方法,所以 监听线程触发了UpdateLog 事件,监听线程处理订阅了该事件的方法。
不应该将触发事件的方法写在 dispatcher 里面,注意这里Dispather 处理与UI有关的部分,
所以这里我转变思路,Dispather 写在 订阅了UpdateLog 事件的事件处理程序 AddLog 里面。 因为这里面是将ItemSource Item 产生变化的地方,虽然可能像其他线程也会触发日志事件,但Dispather 会将UI线程里面的Source 更新,从而显示到界面上去。
问题解决:
到此问题已得到解决。哈哈哈,开心 !
3.总结复盘
出现这样的问题主要在于,在WPF 中 对UI 线程的调度不是很理解。
通过这个小项目的编写和调式对Dispatcher 类 有了一定的认识和学习。
当然了也对Prism 框架的依赖注入的使用和理解不到位,还需要多应用多练习和调式。
通过这个项目我也获得了一些收获,对事件和委托的应用掌握得更熟练,对依赖注入其中的单例模式的应用有了一定的理解。