Silverlight ViewModel中的BackgroundWorker

时间:2012-11-23 11:45:48

标签: multithreading silverlight mvvm backgroundworker

我在Silverlight视图中有一个TabControl,我通过将其ItemsSource绑定到我的ViewModel中的TabItems ObservableCollection来加载Tabs。

要打开一个新选项卡,需要一段时间来创建它并加载它,我想同时运行一个BusyIndi​​cator。

当它们在ViewModel中创建和加载时,如果我在调用“load”方法之前设置了IsBusy属性,它就不会显示,因为它不是异步的。

我尝试在后台工作程序中设置它,但是当我创建TabItem以将其添加到TabItems列表(UnauthorizedAccessException)时它崩溃了。

任何想法???提前谢谢。

2 个答案:

答案 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线程的变量。