0

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)
ValentinDP
  • 323
  • 5
  • 14
  • You did not show the relevant code. Normally the bgw completed event should run on the UI thread but only when RunWorkerAsync was started from there too. You probably have too many threads. – H H Apr 29 '19 at 11:21

1 Answers1

1

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

Bruno
  • 924
  • 9
  • 20
  • Okay, so currently I'm getting data over a TCP connection, so I'm using a socket that's read in the background task. I have to process the received messages to transform them into action on the IU. To do this kind of thing it is not necessary that my connection socket is in a task of background then if I can not modify the UI with what I receive? – ValentinDP Apr 29 '19 at 12:30
  • You are right, you need a background task to read the messages from your socket connection, however, when it is time to change the UI itself (in your scenario, I assume that is close the splash screen/image), you need to call the dispatcher to queue a task in the UI thread. If you try to do it through any other thread apart from the UI, you'll have this issue. – Bruno Apr 29 '19 at 12:37
  • 1
    Okay thank you so much. I will go and learn about the dispatcher to implement it in my project. – ValentinDP Apr 29 '19 at 12:40