web-dev-qa-db-fra.com

L'application a appelé une interface qui a été organisée pour un autre thread - Application Windows Store

Donc, j'ai d'abord lu une tonne de fils sur ce problème particulier et je ne comprends toujours pas comment le résoudre. Fondamentalement, j'essaie de communiquer avec une websocket et de stocker le message reçu dans une collection observable liée à une liste. Je sais que je reçois une réponse correctement du socket, mais quand il essaie de l'ajouter à la collection observable, il me donne l'erreur suivante:

The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

J'ai lu quelques informations sur "l'expédition" ainsi que d'autres choses, mais je suis tout simplement confus! Voici mon code:

public ObservableCollection<string> messageList  { get; set; }
private void MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)
    {
        string read = "";
        try
        {
            using (DataReader reader = args.GetDataReader())
            {
                reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
                read = reader.ReadString(reader.UnconsumedBufferLength);
            }
        }
        catch (Exception ex) // For debugging
        {
            WebErrorStatus status = WebSocketError.GetStatus(ex.GetBaseException().HResult);
            // Add your specific error-handling code here.
        }


        if (read != "")
           messageList.Add(read); // this is where I get the error

    }

Et voici la liaison:

protected override async void OnNavigatedTo(NavigationEventArgs e)
{
    //await Authenticate();
    Gameboard.DataContext = Game.GameDetails.Singleton;
    lstHighScores.ItemsSource = sendInfo.messageList;
}

Comment puis-je faire disparaître l'erreur tout en restant liée à la collection observable pour ma vue de liste?

50
Yecats

Cela a résolu mon problème:

Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
    {
        // Your UI update code goes here!
    }
);

Façon correcte d'obtenir le CoreDispatcher dans une application Windows Store

113
various

Essayez de remplacer

messageList.Add(read); 

avec

Dispatcher.Invoke((Action)(() => messageList.Add(read)));

Si vous appelez de l'extérieur de votre classe Window, essayez:

Application.Current.Dispatcher.Invoke((Action)(() => messageList.Add(read)));
7
Baldrick

Légère modification pour les méthodes asynchrones basées sur les tâches mais le code ici ne sera pas attendu.

await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
    // Your UI update code goes here!
}
).AsTask();

Ce code attendra et vous permettra de renvoyer une valeur:

    private async static Task<string> GetPin()
    {
        var taskCompletionSource = new TaskCompletionSource<string>();

        CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
        async () =>
        {
            var pin = await UI.GetPin();
            taskCompletionSource.SetResult(pin);
        }
        );

        return await taskCompletionSource.Task;
    }

Et sur Android:

    private async Task<string> GetPin()
    {
        var taskCompletionSource = new TaskCompletionSource<string>();

        RunOnUiThread(async () =>
        {
            var pin = await UI.GetPin();
            taskCompletionSource.SetResult(pin);
        });

        return await taskCompletionSource.Task;
    }
2