c# - 应用程序调用了为不同线程编码的接口(interface)。 (来自 HRESULT : 0x8001010E (RPC_E_WRONG_THREAD)) 的异常

标签 c# multithreading async-await windows-phone-8.1

在我的 Windows Phone 8.1 应用程序中,我有一个单例服务 DataService,它应该偶尔下载一些数据。同时在 UI 上我应该显示接收到的数据量。 DataService.StartGettingData() 在用户登录应用程序时被调用:

void StartGettingData()
{
    if (getDataTaskCancellationTokenSource != null)
        getDataTaskCancellationTokenSource.Cancel();

    getDataTaskCancellationTokenSource = new CancellationTokenSource();
    var token = getDataTaskCancellationTokenSource.Token;

    Task.Factory.StartNew(async () => await ExecuteCycleAsync(token), token);
}

async Task ExecuteCycleAsync(CancellationToken cancellationToken)
{
    while (true)
    {
        cancellationToken.ThrowIfCancellationRequested();
        await LoadDataAsync(cancellationToken);
        cancellationToken.ThrowIfCancellationRequested();
        await Task.Delay(timeTillNextDownload, cancellationToken);
    }
}

当用户在

的帮助下注销时,此任务将被取消
if (getDataTaskCancellationTokenSource != null)
    getDataTaskCancellationTokenSource.Cancel();

包含下载结果的属性如下所示:

List<DataType> Data = new List<DataType>();
public IEnumerable<DataType> Data
{
    get { return Data; }
    set
    {
        Data = value.ToList();
        OnDataUpdated();
    }
}

void OnDataUpdated()
{
    var handler = DataUpdated;
    if (handler != null)
        handler(this, EventArgs.Empty);
}

这部分似乎一直有效,直到我不得不在屏幕上显示数据量。 我的 MainViewModel 获得了注入(inject)了 Ninject 的 DataService 实例。

readonly IDataService DataService;

public MainViewModel(IDataService dataService)
{
    DataService = dataService;
    DataService.DataUpdated += DataService_DataUpdated;
    UpdateDataCount();
}

void DataService_DataUpdated(object sender, EventArgs e)
{
    UpdateDataCount();
}

void UpdateDataCount()
{
    DataCount = DataService.Data.Count();
}

在 xaml 中,我将 TextBlock 绑定(bind)到 MainViewModel 的 DataCount 属性

int DataCount;
public int DataCount
{
    get { return DataCount; }
    set
    {
        DataCount = value;
        OnPropertyChanged();
    }
}

protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
        handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

这就是出现问题的地方:OnPropertyChanged 失败 “应用程序调用了一个为不同线程编码的接口(interface)。(来自 HRESULT 的异常:0x8001010E (RPC_E_WRONG_THREAD))”在 DataService.LoadDataAsync() 中被捕获。 我知道运行时试图告诉我我正在从非 ui 线程访问 UI 元素。但我是吗?我认为 OnPropertyChanged 是将 UI 与其余后台任务断开连接的神奇之处。 当然,可以通过这种方式实现 OnPropertyChanged 来解决问题:

public CoreDispatcher Dispatcher { get; set; }

protected async void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
        await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        });
    }
}

但是真的应该这样实现吗?还是我在 DataService.ExecuteCycleAsync() 中遗漏了什么?

最佳答案

不想深入挖掘,我相信你的问题是这样的:

Task.Factory.StartNew(async () => await ExecuteCycleAsync(token), token);

简单的改成这样,看看能不能正常工作:

ExecuteCycleAsync(token);

否则,里面的代码ExecuteCycleAsync在没有同步上下文的线程上开始执行,这可能导致各种不同类型的问题,具体取决于内部的内容 LoadDataAsync .

注意调用ExecuteCycleAsync(token)像这样仍然是一个即发即弃的调用,可能不会观察到任何异常(更多 here )。您可能想要存储 Task它返回的对象,以便以后能够观察到它。

关于c# - 应用程序调用了为不同线程编码的接口(interface)。 (来自 HRESULT : 0x8001010E (RPC_E_WRONG_THREAD)) 的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27109584/

相关文章:

c# - 接受变量的静态成员会损坏吗?

java - 如何为 Web 应用程序配置 apache http 客户端 v3.0(多线程)

c# - 等待手动创建的任务正在卡住 ASP.NET 应用程序

python - 如何不等待异步循环?

c# - Unity动态加载和添加动画 Controller

c# - 使用 Pdftron 在 C# 中将 Excel 转为 Pdf

c# - Linq-To-SQL CreateDatabase 不创建存储过程

c# - MVP:一种复杂表单(winforms)的多个 View /演示者?

c++ - 有两个线程的运行时间与一个线程的运行时间没有改善

c# - Entity Framework 可查询异步