使用 web 服务来显示列表 xamarin 表单

consume a webservice to show list xamarin forms

我想在使用 web 服务的 xamarin(VS 2019) 中显示费用列表,但是当 运行 我的应用程序时,它显示一个空列表但是当我使用断点时,我发现信息是到达元素 "content"

PS:服务是运行在postman,

ListExpenses.xaml

    <ListView x:Name="listexpense" 
              ItemsSource="{Binding expenseLists}" 
              HasUnevenRows="True">

        <ListView.ItemTemplate>
            <DataTemplate>
                    <ViewCell Height="150">
                        <StackLayout HorizontalOptions="StartAndExpand" 
                                 Orientation="Horizontal">
                           <Label Text="{Binding Name}"/>
                           <Label Text="{Binding Nature}"/>
                            <Label Text="{Binding AmountHT }"/>
                            <Label Text="{Binding AmountReimbursed }"/>
                            <Label Text="{Binding AmountExceeds }"/>
                            <Label Text="{Binding ExpenseReport }"/>


                            </StackLayout>
                </ViewCell>
          </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

ListExpenses.xaml.cs

     public partial class ListExpenses : ContentPage, INotifyPropertyChanged
{
    public ListExpenses()
    {
        InitializeComponent();
        GetExpense();
    }
    public async void GetExpense()
    {  HttpClient httpClient = new HttpClient();
        httpClient.BaseAddress = new Uri("http://192.168.1.6:3000/api/adepApi/GetExpenseReports");
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        HttpResponseMessage response = await httpClient.GetAsync("http://192.168.1.6:3000/api/adepApi/GetExpenses");
        var content = await response.Content.ReadAsStringAsync();
        ResponseData EL = JsonConvert.DeserializeObject<ResponseData>(content);
        viewRapport.ItemsSource = EL.Data.expenseRLists;
    }
    class ResponseData
    {
        public ExpensRapportList Data;
    }
          private List<Expense> expenseList { get; set; }

     [JsonProperty("expenses")]
    public List<Expense> expenseLists
    {
        get { return expenseList; }
        set
        {
            if (value != expenseList)
            {
                expenseList = value;
                NotifyPropertyChanged();
            }
        }
    }            
    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Expense.cs

public class Expense{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Nature { get; set; }
    public string AmountHT { get; set; }
    public string AmountReimbursed { get; set; }
    public string AmountExceeds { get; set; }
    public string ExpenseReport { get; set; }

}

我的网络服务

[Description("Get Expenses")]
[AllowAnonymous]
[AcceptVerbs("GET", "POST")]
public System.Web.Mvc.JsonResult GetExpenses()
{
    var WorkContext = EngineContext.Current.Resolve<IWorkContext>();
    var expenseBo = EngineContext.Current.Resolve<IExpenseBo>();

    var success = true;
    var errorMessage = String.Empty;
    var successNotificationMessage = String.Empty;
    IList<ExpenseModelCustom> expenses = null;
    try
    {
        expenses=new List<ExpenseModelCustom>();
        expenses = expenseBo.GetExpenses();


    }
    catch (Exception ex)
    {
        success = false;
        errorMessage = ex.Message;
    }
    return new System.Web.Mvc.JsonResult
    {
        Data = new
        {
            expenses = expenses,
            Success = success,

        }
    };
}

Json:

 {"ContentEncoding": null,
  "ContentType": null,
  "Data": {
   "expenses": [
    {
        "userId": null,
        "Id": 4362,
        "Name": "fda",
        "Description": null,
        "Provider": null,
        "Nature": "Déjeuner région Parisienne",
        "AmountHT": 16.67,
        "AmountTTC": 20,
        "AmountReimbursed": 20,
        "Tva": "20 %.",
        "Remboursable": true,
        "Distance": null,
        "IsIk": false,
        "ExpenseReport": "Senda JAOUANI",
        "IsDeleted": false,
        "StatusSystemName": "Draft",
        "Status": "Draft_",
        "HasDocuments": true,
        "Devise": "€",
        "ReportStatus": "Draft",
        "AmountExceeds": false,
        "Date": "2020-03-26T15:24:22",
        "StartDate": null,
        "EndDate": null,
        "Departure": null,
        "ExpenseNatureId": null,
        "CurrencyId": null,
        "TvaId": null,
        "Quantity": null,
        "ExpenseReportId": null,
        "IsDeplacementComplementaire": null,
        "IsFromHome": null,
        "IsToHome": null,
        "Remboursabledistance": null,
        "DistanceHomeToWork": null,
        "IsAlleRetour": null,
        "MissionPlace": null,
        "IsInclud": null,
        "PhysicalEntityId": null,
        "CompanyEntity3Id": null,
        "ventilationTvaList": null,
        "InvitedInExpense": null,
        "ExternalInvitedInExpense": null,
        "documentIds": null,
        "Amount": null
    },
    {
        "userId": null,
        "Id": 4356,
        "Name": "Reprise Initialisation de Plafond",
        "Description": "Reprise Initialisation de plafond",
        "Provider": null,
        "Nature": "Petit déjeuner",
        "AmountHT": 250,
        "AmountTTC": 250,
        "AmountReimbursed": 250,
        "Tva": null,
        "Remboursable": true,
        "Distance": 100,
        "IsIk": false,
        "ExpenseReport": "Reprise Initialisation de Plafond",
        "IsDeleted": false,
        "StatusSystemName": "",
        "Status": "",
        "HasDocuments": false,
        "Devise": "€",
        "ReportStatus": "Approved",
        "AmountExceeds": false,
        "Date": "2019-11-28T00:00:00",
        "StartDate": null,
        "EndDate": null,
        "Departure": null,
        "ExpenseNatureId": null,
        "CurrencyId": null,
        "TvaId": null,
        "Quantity": null,
        "ExpenseReportId": null,
        "IsDeplacementComplementaire": null,
        "IsFromHome": null,
        "IsToHome": null,
        "Remboursabledistance": null,
        "DistanceHomeToWork": null,
        "IsAlleRetour": null,
        "MissionPlace": null,
        "IsInclud": null,
        "PhysicalEntityId": null,
        "CompanyEntity3Id": null,
        "ventilationTvaList": null,
        "InvitedInExpense": null,
        "ExternalInvitedInExpense": null,
        "documentIds": null,
        "Amount": null
       }
],
"Success": true }, "JsonRequestBehavior": 1,  "MaxJsonLength": null, "RecursionLimit": null}

您的网络服务 returns 一个包装器对象,其中包含一个数组。所以你需要反序列化包装器。使用 json2csharp.com 将为您生成 类

// assume the wrapper class is "RootObject"
var data = JsonConvert.DeserializeObject<RootObject>(content);

// now your List of Expenses is a property of RootObject, let's assume
// it's called "Expenses"
listexpense.ItemsSource = data.Expenses;

您还需要更新 XAML 中的绑定路径以匹配修改后的费用对象的 属性 名称