0

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

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

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

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

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

4

2 回答 2

2

使用任务(AsyncCtp 和 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 将项目添加到集合中,就像我在这个答案中建议的那样。

于 2012-11-23T11:54:15.083 回答
0

当您尝试访问 UI 的元素或更改反过来反映在 UI 上的数据的集合时,就会发生这种情况。这实际上是跨线程异常。当你创建一个后台工作者时,你基本上是在创建另一个线程。因此,您无法从后台工作人员访问主 UI 线程的变量。

于 2012-11-25T13:19:14.360 回答