I have a view where I'm letting a user edit a EntryElement. I register the click event fine through the delegate of the "Done" button however, I can't get it to dismiss the current view to go to the previous view though. Here's what I'm trying right now:
AppDelegate.navigation.PresentedViewController.DismissViewController(true, null);
I've also tried:
AppDelegate.navigation.PresentedViewController.RemoveFromParentViewController();
navigation is just a UINavigationController
EDIT:
I am using Monotouch.Dialog to build out all of the views. This view is created via a method. I want it to go back to the previous view once they click the done button. Here's the contents of the method:
public static void EditClientTypeView (string typeName, string typeId)
{
DialogViewController editClientTypeVC;
UIBarButtonItem doneButton = new UIBarButtonItem (UIBarButtonSystemItem.Done);
EntryElement element = new EntryElement("Type Name", "Name of client type", typeName, false);
var root = new RootElement ("Edit Type") {
new Section () {
element
}
};
editClientTypeVC = new DialogViewController (root, true);
editClientTypeVC.NavigationItem.RightBarButtonItem = doneButton;
doneButton.Clicked += (sender, e) => {
// Need to save the edited client type to the database
Console.WriteLine("Done button clicked signifying the user is finished editing");
AppDelegate.navigation.PresentedViewController.RemoveFromParentViewController();
//AppDelegate.navigation.DismissViewController(true, null);
};
AppDelegate.navigation.PushViewController(editClientTypeVC, true);
}
Any help is appreciated!
Since you are PUSHING a view controller onto the Navigation Stack, you dismiss it by POPPING it off the stack. UINavigationController has three POP methods
PopToRootViewController - goes all the way back to the root view of your navigation controller
PopToViewController - pops back to a specific view controller
PopViewController - pops back to the "previous" view controller
Related
We are using MvvmCross 4.4.0 on the our iOS project and I faced the following problem:
I need to implement "Item" page with reference to the other
"Item" page;
I need an instant back navigation from any "Item" page to the previous controller ("Catalogue" controller).
Diagram:
Catalogue --ConcreteItem--> Item1 --MoreItems--> Item2 --MoreItems-->
Item3 --BackNavButton--> Catalogue.
I am doing the following thing in the Custom ViewPresenter:
var topViewController = ParentRootViewController.TopViewController;
ParentRootViewController.PushViewController(currentViewController, needAnimation);
if (topViewController.GetType() == currentView.GetType()
&& /*Logic to determine if its correct view types*/)
{
topViewController.RemoveFromParentViewController();
topViewController.Dispose();
}
And actually it works until I didn't return to the "Catalogue" page.
The problem is that I need to click back button so many times I had clicked "More" button on "Item" page. Also if we use custom back button with such code in both "Catalogue" and "Item" pages:
if (NavigationController?.NavigationBar?.BackItem != null)
{
var backbutton = new UIBarButtonItem(" ",
UIBarButtonItemStyle.Plain,
(sender, e) => { NavigationController?.PopViewController(true); })
{
Image = UIImage.FromBundle("BackButtonImage")
};
NavigationItem.LeftBarButtonItem = backbutton;
}
then app crashes when clicking "Back" NavButton on "Catalogue" page with in lambda
(sender, e) => { NavigationController?.PopViewController(true);
The disposed object ItemPageViewController.
The question is : How to correctly implement "SingleTop" page in MvvmCross?
Or
How to fix this problem?
P.S.: If from MvxPresenter remove line
topViewController.Dispose();
then in custom lambda would throw NullReferenceException.
P.P.S.: I believe it the problem that I don't remove controller from navigation stack. I have tried to remove controllers in Custom View Presenter, but, firstly, it is null there sometimes, and even with null check nothing helped.
UINavigationController has a function PopToViewController(UIViewController viewController, bool animated);
Instead of removing every ViewController when the views are of the same type, you could pop to the ViewController Catalogue when the backbutton is pressed.
UINavigationController has a property ViewControllers that we can use to find CatalogueViewController.
Since you're using MvvmCross we'll check for the ViewModel type.
var catalogueController = NavigationController.ViewControllers.First(c =>
((IMvxIosView)c).ViewModel.GetType() == typeof(CatalogueViewModel));
Now you can use the function PopToViewController to close all the views untill CatalogueController
CurrentNavigationController.PopToViewController(catalogueController, true);
Is it possible such that I can have a navigation controller in each of my tabs of a TabBarController while using Xamarin iOS? I've currently setup my storyboard like so (for simplicity, I'm using a single tab)
TabBarController -> NavigationController -> UITableViewController
In my UITableViewController, the following code in my ViewDidLoad method does not change the title nor add the desired button to the top navigation. Have I set up something wrong?
public override void ViewDidLoad()
{
base.ViewDidLoad();
Console.WriteLine("view did load");
Title = "My custom title";
NavigationItem.SetRightBarButtonItem(
new UIBarButtonItem(UIBarButtonSystemItem.Add, (sender, args) =>
{
PerformSegue("CreateRecordSegue", this);
})
, true);
}
Image of storyboard is here: https://ibb.co/m7qq85
The solution is to:
1) Remove the navigation controller that leads into the tab bar controller
2) Create a segue from the home page into the tab bar controller, making the segue type to replace (instead of push)
Using flyout navigation on monotouch by James Clancey. Can't get a subview controller to elegantly perform a segue on the main containing controller?
NavigationRoot = new RootElement ("Navigation") {
new Section ("Menu") {
new StringElement ("Mapview Controller"),
new StringElement ("Another View Controller"),
}
},
ViewControllers = new [] {
// mapview is a view inside this viewcontroller and able to perform segues
new UIViewController { View = mapView },
// this is a seperate viewcontroller but is embedded inside the flyoutNavigation
// AnotherViewController cant seem to call the root navigation controller (<-- actually a uiNav inside a tab bar nav) so i can perform a segue movement just like the above mapViewController??
this.Storyboard.InstantiateViewController("AnotherViewController") as AnotherViewController,
},
// sub viewcontroller i.e. AnotherViewController trying to move mainViewController to perform a segue..
// throws error: Receiver (<FlyoutNavigation.FlyoutNavigationController: 0x14360600>) has no segue with identifier 'segueTest'
this.ParentViewController.PerformSegue("segueTest", this);
* Update:
I gave up on segue. Instead of using additional view controllers, I'm relying on views but one of my views is a static-celled tableview and not sure how to add it to above code liek so:
ViewControllers = new [] {
new UIViewController { View = mapView },
new UIViewController { View = myTableView } // doesnt work - tried with 'new UITableViewController' which also fails
What do I do?
You can use navigation for that..
ViewControllers = new [] {
new UINavigationController (this.Storyboard.InstantiateViewController("profileViewController") as ProfileViewController),
}
I have a UITabBarController that hosts 5 UINavigationControllers (let's call them N1 - N5). Each of the UINavigationControllers has UI elements that cause a UITableViewController to be pushed onto the navigation stack (I use MonoTouch.Dialog DialogViewController to implement these UITableViewControllers). Let's call those T1 - T5.
When I navigate between the tabs, the ViewDidAppear method gets called on each of N1 - N5 as expected. But when I touch a UI element on, say, N1, that causes T1 to get pushed onto the nav stack, and then try to go back using the back button, N1's ViewDidAppear method doesn't get called.
The funny thing is that if I "tab over" to a different tab (say N2) and then "tab back" to N1, the ViewDidAppear will be called as normal. And even if I have T1 pushed onto the nav stack, if I do the same tabbing around, N1's ViewDidAppear will still be called.
The MonoTouch code for N1 looks like this:
public class CalendarPage : UINavigationController
{
private DialogViewController dvc;
public override void ViewDidAppear (bool animated)
{
// initialize controls
var now = DateTime.Today;
var root = new RootElement("Calendar")
{
from it in App.ViewModel.Items
where it.Due != null && it.Due >= now
orderby it.Due ascending
group it by it.Due into g
select new Section (((DateTime) g.Key).ToString("d"))
{
from hs in g
select (Element) new StringElement (((DateTime) hs.Due).ToString("d"),
delegate
{
ItemPage itemPage = new ItemPage(this, hs);
itemPage.PushViewController();
})
{
Value = hs.Name
}
}
};
if (dvc == null)
{
// create and push the dialog view onto the nav stack
dvc = new DialogViewController(UITableViewStyle.Plain, root);
dvc.NavigationItem.HidesBackButton = true;
dvc.Title = NSBundle.MainBundle.LocalizedString ("Calendar", "Calendar");
this.PushViewController(dvc, false);
}
else
{
// refresh the dialog view controller with the new root
var oldroot = dvc.Root;
dvc.Root = root;
oldroot.Dispose();
dvc.ReloadData();
}
base.ViewDidAppear (animated);
}
}
I figured out what was going on. When the back button is pressed on the inner DialogViewController (created in ItemPage), the outer DialogViewController ("T1" above) is now the first responder, NOT the UINavigationController ("N1"). My confusion stemmed from the fact that I turned the back button off on that outer DialogViewController so I was assuming I had popped out all the way to the UINavigationController (N1), whereas I was still in a DialogViewController (T1).
I implemented the desired behavior (refreshing the contents of "T1") by creating a ViewDissapearing event on the inner DialogViewController (ItemPage in this case) and checking whether I am popping out - and if so, invoking the parent controller's ViewDidAppear method.
actionsViewController.ViewDissapearing += (sender, e) =>
{
if (actionsViewController.IsMovingFromParentViewController)
controller.ViewDidAppear(false);
};
Note the funny thing about this code is that the property that actually works is IsMovingFromParentViewController, NOT IsMovingToParentViewController (which is intuitively what you'd think would be set when you're navigating back). I imagine this may be a bug in MT.Dialog, but something that can't be fixed for back-compact reasons.
I hope this ends up helping someone...
I'm having a problem going back again to my first Apps VC, the first "screen/ViewController)" is a login screen, then I call a UITabbar with their respective ViewControllers, when I'm on a certain level of a ViewController (for example the 5th one) I want to get a "Logout" behavior in my App and get back to the first ViewController (Login). But I think I can only Navigate back to the first ViewController of my Tabbar control. I was trying with this methods of my VC:
this.NavigationController.PopToViewController(previousVC,true);
or
this.NavigationController.PopToRootViewController(true);
Any help would be appreciated.
(If you need more details with the code please tell me about it)
//Call to the tab bar from the login viewcontroller
mainTBC = new TabBarMenuPpal ();
this.NavigationController.PushViewController (mainTBC, true);
…
//Tabbarmenuppal with a set of navcontrollers
public TabBarMenuPpal ()
{
var customerVC = new Customers ();
navCustomers = new UINavigationController ();
navCustomers.PushViewController (customerVC, true);
navCustomers.TopViewController.Title = customersTitle;
navCustomers.TabBarItem = new UITabBarItem (customersTitle, UIImage.FromFile ("Utility/Images/Cust-30x30.png"), 0);
…
mainVC = new UIViewController[]
{
navCustomers
, navSettings
} ;
this.ViewControllers = mainVC;
}
The problem is that when I start to navigate in the navCustomers I can't find a way to go back to the login VC (deleting my tab bar and releasing all their resources). (Sorry about my English).
I don't know if it's the best solution but I have implemented a "GoToLogin" method in my UITabBarController which only does this:
public void GoToLogin()
{
this.NavigationController.PopToRootViewController(true);
}
So when I need to go to my first page I only do this:
if(MainDialog.NavigationController.TabBarController != null)//loaded from the tab bar
((TabBarMenuPpal)MainDialog.NavigationController.TabBarController).GoToLogin();
else//loaded from the login screen
MainDialog.NavigationController.PopToRootViewController(true);