C# 任务异步调用不返回将创建死锁

C# 任务异步调用不返回将创建死锁,c#,xamarin,C#,Xamarin,我对c#很陌生,所以这可能很容易。我正忙着创建一个xamarin表单应用程序,需要UI上下一页的数据。这是一个tabbeb页面,所有3个都需要基类返回的信息。 我遇到的问题是,我需要调用GoogleAPI服务获取公司信息。因此,我创建了一个异步调用。因此,现在代码将返回。由于标签页,我需要数据绑定到屏幕,现在我需要等待数据,所以基本上需要同步 关于这个话题,我已经尝试了我能找到的一切。也许我这样做的方式是错误的,但希望我的代码能证明这一点 这是选项卡式页面: public Busines

我对c#很陌生,所以这可能很容易。我正忙着创建一个xamarin表单应用程序,需要UI上下一页的数据。这是一个tabbeb页面,所有3个都需要基类返回的信息。 我遇到的问题是,我需要调用GoogleAPI服务获取公司信息。因此,我创建了一个异步调用。因此,现在代码将返回。由于标签页,我需要数据绑定到屏幕,现在我需要等待数据,所以基本上需要同步

关于这个话题,我已经尝试了我能找到的一切。也许我这样做的方式是错误的,但希望我的代码能证明这一点

这是选项卡式页面:

    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标志,以知道您已经加载了数据。

您不应该在构造函数中调用异步代码,而应该在一个可以正确等待的初始化方法中这样做。谢谢,但是我接下来如何调用异步方法呢。请提供一个例子,请参阅和。