解决 System.NotSupportedException:“该类型的 CollectionView 不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改。”方法
报错背景
在一个新WPF项目中显示加载界面显示进度条和消息。用于封装消息和进度条值的 LoadModel 的loadmsg 属性的数据类型由LeoObservableCollection<string> 改成了ObservableCollection<string>,在界面上执行
Application.Current.Dispatcher.Invoke(new Action(() =>
{
Global._loadIns.LoadMsg.Add(message);
Global._loadIns.LoadProcess = loadProcessVal;
}));
代码时发生报错
1.报错图
2.相关代码
/// <summary> /// 加载 模型 /// </summary> public class LoadModel : ViewModelBase { public LoadModel() { // ObservableCollection LoadMsg = new LeoObservableCollection<string>(); LoadProcess = 0; } //private ObservableCollection<string> loadmsg; private LeoObservableCollection<string> loadmsg; /// <summary> /// 加载时的 消息 /// </summary> public LeoObservableCollection<string> LoadMsg { get => loadmsg; set { loadmsg = value; RaisePropertyChanged("LoadMsg"); } } private float loadprocess; /// <summary> /// 进度条 /// </summary> public float LoadProcess { get => loadprocess; set { loadprocess = value; RaisePropertyChanged("LoadProcess"); } } }
3.解决方法
3.1 方法1
private ObservableCollection<string> loadmsg; 集合还是使用 ObservableCollection 集合时。
修改界面上代码,首先在 构造中增加DispatcherHelper.Initialize();
SetLoadMsg 方法如下修改
/// <summary> /// 设置加载消息 /// </summary> /// <param name="message">显示消息</param> /// <param name="loadProcessVal">进度条数值</param> public static void SetLoadMsg(string message, float loadProcessVal) { //System.NotSupportedException:“该类型的 CollectionView 不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改。” //这个报错和ObservableCollection这个集合有关,ObservableCollection这个集合是线程安全集合默认是不能进行跨线程访问的,如果出现跨线程访问就是报上面的错 //报错解决方法 //方法1.用task启动一个线程,具体代码如下 Task.Run(() => DispatcherHelper.CheckBeginInvokeOnUI(() => { Global._loadIns.LoadMsg.Add(message); Global._loadIns.LoadProcess = loadProcessVal; })); }
代码结图
3.2 方法2 只改LoadModel的loadmsg属性的数据类型为LeoObservableCollection
具体看上面LoadModel的代码
配合原来的界面代码
/// <summary> /// SplashWindow.xaml 的交互逻辑 /// </summary> public partial class SplashWindow : Window { public SplashWindow() { InitializeComponent(); DataContext = Global._loadIns; } /// <summary> /// 设置加载消息 /// </summary> /// <param name="message">显示消息</param> /// <param name="loadProcessVal">进度条数值</param> public static void SetLoadMsg(string message, float loadProcessVal) {//方法2.LoadMsg集合的类型ObservableCollection这个集合用LeoObservableCollection这个替换 Application.Current.Dispatcher.Invoke(new Action(() => { Global._loadIns.LoadMsg.Add(message); Global._loadIns.LoadProcess = loadProcessVal; })); } }