Xamarin表单-在选择器选择中使用异步SelectedIndexChanged

时间:2018-09-26 15:20:27

标签: .net visual-studio xamarin xamarin.forms eventhandler

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

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

这会导致性能不佳,并且似乎在执行OnSelectedCountry时应用程序卡住了,因为直到onSelectedCountry结束,picker1的国家/地区列表才会关闭。 选择国家/地区后,如何关闭Picker1的列表项?或在其顶部显示“正在加载”图像。

我已经尝试过this thread的解决方案,但没有用。

代码片段(为简单起见,省略了变量模型):

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类中执行,例如:

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

2 个答案:

答案 0 :(得分:0)

您应该在其他任务中运行它,以免冻结。

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

答案 1 :(得分:0)

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

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

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

    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

            });
        });
    }

```