简体   繁体   中英

WPF updating the itemssource in a ListBox with an async method

I have a ListBox and wanting to set its ItemsSource to an ObservableCollection that I get from my cloud. I have to await this incoming collection and it is causing my itemssource not to be updated.

This is my approach. This is my xaml.cs constructor:

{
    InitializeComponent();
    GetEmployeeList();
}

And the method it calls:

private async void GetEmployeeList()
{
    await EmployeeController.GetAllEmployees().ContinueWith(r =>
    {
        _employees = (r.Result);
        EmployeeListBox.ItemsSource = _employees;
    });
}

My EmployeeController.GetAllEmployees() returns an ObservableCollection. and _employees gets updated, however my EmployeeListBox doesn't show these objects. I have tried with a static hard coded collection and it works fine - so is it due to my async? Anyone got a suggestion?

- Thanks.

Assuming you're sure the continueWith is being called, It's likely your continueWith code block is happening on a none-UI thread.

One option is to set the CurrentSyncronizationContext for the continuation (example below). This asks the continuation code to execute on the same thread that the original task was started from. Or alternatively, you need to invoke the code on the UI thread, most commonly using the Dispatcher.

private async void GetEmployeeList()
{
   await EmployeeController.GetAllEmployees().ContinueWith(r =>
   {
       _employees = (r.Result);
       EmployeeListBox.ItemsSource = _employees;
   },
   TaskScheduler.FromCurrentSynchronizationContext());
}

However, since you're using an await - and that is being called from a UI thread, you may as well set the result of the await to the ItemSource direct:

private async void GetEmployeeList()
{
   EmployeeListBox.ItemsSource = await EmployeeController.GetAllEmployees();
}

... Which is also a nice demonstration of how much code the async/await keywords save you having to write :)

I think you have a "cross-thread" problem. When you do an async code, it runs in another Thread, and this new thread doesn't have rights to access UserInterface (UI) because controls are owned by User Interface Thread. The solution is to gently ask the UI to execute your code when it will be possible for it :

You have to use a Dispatcher.

    this.Dispatcher.BeginInvoke(new Action(() =>
        {
            // - Change your UI information here

        }), null);

Sometimes, this type of error isn't visible. That's for what this is difficult to diagnose. You could see it by adding Try...Catch around the code executed for the callback.

Best regards,

您可以将项目来源用作IEnumerable,并为每个值使用yield return

If you store the result of your await in a variable and then assign it you should avoid the cross-thread.

private async void GetEmployeeList()
{
    var emps = await EmployeeController.GetAllEmployees();
    EmployeeListBox.ItemsSource = _emps;
}

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