简体   繁体   中英

ViewModel Initialize method for different Views

I have a TabbedPage which shows deliveries in progress and finished deliveries. The model for both views is the same, only the service method from where we get the data is different, so I would like to reuse the ViewModel.

Would it be a good solution to reuse the ViewModel by passing some navigation data into my InitializeAsync method that would allow me to decide which service method to use to get the data for the view?

I would override OnCurrentPageChanged in TabbedPage View's code-behind and Initialize the ViewModel from there

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();
            }
        }
    }

What could be alternative solutions?

The best way is to use two different properties in your viewmodel. Then you can bind the two different views in the tabs to the associated property.

In your viewmodel:

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

Know you can add two methods to load the data for those properties:

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
}

And then in your TabbedPage-Event:

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

With this solution you can separate the data and you don't need to reload the whole data everytime you change the tabs. You can check if there is already some data in the collection, and if so... just don't reload the data. Just do it if the user wants it.

This improves the performance and the "wait-time" for the user.

Or as an alternative: Load all data at once and just filter the data for the two collection-properties. This reduces the service-calls.

You can accomplish this by using a base viewmodel and a view model for each tab that uses the base. The base then holds your commands and deliveries. you bind each tabbed page to the viewmodel for that page so you won't need to check on tab changed. When you construct each viewmodel, pass in the information needed to base to know how to query the data. For each tabbed view, if the views are the same for in progress and finished, use a partial view and put it in both tabbed pages. This gives flexibility in the long run.

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

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM