在 UWP 中使用 Caliburn.Micro 从构造函数调用异步方法
Async method call from constructor using Caliburn.Micro in UWP
我有以下 ViewModel 结构:
- App.xaml.cs
- 主视图模型
- DetailViewModel
我通过以下代码在 MainViewModel 和 DetailViewModel 之间导航:
navigationService.For<DetailViewModel>().Navigate();
是DetailViewModel的构造函数:
public DetailViewModel(INavigationService navigationService)
{
GetData();
}
private async Task GetData()
{
using (var context = new MyDataContext())
{
var result = await (from data in context.Data
select data).ToListAsync();
DataList = new ObservableCollection<Data>(result);
}
}
因为我在调用 GetData
时不使用 await
,所以构造函数应该 return 非常快并且稍后应该填充列表。
我遇到非常慢的导航,我单击 MainViewModel 中的项目,GUI 冻结了一秒钟,我看到详细信息当 列表已填充(调试显示构造函数在列表完成之前完成)。
我看到一条警告说:
Because this call is not awaited, execution of the current method
continues before the call is completed.
那是什么阻碍了?我还应该设置什么?
用这个替换您的代码:
public DetailViewModel(INavigationService navigationService)
{
Task.Run(() =>
{
GetData();
});
}
private void GetData()
{
using (var context = new MyDataContext())
{
var result = await (from data in context.Data
select data).ToListAsync();
DataList = new ObservableCollection<Data>(result);
}
}
按预期方式工作:
public DetailViewModel(INavigationService navigationService)
{
Task.Run(() =>
{
GetData();
}).ContinueWith(
(x) =>
{
Execute.OnUIThread(
() => DataList = new ObservableCollection<Data>(x.Result));
});
};
}
private Task<List<Data>> GetData()
{
using (var context = new MyDataContext())
{
return await (from data in context.Data
select data).ToListAsync();
}
}
感谢您的建议。
AFAIK,SQLite Entity Framework 提供程序不支持真正的异步方法。所以,对 ToListAsync
的调用实际上是同步的,导致你的延迟。
解决此问题的最佳方法是将 Task.Run
与 await
一起使用( 而不是 ContinueWith
或 Execute.OnUIThread
):
public DetailViewModel(INavigationService navigationService)
{
InitializeAsync();
}
private async Task InitializeAsync()
{
try
{
DataList = await Task.Run(() => GetData());
}
catch
{
// TODO: Log
}
}
private List<Data> GetData()
{
using (var context = new MyDataContext())
{
return context.Data.ToList();
}
}
注意引入一个try
/catch
;此处的错误处理是必要的,因为 InitializeAsync
被视为 "top-level" 异步操作。
我有以下 ViewModel 结构:
- App.xaml.cs
- 主视图模型
- DetailViewModel
- 主视图模型
我通过以下代码在 MainViewModel 和 DetailViewModel 之间导航:
navigationService.For<DetailViewModel>().Navigate();
是DetailViewModel的构造函数:
public DetailViewModel(INavigationService navigationService)
{
GetData();
}
private async Task GetData()
{
using (var context = new MyDataContext())
{
var result = await (from data in context.Data
select data).ToListAsync();
DataList = new ObservableCollection<Data>(result);
}
}
因为我在调用 GetData
时不使用 await
,所以构造函数应该 return 非常快并且稍后应该填充列表。
我遇到非常慢的导航,我单击 MainViewModel 中的项目,GUI 冻结了一秒钟,我看到详细信息当 列表已填充(调试显示构造函数在列表完成之前完成)。
我看到一条警告说:
Because this call is not awaited, execution of the current method continues before the call is completed.
那是什么阻碍了?我还应该设置什么?
用这个替换您的代码:
public DetailViewModel(INavigationService navigationService)
{
Task.Run(() =>
{
GetData();
});
}
private void GetData()
{
using (var context = new MyDataContext())
{
var result = await (from data in context.Data
select data).ToListAsync();
DataList = new ObservableCollection<Data>(result);
}
}
按预期方式工作:
public DetailViewModel(INavigationService navigationService)
{
Task.Run(() =>
{
GetData();
}).ContinueWith(
(x) =>
{
Execute.OnUIThread(
() => DataList = new ObservableCollection<Data>(x.Result));
});
};
}
private Task<List<Data>> GetData()
{
using (var context = new MyDataContext())
{
return await (from data in context.Data
select data).ToListAsync();
}
}
感谢您的建议。
AFAIK,SQLite Entity Framework 提供程序不支持真正的异步方法。所以,对 ToListAsync
的调用实际上是同步的,导致你的延迟。
解决此问题的最佳方法是将 Task.Run
与 await
一起使用( 而不是 ContinueWith
或 Execute.OnUIThread
):
public DetailViewModel(INavigationService navigationService)
{
InitializeAsync();
}
private async Task InitializeAsync()
{
try
{
DataList = await Task.Run(() => GetData());
}
catch
{
// TODO: Log
}
}
private List<Data> GetData()
{
using (var context = new MyDataContext())
{
return context.Data.ToList();
}
}
注意引入一个try
/catch
;此处的错误处理是必要的,因为 InitializeAsync
被视为 "top-level" 异步操作。