在异步线程中创建对象会导致STA异常。

3

我是一名能够协助翻译的助手。以下为您翻译的内容:

我有一个类,当某些操作的状态发生改变时,应向用户显示一些消息,如下所示:

public static class AutoUpdater
    {
        public static async void AutoUpdateCheck()
        {
            UpdaterStatus.CurrentUpdateStatus = await UpdaterLogic.CheckForUpdateAsync();
        }

        public static void OnStatusChanged()
        {
                switch (UpdaterStatus.CurrentStatus)
                {
                    case UpdateStatus.UpdateFound:
                        {
                            Message ToAdd = new Message("some params"); //Exception here
                            MessagesManager.AddNewMessage(ToAdd);
                            break;
                        }
                    //some other cases
                }
        }

当应用程序启动时,我会订阅以下事件:AutoUpdater
UpdaterStatus.EventStatusChanged += (sender, args) => { AutoUpdater.OnStatusChanged(); };

我得到的异常是:“调用线程必须是STA,因为许多UI组件需要这个”。
但是,我不能自己创建STA线程,然后将新创建的消息添加到其父控件中,因为这样我会得到一个异常,说“该对象属于另一个线程”。
有没有什么解决方法?

3
不要在后台线程上创建UI元素。为消息创建一个视图模型,并使用数据模板来可视化它们,例如在ItemsControl中。 - Clemens
控件应该只能从创建它们的线程访问。此外,它们应该在 UI 线程上创建和访问。如果您想从另一个线程更新它们,则应使用 Dispatcher。请参考用户“tym32167”提供的答案。 - Kamalesh Wankhede
2个回答

4

您应该在UI线程中创建UI控件。您可以尝试在此处使用调度程序。

Application.Current.Dispatcher.Invoke(/* your action here*/ () => {/* creating UI controls */});

我正在尝试的事情是在WinForms项目中完成,同时使用WPF控件(Message类)。没有Application.Current这样的东西,但是我尝试做的是:Dispatcher.CurrentDispatcher.Invoke(new Action(() => MessagesManager.AddNewMessage(new Message("some params")))); 然而异常仍然是相同的,我做错了什么吗? - Ilya Bezus
你需要找到UI线程的Dispatcher。当你尝试调用Dispatcher.CurrentDispatcher时,你会得到当前线程的Dispatcher,但是当前线程不是UI线程,所以这并不能解决你的问题。 - tym32167
关于 Application.Current,您可以尝试这个链接:https://dev59.com/eFsV5IYBdhLWcg3wsQrf 希望能帮到您。 - tym32167
请避免依赖于特定的GUI类库,SynchronizationContext.Current是适当的解决方案。在将要在UI线程上运行的代码中复制其值,最好在构造函数中实现。 - Hans Passant
太感谢了,我只需要使用你提供的(System.Windows.Application.Current.Dispatcher.Invoke)而不是Dispatcher.CurrentDispatcher.Invoke就可以了。现在正常工作了。谢谢! - Ilya Bezus

0

请将您的函数更新如下

public void OnStatusChanged()
    {
        if (this.Dispatcher.CheckAccess())
        {
            switch (UpdaterStatus.CurrentStatus)
            {
                case UpdateStatus.UpdateFound:
                    {
                        Message ToAdd = new Message("some params"); //Exception here
                        MessagesManager.AddNewMessage(ToAdd);
                        break;
                    }
                //some other cases
            }
        }
        else
            this.Dispatcher.Invoke(new Action(OnStatusChanged));
    }   

遗憾的是,this.Dispatcher并不存在。 - Ilya Bezus
好的,我忘记了您使用了静态方法,所以它在静态方法内不可用。您可以使用任何形式或控件对象代替此方法。 - Pratik Parikh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接