我对C#还是很陌生,所以这很容易。我正忙于创建xamarin表单应用程序,并且需要UI上下一页的数据。它的标签页,所有3个页面都需要基类返回的信息。 我遇到的问题是我需要致电google api服务获取公司信息。因此,我创建了一个异步调用。因此现在代码由于此而返回。由于选项卡式页面,我需要将数据绑定到屏幕上,现在我需要等待数据,因此基本上需要同步。
我已经尽力在该主题上找到了一切。也许我这样做的方式是错误的,但希望我的代码能证明这一点。
这是标签页:
public BusinessTabbedPage(string PlaceId)
{
Children.Add(new BusinessSpecialsPage(PlaceId));
InitializeComponent();
}
这将是应用程序中调用viewmodel的页面之一
public BusinessSpecialsPage(string PlaceId)
{
BindingContext = new BusinessSpecialsPageViewModel(PlaceId);
InitializeComponent();
}
由于3个页面需要相同的数据,因此我创建了一个基类。这将获取数据并将所有内容传递回UI。
public BusinessBaseViewModel(string placeId)
{
Task<List<CompanyProfileModel>> task = GBDFromGoogle(placeId);
task.Wait();
}
public async Task<List<CompanyProfileModel>> GBDFromGoogle(string PlaceId)
{
var info = await ApiGoogle.GetGoogleCompanySelectedDetails(PlaceId);
var Companyresult = info.result;
CompanyProfileModel CompList = new CompanyProfileModel
{
ContactDetails = Companyresult.formatted_phone_number,
Name = Companyresult.name,
Website = Companyresult.website,
};
ComPF.Add(CompList);
return ComPF;
}
这是我认为正在添加新任务然后进程死锁的api调用?
public static async Task<GoogleSelectedPlaceDetails> GGCSD(string place_id)
{
GoogleSelectedPlaceDetails results = null;
var client = new HttpClient();
var passcall = "https://maps.googleapis.com/maps/api/place/details/json?placeid=" + place_id + "&key=" + Constants.GoogleApiKey;
var json = await client.GetStringAsync(passcall);
//results = await Task.Run(() => JsonConvert.DeserializeObject<GoogleSelectedPlaceDetails>(json)).ConfigureAwait(false);
results = JsonConvert.DeserializeObject<GoogleSelectedPlaceDetails>(json);
return results;
}
我需要避免死锁的过程。它需要等待任务完成,这样我才能将数据返回到屏幕。
答案 0 :(得分:1)
Task.Wait
将阻塞当前线程,因此您永远不要在Xamarin应用程序中使用它,甚至不要在构造函数中使用它,否则,您的应用程序将冻结,直到您收到一些数据,如果服务关闭或启动时可能永远不会发生用户失去连接。
您可以在Appearing
视图的ContentPage
事件上初始化数据,而不用在ViewModel的构造函数中调用数据。
为此,您可以创建一个自定义behaviour甚至更好的自定义标签,可以使用以下已为您完成此操作的库:
使用NuGet:Install-Package Behaviors.Forms -Version 1.4.0
一旦安装了库,就可以使用EventHandlerBehavior
将事件关联到ViewModel命令,例如:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:behaviors="clr-namespace:Behaviors;assembly=Behaviors"
xmlns:viewModels="clr-namespace:YourApp.ViewModels"
Title="Business Page"
x:Class="YourApp.Views.BusinessPage">
<ContentPage.BindingContext>
<viewModels:BusinessViewModel />
</ContentPage.BindingContext>
<ContentPage.Behaviors>
<behaviors:EventHandlerBehavior EventName="Appearing">
<behaviors:InvokeCommandAction Command="{Binding AppearingCommand}" />
</behaviors:EventHandlerBehavior>
</ContentPage.Behaviors>
[...]
ViewModel:
public BusinessBaseViewModel(string placeId)
{
AppearingCommand = new Command(Appearing);
PlaceId = placeId;
}
public ICommand AppearingCommand { get; private set; }
public string PlaceId { get; private set; }
private ObservableCollection<CompanyProfileModel> _googleGbd;
public ObservableCollection GoogleGbd
{
get { _googleGbd?? (_googleGbd = new ObservableCollection<CompanyProfileModel>()); };
set
{
if (_googleGdb != value)
{
_googleGdb = value;
NotifyPropertyChanged();
}
}
}
private async void Appearing()
{
var companyResult = await ApiGoogle.GetGoogleCompanySelectedDetails(PlaceId);
CompanyProfileModel companyProfile = new CompanyProfileModel
{
ContactDetails = companyResult.formatted_phone_number,
Name = companyResult.name,
Website = companyResult.website,
};
GoogleGbd.Add(companyProfile);
}
如果只希望在视图第一次出现时加载数据,则可以添加一个bool标志来知道您已经加载了数据。