Xamarin формы - не удается получить объект из API REST на страницу xaml - PullRequest
1 голос
/ 02 ноября 2019

Я занимаюсь разработкой приложения Xamarin.Forms в VS 2019. Мой REST API размещен на GoDaddy. Когда я вызываю API, я возвращаю мой преобразованный json объект в моей модели представления. Но объект не указан на моей странице xaml. Смотрите этот код:

public class NewOrderViewModel : BaseViewModel
{

    public NewOrderDetails NewOrderDetails { get; set; }
    public ICommand OkCommand { get; private set;}
    public ICommand CancelCommand { get; private set; }
    readonly IPageService _pageService;

    public NewOrderViewModel(IPageService pageService, int custId)
    {
        _pageService = pageService;
        OkCommand = new Command(NewOrder);
        CancelCommand = new Command(CancelOrder);
        NewOrderDetails = new NewOrderDetails();

        LoadNewOrderDetails(custId);
     }
    private async void LoadNewOrderDetails(int custId)
    {
        using (var client = new HttpClient(new System.Net.Http.HttpClientHandler()))
        {

            var response = await client.GetStringAsync("http://api.lates.com.au/api/Customers/" + custId.ToString());
            var customer = JsonConvert.DeserializeObject<Customer>(response);

            await _pageService.DisplayAlert("Value", customer.CustomerName, "OK"); //This confirms the correct customer is returned.
             NewOrderDetails.CustomerName = customer.CustomerName;
            foreach (var cd in customer.CustomerDepartments)
            {
                NewOrderDetails.CustomerDepartments.Add(cd);
            }
            NewOrderDetails.OrderDate = DateTime.Today;
            NewOrderDetails.DeliveryDate = DateTime.Today;
            NewOrderDetails.CustomerId = custId;
         }
    }

    private void NewOrder()
    {
        _pageService.PopAsync();
        _pageService.PushModalAsync(new CustomerOrder());
    }

    private void CancelOrder()
    {
        _pageService.PopAsync();
    }
}


public partial class NewOrder : ContentPage
{
    public NewOrder()
    {
        InitializeComponent();

        imgAddIcon.Source = FileImageSource.FromFile("AddDocument64By64.png");

    }

    protected override void OnAppearing()
    {
        BindingContext = new NewOrderViewModel(new PageService(), 1);
//If i put a break point here the NewOrderDetails property of NewOrderViewModel is null - WHY???
    }
}

Кажется, что-то связано с асинхронной синхронизацией. Дайте мне знать, если вам нужна дополнительная информация.

Малкольм

Ответы [ 2 ]

0 голосов
/ 04 ноября 2019

Если я поставлю здесь точку останова, свойство NewOrderDetails объекта NewOrderViewModel будет нулевым - ПОЧЕМУ ???

В то время, когда достигнута точка останова, данные в NewOrderDetails не имеютбыть установленным, потому что httpRequest все еще запрашивает, и вам нужно дождаться окончания запроса, чтобы получить данные от Api.

. Чтобы решить вашу проблему, вы должны реализовать INotifyPropertyChanged в NewOrderDetails и NewOrderViewModel для уведомления об обновлении значения View после получения данных от Api. Я дам вам несколько фрагментов кода:

В NewOrderDetails:

public class NewOrderDetails : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    public NewOrderDetails()
    {

    }
    public string CustomerName
    {
        set
        {
            if (customerName != value)
            {
                customerName = value;

                OnPropertyChanged("CustomerName");
            }
        }
        get
        {
            return customerName;
        }
    }
    string customerName { get; set; }
}

В NewOrderViewModel:

public class NewOrderViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    public NewOrderDetails NewOrderDetaila
    {
        set
        {
            if (newOrderDetails != value)
            {
                newOrderDetails = value;

                OnPropertyChanged("NewOrderDetaila");
            }
        }
        get
        {
            return newOrderDetails;
        }
    }
    NewOrderDetails newOrderDetails { get; set; }


    public NewOrderViewModel( int custId)
    {

        NewOrderDetaila = new NewOrderDetails();

        LoadNewOrderDetails(custId);
    }
    private async void LoadNewOrderDetails(int custId)
    {
        //...
        NewOrderDetaila.CustomerName = "133"; 
        //...
    }
}

И в Xaml привязка:

<Label Text="{Binding NewOrderDetaila.CustomerName}" 
   HorizontalOptions="Center"
   VerticalOptions="CenterAndExpand" />

Попробуйте и дайте мне знать, если это работает для вас.

0 голосов
/ 02 ноября 2019

Одна проблема в вашем коде заключается в следующем:

        using (var client = new HttpClient(new System.Net.Http.HttpClientHandler()))
    {

        var response = await client.GetStringAsync("http://api.lates.com.au/api/Customers/" + custId.ToString());
        var customer = JsonConvert.DeserializeObject<Customer>(response);

        await _pageService.DisplayAlert("Value", customer.CustomerName, "OK"); //This confirms the correct customer is returned.
         NewOrderDetails.CustomerName = customer.CustomerName;
        foreach (var cd in customer.CustomerDepartments)
        {
            NewOrderDetails.CustomerDepartments.Add(cd);
        }
        NewOrderDetails.OrderDate = DateTime.Today;
        NewOrderDetails.DeliveryDate = DateTime.Today;
        NewOrderDetails.CustomerId = custId;
     }

HttpClient должен быть определен как статический класс и повторно использоваться в течение срока службы вашего приложения. Утилизация и воссоздание HttpClient приводит к ошибкам сокета. Ваш код вызывает несколько запросов. Я предлагаю также переместить этот метод в Task, который возвращает объект.

Пример метода:

    internal class SendData
{

    private static HttpClient client = new HttpClient();

    internal static async Task<string> MakeServerRequest(string url, string content)
    {
        try
        {
            var request = new StringContent(content, Encoding.UTF8, "application/json");
            var result = await client.PostAsync(url, request);
            var response = await result.Content.ReadAsStringAsync();
            return response;
        }
        catch (Exception ex)
        {
            YOUR ADDITIONAL LOGIC HERE
            return null;
        }
    }
}

Это вернет строку JSON, которую вы можете сериализовать в объект, и делать все, что требуется вашему приложению.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...