Как я могу получить доступ к ViewController в моей службе DependencyService для представления MFMailComposeViewController? Я пробовал использовать Application.Context, но похоже, что он работает только на Android. Любые советы?
Access ViewController в DependencyService представляет MFMailComposeViewController
Ответ 1
Вы можете представить MFMailComposeViewController, выполнив window.RootController.PresentViewController (mail controller, true, null);
. В зависимости от архитектуры вашего приложения 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 [] {"[email protected]"}, "Test", "Hello, World");
})
}
Ответ 2
Использование: UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(controller, true, null);
Ответ 3
Я хотел бы добавить дополнительный ответ, основанный на KeyWindow, который не всегда является основным окном. (это происходит, когда вы представляете свой контроллер после того, как пользователь взаимодействует с окном действия или диалоговым окном предупреждения)
public static UIViewController GetCurrentUIController()
{
UIViewController viewController;
var window = UIApplication.SharedApplication.KeyWindow;
if (window == null)
{
throw new InvalidOperationException("There 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 и верните его для использования, представляя любой пользовательский интерфейс или контроллер просмотра, который вам нужно представить.
Ответ 4
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(controller, true, null);
Это работает только во всех решениях
Ответ 5
Просто для справки. Мне потребовалось некоторое время, чтобы понять, как запустить его из модального окна.
Вот решение:
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);