简体   繁体   中英

Using Tasks but the UI is still blocked

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?

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM