I have an Xamarin iOS app where I am using MVVMCross v3.2.1 to control the navigation between the view controllers / view models. I have used the ShowViewModel<TViewModel>(); method to navigation between view models and have a special case where I want to navigate back one step on the navigation stack.
I can do this my using the MvxClosePresentationHint as in ChangePresentation(new MvxClosePresentationHint(this)); but when it navigates back to the previous view I need the data to refresh.
Are there any MVVMCross view model lifecycle methods I can us to detect the back navigation or should I implement a MvxMessage?
As Cheesebaron suggested I am refreshing the data from the ViewWillAppear on the previous ViewController which seems to have resolved the issue.
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
Refresh();
}
Related
I have a question about the Navigation Service introduced in MvvmCross 5.
In Version 4:
I navigate with ShowViewModel<ViewModel>() to a Fragment
then Init method of the ViewModel is called
after that the OnCreateView method of the Fragment is called
There I can manipulate the view based on ViewModel data (for example add specific elements to the view).
In Version 5:
I navigate with await NavigationService.Navigate<ViewModel>()
the OnCreateView of the Fragment is called first
after that the Initialize method from the ViewModel.
This ends in no ViewModel data while creating the Fragment view.
Is this a bug or a feature of async navigation?
If that is so wanted, is there a better way to manipulate the Fragment view based on ViewModel data?
Is this a bug or a feature of async navigation?
It was by design, but has since (v5.0.4) been revised, see below of flow changes.
If that is so wanted, is there a better way to manipulate the Fragment
view based on ViewModel data?
Using v5.0.4+ should yield the desired behaviour you are expecting. Where the navigation service is awaited on Initialize() of your ViewModel to complete before starting the views life cycle events.
MvvmCross v5.0.0 - v5.0.3
The behaviour you are seeing was present in MvvmCross 5.0.0-5.0.3. The flow was as follows:
ViewModel.Ctor
(Selected Navigate calls) Init(parameter) (deprecated, uses reflection, rather use type safe Initialize)
(Selected Navigate calls) ViewModel.ReloadState(savedState)
(Selected Navigate calls) ViewModel.Start()
BeforeNavigate (NavigationService Event)
*ViewDispatcher.ShowViewModel() (Triggers view life cycles)
*ViewModel.Initialize()
AfterNavigate (NavigationService Event)
BeforeClose (NavigationService Event)
ViewDispatcher.ChangePresentation()
AfterClose (NavigationService Event)
MvvmCross v5.0.4+
v5.0.4+ has improved the flow and changed the navigation order:
ViewModel.Ctor
BeforeNavigate (NavigationService Event)
*ViewModel.Initialize()
Init(parameter) (deprecated, uses reflection, rather use type safe Initialize)
ViewModel.ReloadState(savedState)
ViewModel.Start()
*ViewDispatcher.ShowViewModel() (Triggers view life cycles)
AfterNavigate (NavigationService Event)
BeforeClose (NavigationService Event)
ViewDispatcher.ChangePresentation()
AfterClose (NavigationService Event)
Additional Information
You can check out the GitHub issue(#1968) logged around the navigation order. Additionally, you can check out the pull request(#1971) which updated the Initialize order for version 5.0.4.
I am using WPF Prism 6 with autofac and having issues navigating between views. What I have is a view that I only want to keep alive till I leave it, and the next time I navigate to it, I want to create a new version of this view.
On load, I regist an IModule that has the following code
_regionManager.RegisterViewWithRegion(RegionNames.MainRegion,
typeof(DxfDisplay.Views.DxfDisplay));
This registers my view and the system works on initial load, I implement the INavigationAware and IRegionMemberLifetime interfaces on the view model and have public bool KeepAlive => false; implementing the IRegionMemberLifetime so that my view is disposed when I am done.
When I navigate away from this view everything is fine, but when I attempt to navigate to navigate to the view using
_regionManager.RequestNavigate(RegionNames.MainRegion,
new Uri("DxfDisplay", UriKind.Relative), parameters);
The view is not opened and a view model constructor is not called. To make the navigation work correctly, I need to register with view with the region again. Or if I change the KeepAlive to true I can navigate back to the original view, but I cannot generate a new view if INavigationAware.IsNavigationTarget returns false.
My question is how do I register the view with the region manager in such a way that when I call _regionManager.RequestNavigate, it will create a new instance of the view and display it. I feel like I am missing something simple and just overlooking it.
_builder.RegisterTypeForNavigation<DxfDisplay.Views.DxfDisplay>();
In Prism 7, this is now called RegisterForNavigation<T>() and exists on the IContainerRegistry interface.
For example, in your module:
public class MyModule : IModule
{
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<MyView>();
}
}
I using MvvmCross to build my UWP application. I have views with their own view models.
When I start the app then first time from Setting view navigate to Passcode view using ShowViewModel<PasscodeViewModel>(). Then it call view model and view constructor to build and initialize view. When user come back to setting view and again navigate to passcode view using same method like ShowViewModel<PasscodeViewModel>() then this time view and view model constructor not get called. Since unable to reinitialize passcode view. So it display previous instance of passcode view.
Following solution I have tried
I tried removing the backstack in the navigations but then also not constructor get call.
Also implement loaded event but this solution also not working for me.
Also implemented Void Init() in view model but this method also not get call.
I just want when I navigate to PasscodeView then each time it call constructor of PasscodeView and PasscodeViewModel.
So my question is how to force to re-initialize page and viewmodel each time while navigation??
Please help to resolve this issue.
I needed to use navigation cache mode on required.
I resolved it for me with the not very clean solution to call init again.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (this.ViewModel!= null && e.NavigationMode != NavigationMode.Back)
{
var reqData = (string)e.Parameter;
var converter = Mvx.Resolve<IMvxNavigationSerializer>();
var req = converter.Serializer.DeserializeObject<MvxViewModelRequest>(reqData);
this.Vm.CallBundleMethods("Init", new MvxBundle(req.ParameterValues));
}
base.OnNavigatedTo(e);
}
This code avoids to call init again on back navigation.
I just set Universal Windows Phone apps page navigation cache mode "Disabled". I think its default value is "Required".
public PasscodeView()
{
InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Disabled;
}
The above code work for me.
I'm working on an application and everything works fine but when I go back to the previous page the View Model is called so it will not maintain the old data.
I use this line to call My View Model in XAML.
prismmvvm:ViewModelLocator.AutoWireViewModel="true"
So my question is:
How do I disable the call of the View Model when I go back?
You're referring caching here.
In the constructor of your ViewModel , set your NavigationCacheMode
this.NavigationCacheMode = NavigationCacheMode.Required;
and in OnNavigatedTo event handler , check your navigationMode and delete if you're doing something more than default initializing.
This is more complex than it sounds. I'm implementing MVVM pattern, which states a ViewModel cannot have a reference to it's View. That being said, I'm implementing Page navigation so that changes in views are done by using NavigationService in the View's code behind (let's say by pressing the "Next" button).
At some point in the program, we need to change Page using a voice command instead of a button (using speech recognition), and that logic is handled in the ViewModel (which doesn't have a reference to NavigationService).
So, without keeping a reference to thew View inside the ViewModel, how can I change page using NavigationService?
You could publish a "next page requested" message from within your view model using something like an event aggregator. Your view then subscribes to the message and handles it by using NavigationService to change the page. If you are using an MVVM framework most of them provide a way to publish / subscribe to messages out of the box.
In your Core (nonUI) project that containts your view models. Create a INavigationService interface:
public interface INavigation
{
void Navigate(IViewModel viewmodel);
void GoBack();
}
Then in your UI project, provide the implementation for that interface. You can get fancy with how you provide that implementation to the view model.
In the simple form you'd want to do something like:
public class MyViewModel
{
public MyViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
}
}
When the app starts up give the view model the implementation. At that point all your navigation can live in the view model. If you need to navigate from a view, execute a command on the view model and have it navigate.
Take a look at how MvvmLight does it:
INavigationService,
NavigationService