我在Silverlight视图中有一个TabControl,我通过将其ItemsSource绑定到我的ViewModel中的TabItems ObservableCollection来加载Tabs。
要打开一个新选项卡,需要一段时间来创建它并加载它,我想同时运行一个BusyIndicator。
当它们在ViewModel中创建和加载时,如果我在调用“load”方法之前设置了IsBusy属性,它就不会显示,因为它不是异步的。
我尝试在后台工作程序中设置它,但是当我创建TabItem以将其添加到TabItems列表(UnauthorizedAccessException)时它崩溃了。
任何想法???提前谢谢。
答案 0 :(得分:2)
使用任务(AsyncCtp with Silverlight 4):
public void Load(){
this.IsBusy = true;
Task.Factory.StartNew(()=> DoHeavyWork())
.ContinueWith( t => this.IsBusy = false);
}
如果您可以将新的async / await功能与Async CTP或VS2012/Silverlight 5
一起使用,那就更好了public async void Load(){
try{
this.IsBusy = true;
await Task.Factory.StartNew(()=> DoHeavyWork());
}
finally
{
this.IsBusy = false;
}
}
修改强>
我假设您正在后台任务中更新ObservableCollection。这确实会给你带来问题,因为处理集合更新的处理程序不在UI线程中运行,因此集合更新不像绑定系统那样是线程安全的。为此,您必须将项添加到UI线程中的ObservableCollection。如果您可以一次性获取所有商品,则可以执行以下操作:
public async void Load(){
try{
this.IsBusy = true;
// Returns the fetched items
var items = await Task.Factory.StartNew(()=> DoHeavyWork());
// This will happen in the UI thread because "await" returns the
// control to the original SynchronizationContext
foreach(var item in items)
this.observableCollection.Add(item);
}
finally
{
this.IsBusy = false;
}
}
如果必须批量加载,可以使用当前的Dispatcher将项添加到集合中,就像我在this answer中建议的那样。
答案 1 :(得分:0)
当您尝试访问UI的元素或更改数据的集合时会发生这种情况,而这些集合又反映在UI上。这实际上是跨线程异常。创建后台工作程序时,您基本上是在创建另一个线程。因此,您无法从后台工作程序访问主UI线程的变量。