I am creating an application that uses two threads, one for the whole UI and the other for the background task that retrieves the data received by the serial link.

When launching my application, an extended splash screen is displayed, to unlock it and go to the main page, the application expects a message from the server "start ".

When I receive a message, the OnTaskCompleted method of my background task activates and reads the data stored by my background task. (see the code below).

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);
        }
    }

You can see that I also pass the value object to another class to do the processing of the received message. Here is the TriMessage method:

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;
        }
    }

When I receive the start message, I call the DimissExtendedSplash method to stop it but here is the error code that emerges from Visual. I do not know how to change threads to avoid this problem.

Error from 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)

1 Answers

1
Bruno On Best Solutions

This happens because you are trying to change the UI from a different Thread that is not the UI Thread.

You are calling the TriMessage method inside a background Thread which tries to change the UI inside of it through this method:

UnlockScreen.DismissExtendedSplash();

You can't update the UI from a background thread but you can post a message to it with CoreDispatcher.RunAsync to cause code to be run there.

Taken from Keep the UI Thread Responsive

If you want to understand how the dispatcher works, here is a good post about that: Dispatcher