【问题标题】:The application called an interface that was marshalled for a different thread - Xamarin Forms该应用程序调用了一个为不同线程编组的接口 - Xamarin Forms
【发布时间】:2017-06-19 02:12:32
【问题描述】:

我在加载给定页面时通过 WCF 加载一些数据。然后,我想在数据加载后用值填充 Picker。但是,我遇到了跨线程问题。代码如下:

protected async override void OnAppearing()
{
    base.OnAppearing();
    await Task.Factory.StartNew(async () => { await Initialise(); });
}

private async Task Initialise()
{
    var activities = await App.XivicServicesClient.DataAccessCalls.GetRecordsAsync<ActivityDef>(null, new ConnectionInfo(null, App.XivicServicesClient.AuthToken));

    var activityCodes = activities.Select(a => a.Code);
    foreach (var activityCode in activityCodes)
    {
        ActivityPicker.Items.Add(activityCode);
    }
}

在 Windows UWP 中,我得到的错误是

附加信息:应用程序调用了为不同线程编组的接口。 (来自 HRESULT 的异常:0x8001010E (RPC_E_WRONG_THREAD))

我想我正在以一种意想不到的方式使用 OnAppearing 调用,那么我应该如何解决这个问题?我需要在页面开始加载时进行基于任务的异步 WCF 调用。

在 iOS 上,我没有收到错误消息。

【问题讨论】:

  • 如前所述,您不应在此处使用Task.Factory.StartNew。更何况Task.Factory.StartNew是一种危险的方法;即使您想要在后台线程上运行代码,也几乎不应该使用它(改用Task.Run)。

标签: c# multithreading wcf xamarin xamarin.forms


【解决方案1】:

你的问题来自于

ActivityPicker.Item.Add(activityCode);

该行只能在 UI 线程上运行。

您可以使用以下方法轻松修复此代码

protected async override void OnAppearing()
{
    base.OnAppearing();
    var activityCodes = await Task.Factory.StartNew(async () => { await Initialise(); });

    foreach (var activityCode in activityCodes)
    {
        ActivityPicker.Items.Add(activityCode);
    }
}

private async Task<List<string>> Initialise()
{
    var activities = await App.XivicServicesClient
                       .DataAccessCalls
                       .GetRecordsAsync<ActivityDef>(null, new ConnectionInfo(null, App.XivicServicesClient.AuthToken));

    return activities.Select(a => a.Code).ToList();

}

但是,我真的怀疑您“需要”使用Task.Factory.StartNewGetRecordsAsync 已经是一个异步方法。 Initialise(sic) 中的大部分延迟可能来自 I/O 延迟。

从另一个线程运行 Initialise 只会增加运行时间,因为数据需要跨线程封送以及同步。

不如试试吧。

protected async override void OnAppearing()
{
    base.OnAppearing();

    var activities = await App.XivicServicesClient
                          .DataAccessCalls
                          .GetRecordsAsync<ActivityDef>(null, new ConnectionInfo(null, App.XivicServicesClient.AuthToken));

    foreach (var activityCode in activities.Select(a => a.Code))
    {
        ActivityPicker.Items.Add(activityCode);
    }
}

【讨论】:

  • 这里有很多很棒的信息。您对我从反复试验中得出的结论给出了很好的解释。
【解决方案2】:

问题很简单。我添加了不必要的代码,而该代码导致了该错误。下面是固定方法:

protected async override void OnAppearing()
{
    base.OnAppearing();
    await Initialise();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-26
    • 1970-01-01
    • 1970-01-01
    • 2018-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多