访问DependencyService中的ViewController以显示MFMailComposeViewController

FrT*_*pen 13 xamarin.ios xamarin xamarin.forms

如何在DependencyService中访问ViewController来呈现MFMailComposeViewController?我尝试使用Application.Context,但这似乎只适用于Android.有什么建议?

Ste*_*oix 22

您可以通过执行一个来呈现MFMailComposeViewController window.RootController.PresentViewController (mail controller, true, null);.根据您的应用程序体系结构,RootViewController可能不是层次结构中可用的ViewController.在那种情况下你会得到一个

警告:尝试在<Xamarin_Forms_Platform_iOS_PlatformRenderer:0x14fd1530>上显示<MFMailComposeViewController:0x16302c30>,其视图不在窗口层次结构中!

在这种情况下,你必须挖掘具体的ViewController,在我的例子中它是:

var rootController = ((AppDelegate)(UIApplication.SharedApplication.Delegate)).Window.RootViewController.ChildViewControllers[0].ChildViewControllers[1].ChildViewControllers[0];
Run Code Online (Sandbox Code Playgroud)

这有点邪恶,但有效(这个问题已经提交以备将来修复).

完整的解决方案如下:

在你的AppDelegate.cs,添加这个:

public UIWindow Window {
    get { return window; }
}
Run Code Online (Sandbox Code Playgroud)

在您的PCL项目中,声明接口: ISendMailService.cs

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

在您的iOS项目中,实现并注册界面: 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以从Xamarin.Forms PCL项目中使用它:

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");
    })
}
Run Code Online (Sandbox Code Playgroud)


Kla*_*sel 11

使用: UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(controller, true, null);


TCh*_*ick 5

我想基于KeyWindow添加一个额外的答案并不总是主窗口.(当您在用户与操作表或警报对话框进行交互后展示控制器时会发生这种情况)

public static UIViewController GetCurrentUIController()
    {
        UIViewController viewController;
        var window = UIApplication.SharedApplication.KeyWindow;
        if (window == null)
        {
            throw new InvalidOperationException("There's no current active window");
        }

        if (window.RootViewController.PresentedViewController == null)
        {
            window = UIApplication.SharedApplication.Windows
                     .First(i => i.RootViewController != null && 
                                 i.RootViewController.GetType().FullName
                                 .Contains(typeof(Xamarin.Forms.Platform.iOS.Platform).FullName));
        }

        viewController = window.RootViewController;

        while (viewController.PresentedViewController != null)
        {
            viewController = viewController.PresentedViewController;
        }

        return viewController;
    }
Run Code Online (Sandbox Code Playgroud)

这将保证您获得Xamarin Forms平台渲染器窗口,然后找到最重要的ViewController并将其返回以用于呈现您需要呈现的任何UI或视图控制器.