Shax
Shax

Reputation: 4307

How to correctly refresh data in a grid using Task in WPF

My small WPF code is giving me this error The calling thread cannot access this object because a different thread owns it I know what exactly it is saying but I am unable to understand how can I fix it. I have tried different things but no luck and I admit that I am not good in Task library.

This is what I am trying to achieve.

  1. Load data when WPF form loads - This is ok
  2. On the form user will press the Refresh button to refresh the data from the database.

here is my code

public partial class DocListView : UserControlListBase
{
    private ScecoBillDataScope _scecoBillDataScope;
    public EntityCollection<ScecoBillEntity> ScecoBills = new EntityCollection<ScecoBillEntity>();

   public DocListView()
    {
        InitializeComponent();
        LoadData();
    }


   private async void LoadData()
    {
        await Task.Run(() =>
        {

            _scecoBillDataScope.FetchData();
        });
        var collectionView = CollectionViewSource.GetDefaultView(_scecoBillDataScope.ScecoBills);

        await Dispatcher.BeginInvoke(new ThreadStart(()=> LayoutRoot.DataContext = collectionView));

     }

  private void BbiRefresh_ItemClick(object sender, DevExpress.Xpf.Bars.ItemClickEventArgs e)
    {
        _scecoBillDataScope.Reset();
        LoadData();
        e.Handled = true;
    }}

Actually the error is appearing when I click the Refresh button at this line _scecoBillDataScope.FetchData(); Please advice.

Upvotes: 0

Views: 521

Answers (3)

Stephen Cleary
Stephen Cleary

Reputation: 457167

Since your collection items are data bound to your view, you have to treat them as part of your UI.

Try loading a new collection from within Task.Run, and then copying them over your existing items while on the UI thread. So, the new collection is built on a thread pool thread (Task.Run), and then the data-bound collection items are modified from the UI thread.

Upvotes: 0

Masuri
Masuri

Reputation: 1136

It looks like you want to do something in UI Thread.

As You know You can use Dispatcher class.

But There is another way to ask something to UI Thread.

var uiThread = TaskScheduler.FromCurrentSynchronizationContext();

Task.Factory.StartNew(() =>
{
    // I assumed that It returns boolean value
    _scecoBillDataScope.FetchData();
}).ContinueWith(x =>
{
    // Here you can put the code to work on the UI thread.
    if (x.Result)
    {
          var collectionView = CollectionViewSource.GetDefaultView(_scecoBillDataScope.ScecoBills);
          LayoutRoot.DataContext = collectionView;
    }

}, uiThread);

I hope it helps.

thank you.

Upvotes: 0

Mark Feldman
Mark Feldman

Reputation: 16148

Your problem is this line:

await Dispatcher.BeginInvoke(new ThreadStart(()=> LayoutRoot.DataContext = collectionView));

You're just creating a new thread, you have to actually dispatch on the GUI thread:

Application.Current.Dispatcher.Invoke(() =>
{
    LayoutRoot.DataContext = collectionView;
});

Upvotes: 1

Related Questions