访问DependencyService中的ViewController以显示MFMailComposeViewController

时间:2014-06-10 08:39:43

标签: xamarin.ios xamarin xamarin.forms

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

5 个答案:

答案 0 :(得分:22)

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

  

警告:尝试出现< MFMailComposeViewController:0x16302c30> on< Xamarin_Forms_Platform_iOS_PlatformRenderer:0x14fd1530>其视图不在窗口层次结构中!

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

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

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

完整的解决方案如下:

在您的AppDelegate.cs中添加:

public UIWindow Window {
    get { return window; }
}

在您的PCL项目中,声明界面:ISendMailService.cs

public interface ISendMailService
{
    void ComposeMail (string[] recipients, string subject, string messagebody = null, Action<bool> completed = null);
}
在您的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);
    }
}

现在您可以从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");
    })
}

答案 1 :(得分:11)

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

答案 2 :(得分: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;
    }

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

答案 3 :(得分:2)

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

这仅适用于所有解决方案

答案 4 :(得分:0)

仅供参考。我花了一些时间来弄清楚如何从模态窗口启动它。

解决方案来了:

var rootController = ((AppDelegate)(UIApplication.SharedApplication.Delegate)).Window.RootViewController.PresentedViewController;
var navcontroller = rootController as UINavigationController;
if (navcontroller != null)
    rootController = navcontroller.VisibleViewController;
rootController.PresentViewController (controller, true, null);