VISUAL STUDIO   Windows Mac

Hello, iOS Multiscreen

Handling Navigation with Xamarin.iOS

PDF for offline use
Sample Code:
Related SDKs:

Let us know how you feel about this

Translation Quality


0/250

last updated: 2016-12

In this two-part guide, we expand the Phoneword application we created in the Hello, iOS guide to handle a second screen. Along the way we’ll introduce the Model-View-Controller design pattern, implement our first iOS navigation, and develop a deeper understanding of iOS application structure and functionality.

Hello.iOS Multiscreen Quickstart

This part of the walkthrough will add a second screen to the Phoneword application that will display a history of the phone numbers that were called with the app. The final application will have a second screen that displays the call history, as illustrated by the following screenshot:

The accompanying Deep Dive, will review the application that is build built and discuss architecture, navigation, and other new iOS concepts that we encounter along the way.

Requirements

This guide resumes where the Hello, iOS document left off, and requires completion of the Hello, iOS Quickstart. The completed version of the Phoneword app can be downloaded from the Hello, iOS sample.

Walkthrough – Navigation with Segues

This walkthrough will add a Call History screen to our Phoneword application.

  1. Open the Phoneword application in Visual Studio for Mac. If necessary, the completed Phoneword application from the Hello, iOS walkthrough guide can be downloaded from here:

  2. Open the Main.storyboard file from the Solution Pad:

  3. Drag a Navigation Controller from the Toolbox onto the design surface (You might need to zoom out to fit these all on the design surface!):

  4. Drag the Sourceless Segue (that’s the gray arrow to the left of the Phoneword Scene) from the Phoneword Scene to the Navigation Controller to change the starting point of the application:

  5. Select the Root View Controller by clicking on the black bar, and press Delete to remove it from the design surface. Then, let’s move the Phoneword Scene next to the Navigation Controller:

  6. Set the ViewController as the Navigation Controller’s Root View Controller. Press down the Ctrl key and click inside the Navigation Controller. A blue line should appear. Then, still holding down the Ctrl key, drag from the Navigation Controller to the Phoneword Scene and release. This is called Ctrl-dragging:

  7. From the popover, let’s set the relationship to Root:

    The ViewController is now our Navigation Controller’s Root View Controller:

  8. Double-click on the Phoneword screen’s Title bar and change the Title to Phoneword:

  9. Drag a Button from the Toolbox and place it under the Call Button. Drag the handles to make the new Button the same width as the Call Button:

  10. In the Properties Pad, change the Name of the Button to CallHistoryButton and change the Title to Call History:

  11. Create the Call History screen. From the Toolbox, drag a Table View Controller onto the design surface:

  12. Next, select the Table View Controller by clicking on the black bar at the bottom of the Scene. In the Properties Pad, change the Table View Controller’s class to CallHistoryController and press Enter:

    The iOS Designer will generate a custom backing class called CallHistoryController to manage this screen’s Content View Hierarchy. The CallHistoryController.cs file will appear in the Solution Pad:

  13. Double-click on the CallHistoryController.cs file to open it and replace the contents with the following code:

    using System;
    using Foundation;
    using UIKit;
    using System.Collections.Generic;
    
    namespace Phoneword_iOS
    {
        public partial class CallHistoryController : UITableViewController
        {
            public List<string> PhoneNumbers { get; set; }
    
            static NSString callHistoryCellId = new NSString ("CallHistoryCell");
    
            public CallHistoryController (IntPtr handle) : base (handle)
            {
                TableView.RegisterClassForCellReuse (typeof(UITableViewCell), callHistoryCellId);
                TableView.Source = new CallHistoryDataSource (this);
                PhoneNumbers = new List<string> ();
            }
    
            class CallHistoryDataSource : UITableViewSource
            {
                CallHistoryController controller;
    
                public CallHistoryDataSource (CallHistoryController controller)
                {
                    this.controller = controller;
                }
    
                public override nint RowsInSection (UITableView tableView, nint section)
                {
                    return controller.PhoneNumbers.Count;
                }
    
                public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
                {
                    var cell = tableView.DequeueReusableCell (CallHistoryController.callHistoryCellId);
    
                    int row = indexPath.Row;
                    cell.TextLabel.Text = controller.PhoneNumbers [row];
                    return cell;
                }
            }
        }
    }

    Save the application (⌘ + s) and build it (⌘ + b) to ensure there are no errors.

  14. Let’s create a Segue (transition) between the Phoneword Scene and the Call History Scene. In the Phoneword Scene, select the Call History Button and Ctrl-drag from the Button to the Call History Scene:

    From the Action Segue popover, select Show:

    The iOS Designer will add a Segue between the two Scenes:

  15. Add a Title to the Table View Controller by selecting the black bar at the bottom of the Scene and changing the View Controller Title to Call History in the Properties Pad:

  16. When the application is run, the Call History Button will open the Call History screen, but the Table View will be empty because there is no code to to keep track of and display the phone numbers.

    This app will store the phone numbers as a list of strings.

    Add a using directive for System.Collections.Generic at the top of ViewController:

    using System.Collections.Generic;
  17. Modify the ViewController class with the following code:

    namespace Phoneword_iOS
    {
        public partial class ViewController : UIViewController
        {
            // translatedNumber was moved here from ViewDidLoad ()
            string translatedNumber = "";
    
            public List<string> PhoneNumbers { get; set; }
    
            public ViewController (IntPtr handle) : base (handle)
            {
                //initialize list of phone numbers called for Call History screen
                PhoneNumbers = new List<string> ();
    
            }
            // ViewDidLoad, etc...
        }
    }

    Note that the variable translatedNumber was moved from the ViewDidLoad method to a class-level variable.

  18. Modify the CallButton code to add dialed numbers to the list of phone numbers by calling PhoneNumbers.Add(translatedNumber). The full code will look like this:

    CallButton.TouchUpInside += (object sender, EventArgs e) => {
    
        //Store the phone number that we're dialing in PhoneNumbers
        PhoneNumbers.Add (translatedNumber);
    
        // Use URL handler with tel: prefix to invoke Apple's Phone app...
        var url = new NSUrl ("tel:" + translatedNumber);
    
        // otherwise show an alert dialog
        if (!UIApplication.SharedApplication.OpenUrl (url)) {
            var alert = UIAlertController.Create ("Not supported", "Scheme 'tel:' is not supported on this device", UIAlertControllerStyle.Alert);
            alert.AddAction (UIAlertAction.Create ("Ok", UIAlertActionStyle.Default, null));
            PresentViewController (alert, true, null);
        }
    };
  19. Add the following method to the ViewController class. This will go somewhere below ViewDidLoad:

    public override void PrepareForSegue (UIStoryboardSegue segue, NSObject sender)
    {
       base.PrepareForSegue (segue, sender);
    
       // set the View Controller that’s powering the screen we’re
       // transitioning to
    
       var callHistoryContoller = segue.DestinationViewController as CallHistoryController;
    
       //set the Table View Controller’s list of phone numbers to the
       // list of dialed phone numbers
    
       if (callHistoryContoller != null) {
          callHistoryContoller.PhoneNumbers = PhoneNumbers;
       }
     }

    Save and build the application to make sure there are no errors.

  20. Press the Start button to launch the application inside the iOS Simulator:

⚠️

Note: At present, due to a requirement from Apple, it is necessary to have a a development certificate or signing identity in order to build you code for device or simulator. Follow the steps in the Device Provisioning guide to set this up.

Congratulations on completing your first multi-screen Xamarin.iOS application!

Walkthrough – Code Only Navigation

In the walkthrough above, navigation between the Phoneword and Call History screens was performed using a Storyboard Segue. Segues are great at handling simple navigation that requires moving from one screen to the next. Segues are not good at handling more complex navigation – for example, conditional navigation when the second screen may be different depending on the user’s behavior on the first screen. In this walkthrough, we’ll learn to handle navigation between screens programmatically.

  1. Open the Main.storyboard file and remove the Segue between the Phoneword Scene and the Call History Scene by selecting the Segue and pressing Delete:

    This will remove the Title Bar and Back Button from the Call History screen.

  2. Select the CallHistoryController by clicking on the black bar at the bottom of the Scene. In the Properties Pad, set this View Controller’s Storyboard ID to CallHistoryController:

  3. Next, in the ViewController class, remove the PrepareForSegue method that was added in the previous walkthrough. Comment the the entire method out by selecting the code, right-clicking and choosing Toggle Line Comment(s) from the menu:

  4. Add the following code inside the ViewDidLoad method. This wires up the CallHistoryButton to perform the navigation to the next screen:

    CallHistoryButton.TouchUpInside += (object sender, EventArgs e) => {
       // Launches a new instance of CallHistoryController
       CallHistoryController callHistory = this.Storyboard.InstantiateViewController ("CallHistoryController") as CallHistoryController;
       if (callHistory != null) {
          callHistory.PhoneNumbers = PhoneNumbers;
          this.NavigationController.PushViewController (callHistory, true);
       }
    };

    Save and build the application to make sure there are no errors.

  5. Press the Start button to launch the application inside the iOS Simulator. It should look and behave exactly the same as the previous version:

    ⚠️

    Note: At present, due to a requirement from Apple, it is necessary to have a a development certificate or signing identity in order to build you code for device or simulator. Follow the steps in the Device Provisioning guide to set this up.

Walkthrough – Navigation with Segues

This walkthrough will add a Call History screen to our Phoneword application.

  1. Open the Phoneword application in Visual Studio. If necessary, download the completed Phoneword application from the Hello, iOS walkthrough guide download the . Recall that it is necessary to connect to a Mac to use the iOS Designer, and iOS simulator.

  2. Start by editing the user interface. Open the Main.storyboard file from the Solution Explorer, making sure that View As is set to iPhone 6:

  3. Drag a Navigation Controller from the Toolbox onto the design surface:

  4. Drag the Sourceless Segue (that’s the gray arrow to the left of the Phoneword Scene) from the Phoneword Scene to the Navigation Controller to change the starting point of the application:

  5. Select the Root View Controller by clicking on the black bar, and press Delete to remove it from the design surface. Then, move the Phoneword Scene next to the Navigation Controller:

  6. Set the ViewController as the Navigation Controller’s Root View Controller. Press down the Ctrl key and click inside the Navigation Controller. A blue line should appear. Then, still holding down the Ctrl key, drag from the Navigation Controller to the Phoneword Scene and release. This is called Ctrl-dragging:

  7. From the popover, set the relationship to Root:

    The ViewController is now our Navigation Controller’s Root View Controller.

  8. Double-click on the Phoneword screen’s Title bar and change the Title to Phoneword:

  9. Drag a Button from the Toolbox and place it under the Call Button. Drag the handles to make the new Button the same width as the Call Button:

  10. In the Properties Explorer, change the Name of the Button to CallHistoryButton and change the Title to Call History:

  11. Create the Call History screen. From the Toolbox, drag a Table View Controller onto the design surface:

  12. Select the Table View Controller by clicking on the black bar at the bottom of the Scene. In the Properties Explorer, change the Table View Controller’s class to CallHistoryController and press Enter:

    The iOS Designer will generate a custom backing class called CallHistoryController to manage this screen’s Content View Hierarchy. The CallHistoryController.cs file will appear in the Solution Explorer:

  13. Double-click on the CallHistoryController.cs file to open it and replace the contents with the following code:

    using System;
    using Foundation;
    using UIKit;
    using System.Collections.Generic;
    
    namespace Phoneword
    {
        public partial class CallHistoryController : UITableViewController
        {
            public List<String> PhoneNumbers { get; set; }
    
            static NSString callHistoryCellId = new NSString ("CallHistoryCell");
    
            public CallHistoryController (IntPtr handle) : base (handle)
            {
                TableView.RegisterClassForCellReuse (typeof(UITableViewCell), callHistoryCellId);
                TableView.Source = new CallHistoryDataSource (this);
                PhoneNumbers = new List<string> ();
            }
    
            class CallHistoryDataSource : UITableViewSource
            {
                CallHistoryController controller;
    
                public CallHistoryDataSource (CallHistoryController controller)
                {
                    this.controller = controller;
                }
    
                // Returns the number of rows in each section of the table
                public override nint RowsInSection (UITableView tableView, nint section)
                {
                    return controller.PhoneNumbers.Count;
                }
    
                public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
                {
                    var cell = tableView.DequeueReusableCell (CallHistoryController.callHistoryCellId);
    
                    int row = indexPath.Row;
                    cell.TextLabel.Text = controller.PhoneNumbers [row];
                    return cell;
                }
            }
        }
    }

    Save the application and build it to ensure there are no errors. It is okay to ignore any build warnings for now.

  14. Create a Segue (transition) between the Phoneword Scene and the Call History Scene. In the Phoneword Scene, select the Call History Button and Ctrl-drag from the Button to the Call History Scene:

    From the Action Segue popover, select Show:

    The iOS Designer will add a Segue between the two Scenes:

  15. Add a Title to the Table View Controller by selecting the black bar at the bottom of the Scene and changing View Controller > Title to Call History in the Properties Explorer:

  16. When the application is run, the Call History Button will open the Call History screen, but the Table View will be empty because there is no code to to keep track of and display the phone numbers.

    This app will store the phone numbers as a list of strings.

    Add a using directive for System.Collections.Generic at the top of ViewController:

    using System.Collections.Generic;
  17. Modify the ViewController class with the following code:

    namespace Phoneword_iOS
    {
        public partial class ViewController : UIViewController
        {
            // translatedNumber was moved here from ViewDidLoad ()
            string translatedNumber = "";
    
            public List<string> PhoneNumbers { get; set; }
    
            public ViewController (IntPtr handle) : base (handle)
            {
                //initialize list of phone numbers called for Call History screen
                PhoneNumbers = new List<string> ();
    
            }
            // ViewDidLoad, etc...
        }
    }

    Note that the variable translatedNumber was moved from the ViewDidLoad method to a class-level variable.

  18. Modify the CallButton code to add dialed numbers to the list of phone numbers by calling PhoneNumbers.Add(translatedNumber). The full code will look like this:

    CallButton.TouchUpInside += (object sender, EventArgs e) => {
    
            //Store the phone number that we're dialing in PhoneNumbers
            PhoneNumbers.Add (translatedNumber);
    
            // Use URL handler with tel: prefix to invoke Apple's Phone app...
            var url = new NSUrl ("tel:" + translatedNumber);
    
            // otherwise show an alert dialog
            if (!UIApplication.SharedApplication.OpenUrl (url)) {
                var alert = UIAlertController.Create ("Not supported", "Scheme 'tel:' is not supported on this device", UIAlertControllerStyle.Alert);
                alert.AddAction (UIAlertAction.Create ("Ok", UIAlertActionStyle.Default, null));
                PresentViewController (alert, true, null);
            }
        };
  19. Finally, add the following method to the ViewController class. This will go somewhere below ViewDidLoad:

    public override void PrepareForSegue (UIStoryboardSegue segue, NSObject sender)
    {
       base.PrepareForSegue (segue, sender);
    
       // set the View Controller that’s powering the screen we’re
       // transitioning to
    
       var callHistoryContoller = segue.DestinationViewController as CallHistoryController;
    
       //set the Table View Controller’s list of phone numbers to the
       // list of dialed phone numbers
    
       if (callHistoryContoller != null) {
          callHistoryContoller.PhoneNumbers = PhoneNumbers;
       }
     }

    Save and build the application to make sure there are no errors.

  20. Press the Start button to launch our application inside the iOS Simulator:

Congratulations on completing your first multi-screen Xamarin.iOS application!

Walkthrough – Code-Only Navigation

In the walkthrough above, navigation between the Phoneword and Call History screens was performed using a Storyboard Segue. Segues are great at handling simple navigation that requires moving from one screen to the next. Segues are not good at handling more complex navigation – for example, conditional navigation when the second screen may be different depending on the user’s behavior on the first screen. This walkthrough will demonstrate how to handle navigation programmatically.

  1. Open the Main.storyboard file and remove the Segue between the Phoneword Scene and the Call History Scene by selecting the Segue and pressing Delete:

    This will remove the Title Bar and Back Button from the Call History screen.

  2. Select the CallHistoryController by clicking on the black bar at the bottom of the Scene. In the Properties Explorer, let’s set this View Controller’s Storyboard ID to CallHistoryController:

  3. Next, in the ViewController class, let’s remove the PrepareForSegue method we added in the previous walkthrough. Comment out the entire method by selecting the code, and browsing to Edit > Advanced > Comment Selection:

  4. Add the following code inside the ViewDidLoad method. This wires up the CallHistoryButton to perform the navigation to the next screen:

    CallHistoryButton.TouchUpInside += (object sender, EventArgs e) => {
       // Launches a new instance of CallHistoryController
       CallHistoryController callHistory = this.Storyboard.InstantiateViewController ("CallHistoryController") as CallHistoryController;
       if (callHistory != null) {
          callHistory.PhoneNumbers = PhoneNumbers;
          this.NavigationController.PushViewController (callHistory, true);
       }
    };

    Save and build the application to make sure there are no errors.

  5. Press the Start button to launch the application inside the iOS Simulator. It should look and behave exactly the same as the previous version:

The app can now handle navigation using both Storyboard Segues and in code. Now it’s time to dissect the tools and skills we just learned in the Hello, iOS Multiscreen Deep Dive.

Xamarin Workbook

If it's not already installed, install the Xamarin Workbooks app first. The workbook file should download automatically, but if it doesn't, just click to start the workbook download manually.