【问题标题】:How to solve task execution problem with thread?如何用线程解决任务执行问题?
【发布时间】:2019-04-29 08:45:15
【问题描述】:

我正在创建一个使用两个线程的应用程序,一个用于整个 UI,另一个用于检索串行链接接收到的数据的后台任务。

当启动我的应用程序时,会显示一个扩展的初始屏幕,解锁它并转到主页,应用程序需要来自服务器“启动”的消息。

当我收到一条消息时,我的后台任务的 OnTaskCompleted 方法会激活并读取我的后台任务存储的数据。 (见下面的代码)。

private void Task_Completed(BackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs args)
    {
        var taskName = sender.Name; // Affiche le nom de la tâche en background qui renvoi le task completed
        Debug.WriteLine(taskName);
        var localSettingsData = ApplicationData.Current.LocalSettings; // Créer une variable locale qui stocke en mémoire cache des informations

        try
        {
            args.CheckResult(); // On test si la tâche a bien été terminée 
            Object value = localSettingsData.Values["data"]; // On va lire dans le champs "data" de notre mémoire
            if (value == null) // Test sur notre valeur d'objet
            {
                Debug.WriteLine("Aucune donnée."); // Affichage en debug si aucune donnée trouvée
            }
            else
            {
                Debug.WriteLine("Donnée trouvée."); // Si on trouve une donnée alors, on execute le switch ci-dessous
                RecptData.TriMessage(value); // Envoi de notre message à la class qui gère tous les messages entrant pour les trier et les affecter sur l'IHM
            }
        }
        catch (Exception e)
        {
            Debug.WriteLine("Erreur OnTaskCompleted : " + e);
        }
    }

你可以看到我也将值对象传递给另一个类来对接收到的消息进行处理。这是 TriMessage 方法:

public void TriMessage(object data)
    {
        ExtendedSplash UnlockScreen = new ExtendedSplash(splash, state);

        switch (data.ToString())
        {
            case "Test":
                Debug.WriteLine("OK Fonctionne.");
                break;

            case "start":
                Debug.WriteLine("Dévérouillage de l'application");
                UnlockScreen.DismissExtendedSplash();
                break;
        }
    }

当我收到启动消息时,我调用 DimissExtendedSplash 方法来停止它,但这是 Visual 中出现的错误代码。我不知道如何改变线程来避免这个问题。

视觉错误:

Erreur OnTaskCompleted : System.Exception: L’application a appelé une interface qui était maintenue en ordre pour un thread différent. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
   at Windows.UI.Xaml.Controls.Page..ctor()
   at PhonieMartha.ExtendedSplash..ctor(SplashScreen splashscreen, Boolean loadState)
   at PhonieMartha.ReceptionMessageLTO.TriMessage(Object data)
   at PhonieMartha.SocketConnexionTask.Task_Completed(BackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs args)

【问题讨论】:

  • 您没有显示相关代码。通常 bgw 完成事件应该在 UI 线程上运行,但仅当 RunWorkerAsync 也从那里启动时。你的线程可能太多了。

标签: c# visual-studio xaml uwp


【解决方案1】:

发生这种情况是因为您试图从不是 UI 线程的不同线程更改 UI。

您正在后台线程中调用TriMessage 方法,该线程试图通过此方法更改其中的用户界面:

UnlockScreen.DismissExtendedSplash();

您无法从后台线程更新 UI,但您可以发布 使用 CoreDispatcher.RunAsync 向它发送消息以使代码运行 在那里。

取自Keep the UI Thread Responsive

如果您想了解调度程序的工作原理,这里有一篇很好的帖子:Dispatcher

【讨论】:

  • 好的,所以目前我正在通过 TCP 连接获取数据,所以我正在使用在后台任务中读取的套接字。我必须处理收到的消息以将它们转化为对 IU 的操作。要执行此类操作,我的连接套接字不必处于后台任务中,那么如果我不能用收到的内容修改 UI?
  • 你是对的,你需要一个后台任务来从你的套接字连接中读取消息,但是,当需要改变 UI 本身时(在你的场景中,我假设这是关闭启动屏幕/image),您需要调用调度程序在 UI 线程中对任务进行排队。如果您尝试通过 UI 之外的任何其他线程执行此操作,则会遇到此问题。
  • 好的,非常感谢。我将去了解调度程序以在我的项目中实现它。
猜你喜欢
  • 1970-01-01
  • 2022-08-04
  • 2021-12-08
  • 2014-02-15
  • 2020-09-07
  • 2021-05-04
  • 1970-01-01
  • 2010-10-26
  • 1970-01-01
相关资源
最近更新 更多