Intermittent NullReferenceException when calling MediaPicker.Default.CapturePhotoAsync() & Email.Default.ComposeAsync
A user has reported an issue on an iPhone (iOS 17.3.1) where an exception has been repeatedly thrown when the app calls MediaPicker.Default.CapturePhotoAsync() & Email.Default.ComposeAsync. After a few phone and app restarts the issue seemed to resolve itself. The exceptions are:
EX: System.NullReferenceException: The current view controller can not be detected.
at Microsoft.Maui.ApplicationModel.WindowStateManagerExtensions.GetCurrentUIViewController(IWindowStateManager , Boolean )
at Microsoft.Maui.ApplicationModel.Communication.EmailImplementation.ComposeWithMailCompose(EmailMessage )
at Microsoft.Maui.ApplicationModel.Communication.EmailImplementation.ComposeAsync(EmailMessage )
at MyApp.OnEmail(Object sender, EventArgs e)
EX: System.NullReferenceException: The current view controller can not be detected.
at Microsoft.Maui.ApplicationModel.WindowStateManagerExtensions.GetCurrentUIViewController(IWindowStateManager , Boolean )
at Microsoft.Maui.Media.MediaPickerImplementation.PhotoAsync(MediaPickerOptions , Boolean , Boolean )
at MyApp.ShowPhotoSourceSelectionAsync()
Cut down version of code:
public partial class App : Application
{
public App()
{
MainPage = new LoginPage();
}
}
public partial class LoginPage : ContentPage
{
private async void SignInButton_Clicked(object sender, EventArgs e)
{
App.Current.MainPage = new NavigationPage(new MainPagePhone());
}
}
public partial class MainPagePhone : ContentPage
{
protected override void OnAppearing()
{
var detailPage = DataCollectorSubmissionDetailPage.CreatePage(viewModel.Title, dataCollectorSubmissionViewModel);
await Navigation.PushModalAsync(new NavigationPage(detailPage));
}
}
public partial class DataCollectorSubmissionDetailPage : ContentPage
{
public StackLayout FormContent
{
get; private set;
}
public static DataCollectorSubmissionDetailPage CreatePage(string title, DataCollectorSubmissionViewModel viewModel)
{
var sectionControl = new DataCollectorSectionControl();
FormContent.Children.Add(sectionControl);
mainScrollView.Content = FormContent; // This is a scroll view in the xaml
}
}
public class DataCollectorSectionControl : VerticalStackLayout
{
public StackLayout FieldControls { get; private set; }
public DataCollectorSectionControl()
{
BaseFieldControl control = field.CreateControl(_viewModel, _readOnly, _openToolTipPDF);
FieldControls.Children.Add(control);
Children.Add(FieldControls);
}
}
public class PhotoFieldControl : BaseFieldControl
{
public PhotoFieldControl(PhotoField photoField, DataCollectorSubmissionViewModel viewModel, bool readOnly, Action<string, string> openToolTipPDFAction) : base(photoField, viewModel, readOnly, openToolTipPDFAction)
{
var grid = new Grid();
grid.Add(CreateFieldLabel(_photoField.FieldName, _photoField.IsMandatory), 0, 0);
grid.Add(CreateValueView(FieldValueLabel), 0, 1);
grid.Add(image, 1, 0);
grid.SetRowSpan(image, 2);
var children = new View[] { grid };
ConstructField(children, CreateFieldTapGestureRecogniser(ReadOnly), photoField);
}
public override BaseFieldControl CreateControl(DataCollectorSubmissionViewModel viewModel, bool readOnly, Action<string, string> openToolTipPDFAction)
{
return new PhotoFieldControl(this, viewModel, readOnly, openToolTipPDFAction);
}
public async Task OnTapped()
{
FileResult file = await MediaPicker.Default.CapturePhotoAsync();
}
public class BaseFieldControl : StackLayout
{
protected virtual void ConstructField(IList<View> children, IList<TapGestureRecognizer> gestureRecognizers, Field field)
{
StackLayout stackLayout = new StackLayout();
foreach (View child in children)
{
stackLayout.Children.Add(child);
}
if (gestureRecognizers != null)
{
foreach (TapGestureRecognizer gestureRecognizer in gestureRecognizers)
{
stackLayout.GestureRecognizers.Add(gestureRecognizer);
}
}
ConstructField(stackLayout, field);
}
protected virtual void ConstructField(StackLayout containerLayout, Field field)
{
AddStackLayoutStyleBinding(containerLayout);
containerLayout.BindingContext = field;
Children.Add(containerLayout);
}
}