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.
Related
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();
}
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 have problem how to implement sub-page navigation in UWP. The page is in RootFrame, which I can use on navigation. But i want to use something like this:
<Page>
<Grid>
<Frame x:Name="MyFrame"/>
</Grid>
</Page>
What I want is, use Navigate method of control MyFrame in ViewModel. I can call the method from code-behind, but I'm developing my app using MVVM. I'm not sure, if Template10 can work with sub-frames.
I appreciate any advice.
EDIT:
More details:
I have pivot control which is in page. the pivot has 2 tabs (pivotitems). The content of the pivotitem must be navigable. What I mean: I pivotitem 1, I need to have one Frame and use it for navigation in the pivotitem. My problem is, how to use or how to call the frame in pivotitem from ViewModel, especially I need to call Navigate method. Now I'm using Template10's navigation service and it's working with rootframe. I don't know, how to use it for other let's say sub-frames.
You can always do this.
var nav = Bootstrapper.NavigationServiceFactory(BackButton.Attach, ExistingContent.Exclude, this.Frame);
This will give you a navigation service for the frame in your page. You can then use session state, if you like.
Bootstapper.SessionState["MyNav"] = nav;
From here your view-model can access the service and navigate. You can repeat this for as many frames as you have. And you can then handle navigation in your view-model without consideration of "where" the frame is, just that your logic requires it to nav.
Does this make sense?
I don't know how you are going to trigger the navigation change so I'll assume it will start from a button click. I am also assuming the button's Command property is already bound to an ICommand in the viewmodel (the same concepts can be applied to different kinds of views).
All we have to do now is to make the ICommand implementation call our custom NavigationService to perform the content switch. This NavigationService class will be nothing but a simple proxy to the window global frame. Its main navigation method can be as simples as:
public void Switch()
{
var rootFrame = Window.Current.Content as Frame;
if ((rootFrame.Content as ParentPage) != null)
{
rootFrame.Navigate(typeof(ChildPage));
}
}
So you have tagged this with Template10 but it seems to be a more general question for UWP as a whole. I wonder if you have considered all of the inherent complexities with this approach - specifically related to suspension and resume. For each frame you have, you would need to save and restore navigation state, which isn't straight-forward when you have nested frames. Have you also considered how global navigation would work?
Template 10 does support the concept of multiple NavigationServices and, therefore, multiple frames, but only from the perspective of you can create them. Template10 does not inherently understand how such frames may be related to each other, so cannot perform automatic back propagation where you have something like:
FrameA[Main->Page1->Page1:Pivot1.FrameB[View1->View2->View3]]
Here we have two frames - FrameA and FrameB. FrameA has navigated from
Main to Page1. Page1 has a Pivot that hosts FrameB in PivotItem1 and
FrameB has navigated from View1 to View 2 and from View2 to View 3.
Global navigation (i.e. the shell back, etc.) would be automatically wired to FrameA, so you would need to intercept that action, and then handle you own navigation activity for FrameB.
Take a look at the BackButtonBehavior to see how it is possible to intercept the global back and then put in place your own action.
I don't know if you can do something like that..
One possible workaround is to use a Messenger that sends a message from your viewmodel to the view's code behind.. I'm not a fan of this solution though, because as I said before you have to use the page's code behind..
In the MvvmCross N=26 tutorial, dynamic fragments are loaded into a frame via button click event in the View (code snippet below). However, I'm trying to figure out how handle the click event in the ViewModel and not in the View. After the button is clicked, how do I know the button was clicked and in the View, load the correct fragment in the frame?
For instance, I may have 10 fragments and one frame in the FirstView xml. I want to be able to load any of those 10 fragments in that frame based on a property of a object referenced in the FirstViewModel. Can I check that property in the View and load the fragment that I want from the 10 fragments available? (i.e. remove the but1.Click event in the View and still run the transaction based on the value of the object in the ViewModel)
but1.Click += (sender, args) =>
{
var dNew = new DubFrag()
{
ViewModel = ((SecondViewModel) ViewModel).Sub
};
var trans3 = SupportFragmentManager.BeginTransaction();
trans3.Replace(Resource.Id.subframe1, dNew);
trans3.AddToBackStack(null);
trans3.Commit();
};
The approach you suggest of mapping a vm property to which fragment to show should work, yes.
To use this, just subscribe to property changed in your view code (there are some weak reference helper classes and extension methods to assist with this)
Alternatively, this blog post - http://enginecore.blogspot.ca/2013/06/more-dynamic-android-fragments-with.html?m=1 - introduces a mini framework that allows navigating by fragments.
A similar approach is used in the Shakespeare sample in the mvvmcross-tutorials fragments sample.
It should be possible to adapt that code to your needs
I am building a Windows 8 app (C#/XAML) and using the Frame.Navigate() property to move between pages. Each page has an AppBar icon that will refresh that data on a page, and set the DataContext property. This works, and the UI updates accordingly after the button is pressed.
The problem I'm seeing shows up when I navigate to a different page, then click the back arrow to return to the previous page.
When the OnNavigatedTo(NavigationEventArgs e) method runs (after clicking the back arrow), the e.Parameter value is and old value (before I clicked the refresh button, and the DataContext was updated).
I don't know how to update the parameter value any other way than using Frame.Navigate(typeof(PageTypeName), paramValue);, but I don't want to initiate a navigation action.
My question is two fold.
How can I persist DataContext changes so that when I return to pages, the value I've set is exposed via e.Parameter in the OnNavigatedTo(NavigationEventArgs e) method.
Is there some kind of reference metrial that explains the Navigation lifecycle in Win8 Apps?
... or should I be doing this a different way?
I found the solution.
NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Required;
This tells the frame that it should always cache the old instance of my page, and not create a new one when i navigate back to it.
This way my new DataContext value is not overwritten when I return to the page.