C# 应用程序调用了为不同线程封送的接口。(来自HRESULT的异常:0x8001010E(RPC_E_错误_线程))
在我的WindowsPhone8.1应用程序中,我有一个singleton服务DataService,它应该偶尔下载一些数据。同时在UI上,我应该显示接收到的数据量。用户登录到应用程序时调用DataService.StartGettingData():C# 应用程序调用了为不同线程封送的接口。(来自HRESULT的异常:0x8001010E(RPC_E_错误_线程)),c#,multithreading,async-await,windows-phone-8.1,C#,Multithreading,Async Await,Windows Phone 8.1,在我的WindowsPhone8.1应用程序中,我有一个singleton服务DataService,它应该偶尔下载一些数据。同时在UI上,我应该显示接收到的数据量。用户登录到应用程序时调用DataService.StartGettingData(): void StartGettingData() { if (getDataTaskCancellationTokenSource != null) getDataTaskCancellationTokenSource.Ca
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);
}
在xaml中,我将TextBlock绑定到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失败于
“应用程序调用了为不同线程封送的接口。(HRESULT的异常:0x8001010E(RPC_E_错误的_线程)),该接口在DataService.LoadDataAsync()中捕获。
我知道运行时试图告诉我我正在从非UI线程访问UI元素。但我是吗?我认为OnPropertyChanged是将UI与其他后台任务断开连接的神奇地方。
当然,问题可以通过以下方式解决:通过实施OnProperty更改:
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)
仍然是一个fire-and-forget调用,可能没有观察到任何异常(更多)。您可能希望存储它返回的任务
对象,以便以后能够观察它。在哪里创建视图模型的新实例,以及它如何连接到xaml?是否在单独的线程中运行取决于调用OnDataUpdate的位置。我怀疑它是在LoadDataAsync方法中,如果是这样,那么是的,它在一个单独的线程中。没有什么魔法可以让UI线程不受影响,从而使您的方法正确。@Kell,OnDataUpdate是在IEnumerable数据中调用的,因此我认为它是在后台线程上运行的。@Tejassarma我的xaml页面的DataContext绑定到ViewModel属性:DataContext=“{Binding ViewModel,RelativeSource={RelativeSource Self}”它的值也是通过Ninject初始化的:ViewModel=NinjectKernel.Get(TypeOfViewModel)
ExecuteCycleAsync(token);