I'm trying to show the iOS add contact screen using Xamarin Forms. From what I can see Xamarin Forms does not support this out of the box but Xamarin iOS does. Unfortunately I can't get them to work together. What I mean by "together" is that I need get access to NavigationController from Xamarin Forms Page.
Can this be done?
I have a sample solution that demonstrates the problem here: https://github.com/pawelpabich/XamarinFormsContacts. I also put the most important code below.
public void ShowContact(NavigationPage page)
{
var newPersonController = new ABNewPersonViewController();
var person = new ABPerson();
person.FirstName = "John";
person.LastName = "Doe";
newPersonController.DisplayedPerson = person;
var controller = page.CreateViewController();
//!!!!---> controller.NavigationController is null !!!!!<----
controller.NavigationController.PushViewController(newPersonController, true);
}
I updated the repo and it now contains code that works.
There is a UINavigationController when using Xamarin.Forms (when using a NavigationPage), but you have to search for it. This was the only way I could get a hold of it. Those other methods, CreateViewController and RendererFactory actually create a new ViewController which isn't what you wanted.
public void ShowContact(NavigationPage page)
{
var newPersonController = new ABNewPersonViewController();
var person = new ABPerson();
person.FirstName = "John";
person.LastName = "Doe";
newPersonController.Title = "This is a test";
newPersonController.DisplayedPerson = person;
UINavigationController nav = null;
foreach (var vc in
UIApplication.SharedApplication.Windows[0].RootViewController.ChildViewControllers)
{
if (vc is UINavigationController)
nav = (UINavigationController)vc;
}
nav.PresentModalViewController(new UINavigationController (newPersonController), true);
}
I also attempted to Create a PersonPage and PersonPageRenderer, as that would be the cleanest solution, but I couldn't get it working. This could work if you spent some time.
[assembly: ExportRenderer(typeof(PersonPage), typeof(PersonPageRenderer))]
public class PersonPageRenderer : ABNewPersonViewController, IVisualElementRenderer, IDisposable, IRegisterable
Pawel, the problem is that when you use Xamarin.Forms no NavigationController is created (as I know at least in X.F 1.3+, maybe Michael will prove me wrong). If you want to create new address boo element you can use this approach - How do you add contacts to the iPhone Address book with monotouch?
Because iOS Add Contact screen is a Native iOS API and your application logic is in a PCL you need to use a DependancyService.
1) To do this in the PCL create a Interface which provides the functionality, like
public interface ILocalAddContact
{
void DisplayContactScreen(Contact contact)
}
2) Implement the Interface in the Native Applications:
public class LocalAddContactiOS : ILocalAddContact
{
public void DisplayContactScreen(Contact contact)
{
//... do iOS Magic
}
}
3) Register the Dependancy in the Top of the Native File
[assembly: Xamarin.Forms.Dependency(typeof(LocalAddContactiOS))]
4) Obtain the Dependancy from the iOS Project from the
var addContact = DependencyService.Get<ILocalAddContact> ();
addContact.DisplayContactScreen (contact);
If you take a look at this sample application on github, it's very similar (but is used for CreateCalendar).
Ok, this is how I finally implemented. I created UINavigationController manually and use it for navigations outside Xamarin.Forms.
using System;
using System.Collections.Generic;
using System.Linq;
using Foundation;
using UIKit;
using Xamarin.Forms;
using AddressBookUI;
using AddressBook;
namespace TestContacts.iOS
{
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
UIWindow window;
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init ();
window = new UIWindow(UIScreen.MainScreen.Bounds);
var nav =
new UINavigationController(new App ().MainPage.CreateViewController());
ContactsShared.Instance = new TouchContacts (nav);
window.RootViewController = nav;
window.MakeKeyAndVisible();
return true;
}
}
public class TouchContacts : IContactsShared {
UINavigationController nav;
public TouchContacts(UINavigationController nav){
this.nav = nav;
}
public void Show() {
var newPersonController = new ABNewPersonViewController();
newPersonController.NewPersonComplete +=
(object sender, ABNewPersonCompleteEventArgs e) =>
{
nav.PopViewController(true);
};
var person = new ABPerson();
person.FirstName = "John";
person.LastName = "Doe";
newPersonController.DisplayedPerson = person;
nav.PushViewController(newPersonController, true);
}
}
}