Access ViewController in DependencyService to present MFMailComposeViewController

后端 未结 5 2059
失恋的感觉
失恋的感觉 2020-12-15 23:15

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

5条回答
  •  抹茶落季
    2020-12-15 23:42

    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 on 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 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 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 ();
            if (mailservice == null)
                return;
            mailservice.ComposeMail (new [] {"foo@example.com"}, "Test", "Hello, World");
        })
    }
    

提交回复
热议问题