我基于Split Page示例应用创建了一个Windows 8 Metro应用。但是,在示例应用程序中,数据在构造函数中同步加载。我正在访问文本文件,因此需要异步加载数据。构造函数如下所示:
public MyDataSource()
{
DataLoaded = false;
LoadData();
}
LoadData()
是一个填充数据模型的异步方法。这工作正常,并在加载数据时显示数据(这是我想要的行为)。当我尝试测试挂起并终止时,会出现问题。问题是恢复有可能在填充之前尝试访问数据模型:
public static MyDataGroup GetGroup(string uniqueId)
{
// If the data hasn't been loaded yet then what?
if (_myDataSource == null)
{
// Where app has been suspended and terminated there is no data available yet
}
// Simple linear search is acceptable for small data sets
var matches = _myDataSource.AllGroups.Where((group) => group.UniqueId.Equals(uniqueId));
if (matches.Count() == 1) return matches.First();
return null;
}
我可以通过更改构造函数来调用LoadData().Wait
来解决这个问题,但这意味着应用程序会锁定UI线程。我认为我需要的是一种在GetGroup
中获取恢复代码的方法,以等待数据加载而不锁定UI线程。这是可能的还是可取的,如果是的话,怎么做?
编辑:
有一两个人建议缓存LoadData()
的任务。这是一个很好的主意,但GetGroup
中的代码由页面状态管理部分调用,因此不能是异步的。为了解决这个问题,我尝试了以下方法:
if (!DataLoaded)
{
//dataLoading = await MyDataSource.LoadData();
dataLoading.RunSynchronously();
}
但这给了我一个错误:
RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method.
和
dataLoading.Wait()
只需锁定用户界面。
答案 0 :(得分:5)
我认为如果你制作了构造函数async
,这听起来是最好的选择。但是从that's not possible开始,您可以做的是为async
创建MyDataSource
工厂方法:
private MyDataSource()
{
DataLoaded = false;
}
public static async Task<MyDataSource> Create()
{
var source = new MyDataSource();
await source.LoadData();
return source;
}
然后使用_myDataSource
初始化await
:
_myDataSource = await MyDataSource.Create();
如果由于某种原因,您无法执行此操作,则可以存储工厂方法返回的Task
并在GetGroup()
中等待它:
_myDataSourceTask = MyDataSource.Create();
…
public static async Task<MyDataGroup> GetGroup(string uniqueId)
{
var myDataSource = await _myDataSourceTask;
// Simple linear search is acceptable for small data sets
var matches = myDataSource.AllGroups.Where(group => group.UniqueId == uniqueId);
if (matches.Count() == 1) return matches.First();
return null;
}
答案 1 :(得分:1)
如果LoadData是异步的,那么存储任何等待的东西(或创建一个新的)并公开它(例如,像任务一样)然后GetGroup可以被标记为异步并且可以做var data = await _myDataSource.LoadTask或者其他
答案 2 :(得分:1)
我认为Svick最接近回答问题是因为他使用了任务。无论是在GetGroup方法上返回任务还是在LoadAsync方法上返回任务,都可能无关紧要。重要的是你捕获该任务并在以后的简历中引用它。
任务类已记录here,您会注意到它具有 IsCanceled , IsCompleted 和 IsFaulted 等属性。当构造函数启动LoadAsync方法时,您可以将它返回的Task保存为类级变量。稍后,当您的简历代码启动时,您可以检查任务是否仍在运行(即未完成且未出现故障)。如果任务已完成,您可以立即运行简历代码。如果尚未完成,您可以使用 Task.ContinueWith 来安排在任务完成时运行简历代码。
答案 3 :(得分:0)
我还没有查看Windows 8,但我认为它与Windows Phone类似,假设您使用Silverlight(或WPF)来开发您的应用程序,我的问题并不清楚。如果您使用Silverlight:
您需要使用INotifyPropertyChanged接口和ObservableCollection-s才能将数据绑定到UI。这样,每当您更改数据时,UI都会收到有关更改的通知,并且绑定将刷新。
答案 4 :(得分:0)
MyDataGroup是一个实现iNotifyPropertyChanged的公共属性。
UniqueID是一个公共财产。 当UniqueID更改设置MyDataGroup = null然后调用BackGroundWorker到var mathces =但延迟,如果LoadData();工作中。由于这是在后台,延迟不会占用UI。在回调集中,MyDataGroup和UI将收到通知。确保后台工作者可取消,因为当更改UniqueID(如果它正在运行)时,您将要取消它。
我在WPF中这样做,如果它没有转换为Metro抱歉,我会删除。