• WPF ObservableCollection 异步调用问题


    问题介绍

    当ObservableCollection列表被UI线程占用时,如果在异步线程中调用ObservableCollection,会弹出以下异常:

    问题分析

    我们使用一个viewModel,在ViewModel中添加ObservableCollection类型的ItemsSource列表。

    在列表使用ListBox绑定ItemsSource列表。再由界面触发对ItemsSource的修改。

     1     public class ViewModel : INotifyPropertyChanged
     2     {
     3         private ObservableCollection<string> _itemsSource = new ObservableCollection<string>();
     4 
     5         public ObservableCollection<string> ItemsSource
     6         {
     7             get => _itemsSource;
     8             set
     9             {
    10                 _itemsSource = value;
    11                 OnPropertyChanged();
    12             }
    13         }
    14 
    15         public event PropertyChangedEventHandler PropertyChanged;
    16 
    17         [NotifyPropertyChangedInvocator]
    18         protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    19         {
    20             PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    21         }
    22     }
    View Code

    1. 直接在异步线程下修改ObservableCollection--报错

    1     private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    2     {
    3         var viewModel = this.DataContext as ViewModel;
    4         Task.Run(() =>
    5         {
    6            //此段调用异常
    7             viewModel.ItemsSource.Add("test1");
    8         });
    9     }

    2. 在异步线程下,赋值ObservableCollection--正常

     1     private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
     2     {
     3         var viewModel = this.DataContext as ViewModel;
     4         Task.Run(() =>
     5         {
     6             //此段不会报错
     7             var list = viewModel.ItemsSource.ToList();
     8             list.Add("test0");
     9             viewModel.ItemsSource = new ObservableCollection<string>(list);
    10         });
    11     }

    3. 在异步线程下,赋值ObservableCollection后,再修改ObservableCollection--正常

     1     private void Button1_OnClick(object sender, RoutedEventArgs e)
     2     {
     3         var viewModel = this.DataContext as ViewModel;
     4         Task.Run(() =>
     5         {
     6             //此段不会报错
     7             viewModel.ItemsSource = new ObservableCollection<string>(new List<string>() { "test3", "test2" });
     8             //此段不会报错
     9             viewModel.ItemsSource.Add("test4");
    10         });
    11     }

    在异步线程下设置的ItemsSource,可以被当前异步线程调用。

    4. 异步线程下赋值ObservableCollection,然后在UI线程修改ObservableCollection--正常

     1         private void Button1_OnClick(object sender, RoutedEventArgs e)
     2         {
     3             var viewModel = this.DataContext as ViewModel;
     4             Task.Run(() =>
     5             {
     6                 //此段不会报错
     7                 viewModel.ItemsSource = new ObservableCollection<string>(new List<string>() { "test0" });
     8             });
     9         }
    10 
    11 
    12         private void Button2_OnClick(object sender, RoutedEventArgs e)
    13         {
    14             var viewModel = this.DataContext as ViewModel;
    15             //此段不会报错
    16             viewModel.ItemsSource.Add("test2");
    17         }

    在异步线程下设置的ItemsSource,可以被UI线程调用。此处可以理解为,赋值时,框架默默转到UI线程处理了?

    但是上面3流程,为何正常,so weird~

    5. 异步线程下,回到UI线程中,修改ObservableCollection--正常

     1     private void Button1_OnClick(object sender, RoutedEventArgs e)
     2     {
     3         var viewModel = this.DataContext as ViewModel;
     4         Task.Run(() =>
     5         {
     6             Application.Current.Dispatcher.Invoke(() =>
     7             {
     8                 //此段不会报错
     9                 viewModel.ItemsSource.Add("test");
    10             });
    11         });
    12     }
  • 相关阅读:
    C++ string char[] 转化
    c++ 转化
    2014/4/16
    2014/4/11
    垂直电商现倒闭潮
    经典K线组合图解 > 正文
    上下影线
    分​析​主​力​试​盘​手​法
    nginx重新编译不停服
    nexus
  • 原文地址:https://www.cnblogs.com/kybs0/p/10785489.html
Copyright © 2020-2023  润新知