dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.24k stars 1.76k forks source link

Creating a Page using a DataTemplate does not support Dependency Injection #4072

Closed IndianaGary closed 2 years ago

IndianaGary commented 2 years ago

Description

This was bug #3698: it has reemerged in Preview 11.

Attempting to reference a Page in a ShellContent DataTemplate that supports constructor injection fails with a MissingMethodException because the class does not have a parameterless constructor.

I've included a simple sample demonstrating the problem

MauiDIShellBugSample.zip

Suggested avenue: I reviewed the code in ShellContent.cs GetOrCreateContent() method. It appears that this failure can only occur if

    `var services = Parent?.FindMauiContext()?.Services;`

on or about line 70 returns null; e.g. either Parent or the MauiContext is null.

Steps to Reproduce

  1. Create a new Maui application.
  2. Tailor it to support Shell with one or more Tab pages whose ShellContent DataTemplate references a view model in the constructor.
  3. Register the view model in MauiProgram.cs.
  4. Build and run the app.
  5. See stack trace below for the resulting crash.

Version with bug

Preview 11

Last version that worked well

Unknown/Other

Affected platforms

Android, Windows, I was not able test on other platforms

Affected platform versions

Android 21+; Windows 10.0.19041

Did you find any workaround?

This can only be worked around by avoiding constructor injection which renders the whole feature moot.

Relevant log output

Stack Trace:

System.MissingMethodException
  HResult=0x80131513
  Message=Cannot dynamically create an instance of type 'MauiDIShellBugSample.DIPage1'. Reason: No parameterless constructor defined.
  Source=System.Private.CoreLib
  StackTrace:
   at System.RuntimeType.ActivatorCache..ctor(RuntimeType rt)
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic, Boolean wrapExceptions)
   at System.Activator.CreateInstance(Type type)
   at Microsoft.Maui.Controls.ElementTemplate.<>c__DisplayClass4_0.<.ctor>b__0()
   at Microsoft.Maui.Controls.ElementTemplate.CreateContent()
   at Microsoft.Maui.Controls.Internals.DataTemplateExtensions.CreateContent(DataTemplate self, Object item, BindableObject container)
   at Microsoft.Maui.Controls.ShellContent.Microsoft.Maui.Controls.IShellContentController.GetOrCreateContent()
   at Microsoft.Maui.Controls.Platform.ShellSectionView.NavigateToShellSection(ShellSection section)
   at Microsoft.Maui.Controls.Platform.ShellItemView.OnShellSectionChanged(ShellSection oldSection, ShellSection newSection)
   at Microsoft.Maui.Controls.Platform.ShellItemView.set_ShellSection(ShellSection value)
   at Microsoft.Maui.Controls.Platform.ShellItemView.NavigateToShellItem(ShellItem newItem, Boolean animate)
   at Microsoft.Maui.Controls.Platform.ShellView.SwitchShellItem(ShellItem newItem, Boolean animate)
   at Microsoft.Maui.Controls.Platform.ShellView.OnElementSet(Shell shell)
   at Microsoft.Maui.Controls.Platform.ShellView.SetElement(VisualElement element)
   at Microsoft.Maui.Controls.Handlers.ShellHandler.SetVirtualView(IView view)
   at Microsoft.Maui.Handlers.ViewHandler`2.SetVirtualView(IElement view)
   at Microsoft.Maui.Controls.Element.SetHandler(IElementHandler newHandler)
   at Microsoft.Maui.Controls.Element.set_Handler(IElementHandler value)
   at Microsoft.Maui.Platform.HandlerExtensions.ToNative(IElement view, IMauiContext context)
   at Microsoft.Maui.Controls.Window.MapContent(WindowHandler handler, IWindow view)
   at Microsoft.Maui.PropertyMapper.UpdatePropertyCore(String key, IElementHandler viewHandler, IElement virtualView)
   at Microsoft.Maui.PropertyMapper.UpdateProperties(IElementHandler viewHandler, IElement virtualView)
   at Microsoft.Maui.Handlers.ElementHandler.SetVirtualView(IElement view)
   at Microsoft.Maui.Controls.Element.SetHandler(IElementHandler newHandler)
   at Microsoft.Maui.Controls.Element.set_Handler(IElementHandler value)
   at Microsoft.Maui.Platform.HandlerExtensions.SetHandler(IWinRTObject nativeElement, IElement element, IMauiContext context)
   at Microsoft.Maui.Platform.HandlerExtensions.SetWindowHandler(Window nativeWindow, IWindow window, IMauiContext context)
   at Microsoft.Maui.Platform.ApplicationExtensions.CreateNativeWindow(Application nativeApplication, IApplication application, OpenWindowRequest args)
   at Microsoft.Maui.Platform.ApplicationExtensions.CreateNativeWindow(Application nativeApplication, IApplication application, LaunchActivatedEventArgs args)
   at Microsoft.Maui.MauiWinUIApplication.OnLaunched(LaunchActivatedEventArgs args)
   at MauiDIShellBugSample.WinUI.App.OnLaunched(LaunchActivatedEventArgs args) in D:\Projects\MauiBugs\MauiDIShellBugSample\Platforms\Windows\App.xaml.cs:line 26
   at Microsoft.UI.Xaml.Application.Microsoft.UI.Xaml.IApplicationOverrides.OnLaunched(LaunchActivatedEventArgs args)
   at ABI.Microsoft.UI.Xaml.IApplicationOverrides.Do_Abi_OnLaunched_0(IntPtr thisPtr, IntPtr args)
PureWeen commented 2 years ago

This behavior was added in P12 not P11 so it will be part of the next release