问题
I'm new to Prism with Xamarin.Forms. I've implemented the ViewModel approach using the Navigation and Commanding classes. It works just fine but there's just one thing I don't understand. With the AutowireViewModel set to true the ViewModelLocator automatically fills the BindingContext for me and that is sweet. The order of things is not what I expected. First the binding for the properties on the View fire and then the OnNavigatedTo is fired. This means that my init of the properties is already finished by the time I receive the parameters on the View. I can solve this by executing the RaisePropertyChanged. This causes the following:
- I'm forced to write RaisePropertyChanged for every property on the ViewModel I want to see on the view with the new Data.
- All bindings fire two times. For fast stuff that's not a problem but some are slower.
- Data is refreshed after the View has become visible. Not disturbing but it would be nicer to show the finished View with it's data all at once.
- All properties must be able to handle null references.
Is there a way to initialize the data in the ViewModel before the binding kicks in?
回答1:
Actually Prism for Xamarin.Forms has long supported initializing your ViewModels prior to the View being pushed onto the NavigationStack. That said there is an order of operations that has to be taken into consideration. We cannot for instance perform a bunch of operations on a ViewModel and then attach it to a View.
The Order in which things are carried out are as follows:
- The View is Created (Anything in the View's ctor is executed)
- If you have specifically attached the ViewModelLocator.AutowireViewModel property this will resolve the ViewModel as part of the ctor
- If you have not specifically opted out of the ViewModelLocator's Autowire, the Navigation Service will set it for you (after the ctor has completed)
- The NavigationService will then call IAutoInitialize/IInitialize/InitializeAsync (for Prism 7.2+... INavigatingAware.OnNavigatingTo in older versions of Prism)
- The NavigationService will then push the Page onto the Navigation Stack (note that this may or may not be visible to the user as additional pages may have to be added first when deep linking)
- The NavigationService will then call OnNavigatedFrom / OnNavigatedTo (this is where people often report seeing a visible delay due to binding updates.
For an overwhelming number of scenarios if you have correctly initialized your ViewModel this process works exactly as you need. If you have some edge case where you absolutely have to ensure the ViewModel is initialized before it is set then you will need to handle this manually.
public partial class ViewA : ContentPage, IInitialize
{
private ViewAViewModel ViewModel { get; }
public ViewA(ViewAViewModel viewModel)
{
ViewModel = viewModel;
// Explicitly Opt Out of Autowiring
ViewModelLocator.SetAutowireViewModel(this, false);
InitializeComponent();
}
public void Initialize(INavigationParameters parameters)
{
ViewModel.Initialize(parameters);
BindingContext = ViewModel;
}
}
来源:https://stackoverflow.com/questions/60238660/onnavigatedto-or-initialize-too-late-for-binding