C# 任务异步调用不返回将创建死锁
我对c#很陌生,所以这可能很容易。我正忙着创建一个xamarin表单应用程序,需要UI上下一页的数据。这是一个tabbeb页面,所有3个都需要基类返回的信息。 我遇到的问题是,我需要调用GoogleAPI服务获取公司信息。因此,我创建了一个异步调用。因此,现在代码将返回。由于标签页,我需要数据绑定到屏幕,现在我需要等待数据,所以基本上需要同步 关于这个话题,我已经尝试了我能找到的一切。也许我这样做的方式是错误的,但希望我的代码能证明这一点 这是选项卡式页面:C# 任务异步调用不返回将创建死锁,c#,xamarin,C#,Xamarin,我对c#很陌生,所以这可能很容易。我正忙着创建一个xamarin表单应用程序,需要UI上下一页的数据。这是一个tabbeb页面,所有3个都需要基类返回的信息。 我遇到的问题是,我需要调用GoogleAPI服务获取公司信息。因此,我创建了一个异步调用。因此,现在代码将返回。由于标签页,我需要数据绑定到屏幕,现在我需要等待数据,所以基本上需要同步 关于这个话题,我已经尝试了我能找到的一切。也许我这样做的方式是错误的,但希望我的代码能证明这一点 这是选项卡式页面: public Busines
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;
}
公共BusinessBaseViewModel(字符串placeId)
{
Task Task=GBDFromGoogle(placeId);
task.Wait();
}
公共异步任务GBDFromGoogle(字符串PlaceId)
{
var info=wait apigool.GetGoogleCompanySelectedDetails(PlaceId);
var Companyresult=信息结果;
CompanyProfileModel CompList=新的CompanyProfileModel
{
ContactDetails=Companyresult.formatted\u电话号码,
Name=Companyresult.Name,
网站=Companyresult.Website,
};
组件添加(组件列表);
返回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;
}
公共静态异步任务GGCSD(字符串位置\u id)
{
GoogleSelectedPlaceDetails结果=null;
var client=新的HttpClient();
var passcall=”https://maps.googleapis.com/maps/api/place/details/json?placeid=“+place_id+”&key=“+Constants.GoogleApiKey;
var json=await client.GetStringAsync(passcall);
//结果=等待任务。运行(()=>JsonConvert.DeserializeObject(json))。配置等待(false);
结果=JsonConvert.DeserializeObject(json);
返回结果;
}
我需要这个过程不要陷入僵局。它需要等待任务完成,这样我才能将数据返回到屏幕。
任务。等待将阻止当前线程,因此您永远不要在Xamarin应用程序中使用它,更不要在构造函数中使用它,否则,您的应用程序将冻结,直到您收到一些数据,如果服务关闭或用户失去连接,这些数据可能永远不会发生
您可以在ContentPage
视图的出现事件中初始化数据,而不是调用ViewModel构造函数中的数据
要做到这一点,您可以创建一个自定义的或更好的库,您可以使用以下库,该库已经为您完成了这项工作:
使用NuGet:安装包行为.Forms-版本1.4.0
安装库后,可以使用eventhandlerbhavior
将事件关联到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);
}
公共BusinessBaseViewModel(字符串placeId)
{
AppearingCommand=新命令(出现);
PlaceId=PlaceId;
}
公共ICommand AppearingCommand{get;private set;}
公共字符串PlaceId{get;private set;}
私人可观测收集(googleGbd);;
公众可观察收集谷歌地图
{
获取{{u googleGbd??({u googleGbd=newobserveCollection());};
设置
{
如果(_googleGdb!=值)
{
_谷歌GDB=价值;
NotifyPropertyChanged();
}
}
}
私有异步void出现()
{
var companyResult=等待apigool.GetGoogleCompanySelectedDetails(PlaceId);
CompanyProfileModel companyProfile=新的CompanyProfileModel
{
ContactDetails=companyResult.formatted\u电话号码,
Name=companyResult.Name,
网站=companyResult.Website,
};
GoogleGbd.Add(公司档案);
}
如果您只希望在视图第一次出现时加载数据,那么您可以添加一个bool标志,以知道您已经加载了数据。您不应该在构造函数中调用异步代码,而应该在一个可以正确等待的初始化方法中这样做。谢谢,但是我接下来如何调用异步方法呢。请提供一个例子,请参阅和。