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...