Xamarin Forms - 在选取器选择中使用 Async SelectedIndexChanged

Xamarin Forms - Using Async SelectedIndexChanged in picker selection

我正在为 Android 和 iOS 在 Xamarin Forms 中实现一个应用程序,它与 WebAPI (.NET) 通信以从数据库中检索信息。 在某些时候,我有一个带有多个选择器的屏幕。假设在 picker1 中我们 select 一个国家;在 picker2 的后面我们 select 一个城市。

当一个国家在 picker1 中 selected 时,它会引发一个 SelectedIndexChanged 事件(称为 OnSelectedCountry),该事件调用 WebAPI 从该特定国家/地区检索城市,然后通过以下方式将城市名称绑定到 picker2 picker2.ItemsSource。

这会导致性能不佳,看起来应用程序在执行 OnSelectedCountry 时卡住了,因为 picker1 中的国家/地区列表在 OnSelectedCountry 结束之前不会关闭。 如何在 select 访问一个国家后立即关闭 picker1 中的列表项?或者在上面显示 'loading' 图片。

我已经尝试了 的解决方案,但它们没有用。

代码片段(变量模型省略):

XAML

<Picker x:Name="picker1" Title="Select a country" ItemDisplayBinding="{Binding name}" SelectedIndexChanged="OnSelectedCountry" IsEnabled="False"/>
<Picker x:Name="picker2" Title="Select a city" IsEnabled="False" ItemDisplayBinding="{Binding name}"/>

CS

 ...

 private ObservableCollection<City> _replyCities;

 ...

 async void OnSelectedCountry(object sender, EventArgs e)
 { 
      Country selectedCountry = (Country)picker1.SelectedItem;
      string decodedJson = await RestService.GetDataAsync(selectedCountry.name);
      Reply reply = Newtonsoft.Json.JsonConvert.DeserializeObject<Reply>(decodedJsonInput);

      _replyCities = new ObservableCollection<City>(reply.Cities);
      picker2.ItemsSource = _replyCities;
      picker2.IsEnabled = true;
 }

与 WebAPI 的连接在 RestService 中执行 class 如:

public static async Task<String> GetDataAsync(string queryInput)
{ ... }

你应该运行它在另一个任务中,这样它就不会冻结。

Task.Run(async () => {
        try
        {
            string decodedJson = await RestService.GetDataAsync(selectedCountry.name);
             Reply reply = Newtonsoft.Json.JsonConvert.DeserializeObject<Reply>(decodedJsonInput);

      _replyCities = new ObservableCollection<City>(reply.Cities);
      picker2.ItemsSource = _replyCities;
      picker2.IsEnabled = true;


        }
        catch (System.OperationCanceledException ex)
        {
            Console.WriteLine($"Text load cancelled: {ex.Message}");
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    });

我强烈建议阅读有关异步任务的内容,因为如果您不熟悉它,它可能会非常棘手。这样做以后会避免很多问题。

此代码使用不同的方法代替您的代码,因为我真的不想编写所有 类 等来测试代码,但希望评论会帮助您将其集成到您的解决方案中.

UPDATE:由于以下解决方案不适用于 Laura 的方法,我怀疑 HTTP 调用未使用 await,因此不是异步的。这是 UI 被阻止的真正原因。

    private void Picker1_OnSelectedIndexChanged(object sender, EventArgs e)
    {
        // add code here to display wait icon if you want


        // replace with RestService.GetDataAsync
        Task.Delay(5000)
            .ContinueWith(t =>
        {
            // in the case there is an error making the REST call
            if (t.IsFaulted)
            {
                // handle error
                return;
            }

            // t.Result will have the REST response so replace this code with yours
            var cities = new ObservableCollection<string>(new[] {"1", "2"});

            // Since you're running a new task it is important to make sure all UI 
            // changes are ran in the main UI thread. This will make sure of that.
            Device.BeginInvokeOnMainThread(() =>
            {
                Picker2.ItemsSource = cities;
                Picker2.IsEnabled = true;
                // if you displayed wait icon make sure it is disabled here now that the function has completed

            });
        });
    }

```