【问题标题】:consume a webservice to show list xamarin forms使用 Web 服务来显示列表 xamarin 表单
【发布时间】:2020-04-18 12:42:56
【问题描述】:

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

PS:服务在邮递员中运行,

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}

【问题讨论】:

  • ListExpenses 需要实现INotifyPropertyChanged 然后在expenseLists 的设置器中必须通知属性已更改,以便绑定可以实际检测到它。应该有大量关于如何在线执行此操作的指南
  • @Knoop 是的,我已经成功了!
  • 不错!祝你的项目好运!
  • 我还没有发现问题:/
  • 您的 json 只是一项费用,还是一份费用清单?您将其反序列化为单个费用对象。

标签: c# rest web-services xaml xamarin.forms


【解决方案1】:

您的 web 服务返回一个包装器对象,其中包含一个数组。所以你需要反序列化包装器。使用 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 中的绑定路径以匹配修改后的 Expense 对象的属性名称

【讨论】:

  • 这是我遇到的错误:Newtonsoft.Json.JsonSerializationException:'无法将当前 JSON 对象(例如 {"name":"value"}) 反序列化为类型'System.Collections.Generic。 List`1[Expense]' 因为该类型需要一个 JSON 数组(例如 [1,2,3])才能正确反序列化。要修复此错误,请将 JSON 更改为 JSON 数组(例如 [1,2,3])或更改反序列化类型,使其成为普通的 .NET 类型(例如,不是像整数这样的原始类型,而不是像这样的集合类型一个数组或 List)...
  • 这告诉我你的 JSON 不是一个数组。我之前要求您发布您的 json 样本,但您没有。
  • 您发布的 JSON 与您客户端中的 Expense 类无关。请使用 json2csharp.com 生成正确的类
  • 其实在web服务中我有很多属性,但是我只想展示一些,(不知道有没有回复你的评论)
  • 您的 json 是一个包装器,其中包含一系列费用。您的类中的所有属性名称都与 JSON 属性名称不匹配。您不能简单地将其反序列化为数组。按照我的建议使用 json2csharp.com。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-05
  • 2022-10-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多