Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
512 views
in Technique[技术] by (71.8m points)

xamarin.ios - Access ViewController in DependencyService to present MFMailComposeViewController

How can i access the ViewController in my DependencyService to present a MFMailComposeViewController? I tried using Application.Context but this seems to be only working on Android. Any advice?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can present a MFMailComposeViewController by doing a window.RootController.PresentViewController (mail controller, true, null);. Depending on your app architecture, the RootViewController might not be an usable ViewController in the hierarchy. In that case you get a

Warning: Attempt to present <MFMailComposeViewController: 0x16302c30> on <Xamarin_Forms_Platform_iOS_PlatformRenderer: 0x14fd1530> whose view is not in the window hierarchy!

In that case, you have to dig for the concrete ViewController, in my case it is:

var rootController = ((AppDelegate)(UIApplication.SharedApplication.Delegate)).Window.RootViewController.ChildViewControllers[0].ChildViewControllers[1].ChildViewControllers[0];

which is a bit wicked, but works (An issue for this have been filed for future fix).

The full solution then looks like:

in your AppDelegate.cs, add this:

public UIWindow Window {
    get { return window; }
}

in your PCL project, declare the interface: ISendMailService.cs

public interface ISendMailService
{
    void ComposeMail (string[] recipients, string subject, string messagebody = null, Action<bool> completed = null);
}

in your iOS project, implement and register the interface: SendMailService.cs

[assembly: DependencyAttribute(typeof(SendMailService))]

public class SendMailService : ISendMailService
{
    public void ComposeMail (string[] recipients, string subject, string messagebody = null, Action<bool> completed = null)
    {
        var controller = new MFMailComposeViewController ();
        controller.SetToRecipients (recipients);
        controller.SetSubject (subject);
        if (!string.IsNullOrEmpty (messagebody))
            controller.SetMessageBody (messagebody, false);
        controller.Finished += (object sender, MFComposeResultEventArgs e) => {
            if (completed != null)
                completed (e.Result == MFMailComposeResult.Sent);
            e.Controller.DismissViewController (true, null);
        };

        //Adapt this to your app structure
        var rootController = ((AppDelegate)(UIApplication.SharedApplication.Delegate)).Window.RootViewController.ChildViewControllers[0].ChildViewControllers[1].ChildViewControllers[0];
        var navcontroller = rootController as UINavigationController;
        if (navcontroller != null)
            rootController = navcontroller.VisibleViewController;
        rootController.PresentViewController (controller, true, null);
    }
}

And you can now consume it from your Xamarin.Forms PCL project:

new Button {
    Font = Font.SystemFontOfSize (NamedSize.Medium),
    Text = "Contact us",
    TextColor = Color.White,
    BackgroundColor = ColorsAndStyles.LightBlue,
    BorderRadius = 0,
    Command = new Command (()=>{
        var mailservice = DependencyService.Get<ISendMailService> ();
        if (mailservice == null)
            return;
        mailservice.ComposeMail (new [] {"foo@example.com"}, "Test", "Hello, World");
    })
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...