应用程序调用了一个为不同线程编组的接口 - Windows Store 应用程序

65

所以,首先我阅读了大量关于这个特定问题的帖子,但我仍然不明白如何解决它。基本上,我正在尝试与websocket通信,并将收到的消息存储在绑定到listview的observable collection中。我知道我从套接字正确地获得了响应,但是当它尝试将其添加到可观察集合时,它会给我以下错误:

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

我已经阅读了一些关于“dispatch”的信息以及其他东西,但是我仍然非常困惑!这是我的代码:

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

    }

并且这是绑定:

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

我该如何在绑定到可观察的集合以用于我的列表视图时消除错误?

5个回答

131

8
FYI,这相当于Android中的runOnUiThread。http://developer.android.com/reference/android/app/Activity.html#runOnUiThread(java.lang.Runnable) - kospol
3
难以置信,这正是我的确切问题,并且在搜索整个异常信息后排名第一于谷歌搜索结果中。不错! - Emanuel Vintilă
1
@nickpick - 不完全是这样... 这解决了C#中Windows应用程序的一个非常具体的问题。 - ndbroadbent
3
我对C#和Windows开发非常陌生,但这个方法调用链非常长,感觉有点像骗局。有没有更好的方法来做到这一点? - ndbroadbent
1
这很好,但对于基于任务的异步场景没有帮助,如果您需要等待从“您的UI更新代码放在这里!”部分返回值,那么您就无法做到。我已经添加了另一个答案,可以实现这一点。 - Christian Findlay
显示剩余2条评论

10

尝试替换

messageList.Add(read); 

使用

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

如果你是从Window类的外部调用该方法,请尝试以下操作:

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

1
Dispatcher位于哪个命名空间中?它解析为“System.ServiceModel.Dispatcher”,但Invoke不是它的方法。 - Yecats
2
当在页面上(或任何DependencyObject中)使用时,请调用Dispatcher.RunAsync(()=> messageList.Add(read)); 否则请在其他地方调用Window.Current.Dispatcher.RunAsync(()=> messageList.Add(read))。 - HDW Production

7

对于基于任务的异步方法进行轻微修改,但这里的代码不会被等待。

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

这段代码将会等待,并允许你返回一个值:

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

在安卓设备上:
    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
在 Xamarin 中,我通过使用以下方式解决了这个问题:
Device.BeginInvokeOnMainThread(() => {
   // code goes here
});

0
可能这不是一个“好”的做法,但它能运行... 我从 webSocket 发送一条消息到 mainBody 实例,在那里我有一个定时器读取器...
public class C_AUTHORIZATION
{
    public Observer3.A_MainPage_cl parentPageInstance; //еще одни экземпляр родителя
    public WebSocket x_Websocket; 
    private string payload = "";
    private DateTime nowMoment = DateTime.Now;
    public void GET_AUTHORIZED()
    {
       bitfinex_Websocket= new WebSocket("wss://*****.com/ws/2");

        var apiKey = "";
        var apiSecret = "";
        DateTime nowMoment = DateTime.Now;            

        payload = "{}";            

        x_Websocket.Opened += new EventHandler(websocket_Opened);                                                         
       x_Websocket.Closed += new EventHandler(websocket_Closed);  
    }
    
    void websocket_Opened(object sender, EventArgs e)
    {
        x_Websocket.Send(payload);
        parentPageInstance.F_messager(payload);
    }
    
    void websocket_Closed(object sender, EventArgs e)
    {
        parentPageInstance.F_messager("L106 websocket_Closed!");
        GET_AUTHORIZED();  
    }
   

}

public sealed partial class A_MainPage_cl : Page
{      
    DispatcherTimer ChartsRedrawerTimer;
    public bool HeartBeat = true;
   
    private string Message;        
    public A_MainPage_cl()
    {
       this.InitializeComponent();
      
        ChartsRedrawerTimer = new DispatcherTimer() { Interval = new TimeSpan(0, 0, 0, 0, 100) }; 
        ChartsRedrawerTimer.Tick += Messager_Timer;
        ChartsRedrawerTimer.Start();

        
    }        
         
    private void Messager_Timer(object sender, object e)
    {            
        if(Message !=null) // 
        {
            F_WriteLine(Message);
            Message = null; //  

        } 
    }
    public void F_messager(string message) // 
    { 
        Message = message; 
    }

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