异步任务中的 ObservableCollection

ObservableCollection inside a async Task

我在任务中有 ObservableCollection 的这种奇怪行为。

这个工作正常:

    private string status;
    public string Status
    {
        get { return status; }
        set { SetField<string>(ref status, value); }
    }

    public void AddRandomTask()
    {
        Task t = Task.Run(async () =>
        {
            await Randomizer.Instance.LongRandAsync (new MainViewModelObserver(this));
                });

                t.ContinueWith(m => 
                    {
                        string s = "done: " + DateTime.Now.ToString("HH:mm:ss");
                        Status = s;
                    }, TaskScheduler.FromCurrentSynchronizationContext());

                Tasks.Add(t);       

                Msg.Add("Task is added");
            }

失败并出现 2 个异常:

在构造函数中

Msg = new ObservableCollection<string>();

还有:

public ObservableCollection<string> Msg { get; private set; }

public void AddRandomTask()
        {
            Task t = Task.Run(async () =>
            {
                await Randomizer.Instance.LongRandAsync(new MainViewModelObserver(this));
            });

            t.ContinueWith(m => 
                {
                    string s = "done: " + DateTime.Now.ToString("HH:mm:ss");
                    this.Msg.Add(s);
                }, TaskScheduler.FromCurrentSynchronizationContext());

            Tasks.Add(t);       

            Msg.Add("Task is added");
        }

我错过了什么,为什么字符串 属性 与 ObservableCollection 不同?

编辑:例外情况:

A first chance exception of type 'System.NotSupportedException' occurred in PresentationFramework.dll
A first chance exception of type 'System.NotSupportedException' occurred in mscorlib.dll

它不是失败也不是错误,它是一个功能。

Does a first chance exception mean there is a problem in my code?

First chance exception messages most often do not mean there is a problem in the code. For applications / components which handle exceptions gracefully, first chance exception messages let the developer know that an exceptional situation was encountered and was handled.

http://blogs.msdn.com/b/davidklinems/archive/2005/07/12/438061.aspx

如果没有一个最小的、可重现的例子,很难准确地说出发生了什么;但我怀疑问题是您的代码正在将 data-bound 的可观察 collection 更改为 UI 元素。

作为一般规则,我总是将我的 ViewModel 属性(包括可观察的 collections)视为它们具有 UI 亲和力。

why is a string property different from a ObservableCollection?

我假设你的意思是你发现你可以从后台线程更改字符串 属性 并让它工作,而从后台线程更改 ObservableCollection 会抛出异常。好吧,WPF 试图通过在幕后为简单属性执行一些自动线程封送处理来让事情变得简单。还有 collection 的最新版本 also supports some level of this

但我建议您不要使用它。一方面,WPF 是唯一支持此功能的 XAML 平台 AFAIK。 Windows Store、通用应用程序、Xamarin Forms,...没有其他人这样做,即使是简单的属性。此外,将您的 UI(以及您的 UI 的逻辑表示 - 您的 ViewModel)与后台处理代码分开将使您的代码更具可移植性,并鼓励关注点分离和简单明了更简单。

因此,IMO 最好的方法就是不从后台线程更新 ViewModel。在你的情况下,看起来 Task.Run 无论如何都是多余的,所以这是一个相对容易的修复:

public void AddRandomTask()
{
  Task t = ProcessAsync();
  Tasks.Add(t);       
  Msg.Add("Task is added");
}

private async Task ProcessAsync()
{
  await Randomizer.Instance.LongRandAsync(new MainViewModelObserver(this));
  string s = "done: " + DateTime.Now.ToString("HH:mm:ss");
  this.Msg.Add(s);
}

另请注意单独的 async 方法的使用,这消除了对显式 ConfigureAwait / SynchronizationContext.

的需要