【发布时间】:2013-08-08 03:28:06
【问题描述】:
在我的 MVVM 应用程序中,我的视图模型调用 3 种不同的服务方法,将每个方法的数据转换为通用格式,然后使用属性通知/可观察集合等更新 UI。
服务层中的每个方法都会启动一个新的Task,并将Task 返回给视图模型。这是我的一种服务方法的示例。
public class ResourceService
{
internal static Task LoadResources(Action<IEnumerable<Resource>> completedCallback, Action<Exception> errorCallback)
{
var t = Task.Factory.StartNew(() =>
{
//... get resources from somewhere
return resources;
});
t.ContinueWith(task =>
{
if (task.IsFaulted)
{
errorCallback(task.Exception);
return;
}
completedCallback(task.Result);
}, TaskScheduler.FromCurrentSynchronizationContext());
return t;
}
}
这是视图模型的调用代码和其他相关部分...
private ObservableCollection<DataItem> Data = new ObservableCollection<DataItem>();
public ICollectionView DataView
{
get { return _dataView; }
set
{
if (_dataView != value)
{
_dataView = value;
RaisePropertyChange(() => DataView);
}
}
}
private void LoadData()
{
SetBusy("Loading...");
Data.Clear();
Task[] tasks = new Task[3]
{
LoadTools(),
LoadResources(),
LoadPersonel()
};
Task.WaitAll(tasks);
DataView = CollectionViewSource.GetDefaultView(Data);
DataView.Filter = FilterTimelineData;
IsBusy = false;
}
private Task LoadResources()
{
return ResourceService.LoadResources(resources =>
{
foreach(var r in resources)
{
var d = convertResource(r);
Data.Add(d);
}
},
error =>
{
// do some error handling
});
}
这几乎可行,但有几个小问题。
数字 1:在最开始调用 SetBusy 时,在我开始任何任务之前以及在我调用 WaitAll 之前,我将 IsBusy 属性设置为 true。这应该会更新 UI 并显示 BusyIndicator 控件,但它不起作用。我还尝试添加简单的字符串属性并绑定它们,它们也没有被更新。 IsBusy 功能是基类的一部分,适用于其他视图模型,在这些视图模型中我没有运行多个任务,因此我不认为 XAML 中的属性通知或数据绑定存在问题。
在整个方法完成后,所有数据绑定似乎都已更新。我在输出窗口中没有看到任何“第一次异常”或绑定错误,这让我相信 UI 线程在调用 WaitAll 之前被阻塞了。
第 2 点:我似乎从服务方法返回了错误的任务。我希望WaitAll 之后的所有内容都在视图模型转换了回调中所有服务方法的所有结果之后运行。但是,如果我从服务方法返回延续任务,则永远不会调用延续,WaitAll 将永远等待。奇怪的是绑定到 ICollectionView 的 UI 控件实际上正确显示了所有内容,我认为这是因为 Data 是一个可观察的集合,而 CollectionViewSource 知道集合更改的事件。
【问题讨论】:
标签: c# wpf mvvm task-parallel-library busyindicator