ViewModel Метод за инициализиране за различни изгледи

Имам TabbedPage, който показва доставките в ход и завършените доставки. Моделът и за двата изгледа е един и същ, само методът на обслужване, откъдето получаваме данните, е различен, така че бих искал да използвам повторно ViewModel.

Ще бъде ли добро решение да използвам повторно ViewModel, като предам някои навигационни данни в моя метод InitializeAsync, което ще ми позволи да реша кой метод на услугата да използвам, за да получа данните за изгледа?

Бих отменил OnCurrentPageChanged в задния код на TabbedPage View и бих инициализирал ViewModel от там

TabbedPageView.xaml.cs

    protected override async void OnCurrentPageChanged()
    {
        base.OnCurrentPageChanged();
        if (!(CurrentPage.BindingContext is TabbedPageViewModel tabbedPageViewModel)) return;
        if (CurrentPage == DeliveriesInProgress)
        {
            await tabbedPageViewModel.InitializeAsync("DeliveriesInProgress");
        }
        else if (CurrentPage == FinishedDeliveries)
        {
            await tabbedPageViewModel.InitializeAsync("FinishedDeliveries");
        }
    }

TabbedPageViewModel.cs

    public async Task InitializeAsync(object navigationData)
    {
        if (navigationData is string deliveryType)
        {
            if (deliveryType == "InProgress")
            {
                Deliveries = await _deliveryService.GetDeliveriesInProgress();
            }
            else if (deliveryType == "Finished")
            {
                Deliveries = await _deliveryService.GetFinishedDeliveries();
            }
        }
    }

Какви биха могли да бъдат алтернативните решения?


person Reed    schedule 24.01.2019    source източник
comment
Може да отдели service-calls от ViewModel Initialize . ViewModel просто бъдете готови за показване на данни и след получаване на данни от услугата изберете кой dataModel да бъде показан. Тогава ViewModel Initialize може да се направи преди service-calls или след него. Те нямат ефект между тях.   -  person Junior Jiang    schedule 25.01.2019


Отговори (2)


Най-добрият начин е да използвате две различни свойства във вашия изгледмодел. След това можете да свържете двата различни изгледа в разделите към свързаното свойство.

Във вашия изгледмодел:

public ObservableCollection<MyDeliveryModel> FinishedDeliveries;
public ObservableCollection<MyDeliveryModel> DeliveriesInProgress;

Знайте, че можете да добавите два метода за зареждане на данните за тези свойства:

public async Task RefreshFinishedAsync() 
{ 
    // Your logic to load the data from the service
}
public async Task RefreshInProgressAsync()
{ 
    // Your logic to load the data from the service
}

И след това във вашето TabbedPage-Event:

if (CurrentPage == DeliveriesInProgress)
{
    await tabbedPageViewModel.RefreshInProgressAsync();
}
else if (CurrentPage == FinishedDeliveries)
{
    await tabbedPageViewModel.RefreshFinishedAsync();
}

С това решение можете да разделяте данните и не е необходимо да презареждате целите данни всеки път, когато промените разделите. Можете да проверите дали вече има някакви данни в колекцията и ако е така... просто не презареждайте данните. Просто го направете, ако потребителят го иска.

Това подобрява производителността и "времето за изчакване" за потребителя.

Или като алтернатива: Заредете всички данни наведнъж и просто филтрирайте данните за двете свойства на колекцията. Това намалява сервизните обаждания.

person Joehl    schedule 24.01.2019
comment
Добър вход, благодаря. Един въпрос, ако тръгна по този начин и разделя доставките на DeliveriesInProgress и FinishedDelivery, няма ли да трябва да дублирам ICommands, които преди работеха само върху Deliveries? Например, имам ICommand за мързеливо зареждане, наречено LoadMore и се извиква, когато превъртането на ListView достигне дъното, ще трябва да направя LoadMoreInProgress и LoadMoreDeliveri, които свързват колекциите и манипулират частни полета за прескачане на елементите. - person Reed; 24.01.2019
comment
Но това трябва да е правилният път. Можете да разделите методите за зареждане за двата свойства. С това можете да намалите натоварването на услугата и да подобрите производителността. Представете си, че потребител просто иска да види InProgress доставките: Вие просто трябва да заредите това и никакви други данни... - person Joehl; 25.01.2019

Можете да постигнете това, като използвате основен модел на изглед и модел на изглед за всеки раздел, който използва основата. След това базата съхранява вашите команди и доставки. обвързвате всяка страница с раздели към модела на изглед за тази страница, така че няма да е необходимо да проверявате променения раздел. Когато конструирате всеки модел на изглед, предайте информацията, необходима на базата, за да знаете как да направите заявка за данните. За всеки изглед с раздели, ако изгледите са еднакви за в ход и завършен, използвайте частичен изглед и го поставете в двете страници с раздели. Това дава гъвкавост в дългосрочен план.

public class InProgressDeliveriesViewModel: BaseDeliveryViewModel{

     public InProgressDeliveriesViewModel():base(filterParams){}
}

public class FinishedDeliveriesViewModel: BaseDeliveryViewModel{

     public FinishedDeliveriesViewModel():base(filterParams){}
}

public class BaseDeliveryViewModel{

   private FilterObjectOfSomeSort _filterParams;

   public BaseDeliveryViewModel(filterParams whatever){
      //use these params to filter for api calls, data.  If you are calling the same 
      //endpoint pass up the filter
      _filterParams = whatever;
    }

   public ObservableCollection<MyDeliveryModel> Deliveries {get;set;}

   public async Task LoadDeliveries(){
       //use the filter params to load correct data
       var deliveries = await apiClient.GetDeliveries(filterParams); //however you 
       //are gathering data
   }

.... All of your other commands

}
person rleffler    schedule 24.01.2019