我正在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)
{ ... }
答案 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
});
});
}
```