BackgroundWorker in Silverlight ViewModel

南楼画角 提交于 2019-12-11 19:09:23

问题


I have a TabControl in a Silverlight View and I'm loading Tabs by binding its ItemsSource to a TabItems ObservableCollection in my ViewModel.

To open a new tab, it takes a little while to create it and load it and I want to run a BusyIndicator meanwhile.

As they are created and loaded in the ViewModel, it doesn't show up if I set IsBusy property before calling the "load" method because it's not asynchronous.

I've tried to set it in a backgroundworker but it crashes when I create the TabItem to add it to the TabItems list (UnauthorizedAccessException).

Any idea??? Thanks in advance.


回答1:


Use a Task (AsyncCtp with Silverlight 4):

public void Load(){
    this.IsBusy = true;
    Task.Factory.StartNew(()=> DoHeavyWork())
        .ContinueWith( t => this.IsBusy = false);
}

It gets even better if you can use the new async/await features with the Async CTP or with VS2012/Silverlight 5

public async void Load(){
    try{
        this.IsBusy = true;

        await Task.Factory.StartNew(()=> DoHeavyWork());
    }
    finally
    {       
        this.IsBusy = false;
    }
}

EDIT

I assume you are updating the ObservableCollection in the background task. That will indeed give you problems because the handlers that deal with the collection update are not run in the UI thread, so the collection update is not thread safe as the binding system is. For that to work, you will have to add the items to the ObservableCollection in the UI thread. If you can fetch all your items at once, you can do this:

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;
    }
}

If you have to load in batches, you can add the items to the collection using the current Dispatcher, like I suggested in this answer.




回答2:


This happens when you try to access the elements of UI, or the collections which alters the data which in turn reflects on UI. This is actually the cross thread exception. When you create a background worker, you are basically creating another thread. Therefore, you cannot access the main UI thread's variable from Background worker.



来源:https://stackoverflow.com/questions/13528486/backgroundworker-in-silverlight-viewmodel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!