0

I have a WPF MVVM c# application. In one of my views I have to retrieve data from the database after a button is clicked. The call to the database is really long and so I want to enable a spinner while the call is being made and disable it when the call is done.

So in the method handling the button click (using Command, not code behind) I set the boolean variable to enable the spinner then create a Task that goes fetches the data and set it to an ObservableCollection<T> like this

private void GetDataButtonCommand() {
    this.IsBusy = true;
    var tasks = new List<Task>();

    tasks.Add(Task.Factory.StartNew(() =>
    {
        System.Windows.Application.Current.Dispatcher.BeginInvoke(new System.Action(() =>
        {
            var GotData= DBHelper.GetData();
            _observablecollectionname.Clear();
            foreach (var item in GotData)
            {
                _observablecollectionname.Add(item);
            }
        }));
    }));

    var finalTask = Task.Factory.ContinueWhenAll(tasks.ToArray(), datacomplete =>
    {
        this.IsBusy = false;  
    });
}

On completion of the Task I would like to disable the spinner.

The problem that I am running into is that I am unable to see the spinner during the call. The UI is still being blocked, even thou I am using a Task to execute the database query.

What am I doing wrong?

Tseng
  • 61,549
  • 15
  • 193
  • 205
ANewUser
  • 13
  • 6
  • Draw https://en.wikipedia.org/wiki/Swim_lane. Take list of paper draw 2 lanes "UI thread", "other thread". Than map each line of your code to one of the lanes.... If that is not enough to find a problem it should at least clarify to you what you don't know. – Alexei Levenkov Feb 04 '16 at 20:46
  • Are the tasks executed in a background thread? There is no async/await in this code. For me it looks like that this running on the UI thread. Or at least there is no point where returning from background thread. – onestarblack Feb 04 '16 at 20:48
  • `ContinueWith` and `ContinueWhenAll` are equivalent to `await` call in C# 5.0 – Tseng Feb 04 '16 at 20:50
  • @Tseng again something learned ;) – onestarblack Feb 04 '16 at 20:52

2 Answers2

5

Your code is running on the UI thead.

You do all your operations in System.Windows.Application.Current.Dispatcher.BeginInvoke(new System.Action(() => { ... })) so it's natural to block the UI.

You should only call the dispatcher when you really need to do an UI action.

Move var GotData= DBHelper.GetData(); before the dispatcher.

But it'd be better to use the async/await pattern/keywords of C# 5.0 and higher.

Tseng
  • 61,549
  • 15
  • 193
  • 205
1

I always use the bellow code when I have a long running query.

    private async void button1_Click(object sender, EventArgs e)
    {
        var list = await GetDatabaseAsync();
        //do whatever you need with the list.
    }



    private async Task<List<string>>  GetDatabaseAsync()
    {
        var list = Task.Run(() =>
        {
            var _observablecollectionname = new List<string>();
            var GotData = Helper.GetData();
            _observablecollectionname.Clear();
            foreach (var item in GotData)
            {
                _observablecollectionname.Add(item);
            }
            return _observablecollectionname;
        });
        return await list;
    }
Tseng
  • 61,549
  • 15
  • 193
  • 205
Bewar Salah
  • 567
  • 1
  • 5
  • 15
  • The main issue here is, that you can't manipulate the observable collection from a thread. It has to be done via and you are using list in your example. – Tseng Feb 04 '16 at 21:02
  • List can be changed to List of anything like List. The question is a little bit ambiguous. If there is only one list the above code can work fine. But if there are multiple lists, then there is another way. – Bewar Salah Feb 04 '16 at 21:18
  • Question is about WPF and `ObservableCollection`. It's not a normal list or collection, it's one that impements `INotifyCollectionChanged` interface, used to notify the WPF UI when the collection gets updated. And you can only add/remove items from it from the UI thread. You get exceptions, if you attempt to do it from an non-UI thread. See http://stackoverflow.com/a/2104750/455493. On a side note, in MVVM we also don't register event handlers, but that's another story – Tseng Feb 04 '16 at 21:26