Reputation: 1228
I have a xaml file containing a ResourceDictionary
which I load during startup of my WPF GUI. This xaml file resides in the same assembly. Here's a minimal version of the code which triggers the issue:
var uri = new Uri("/MyAssemblyName;component/MyNamespace/ResDict.xaml", UriKind.Relative);
System.Windows.Application.LoadComponent(uri);
Here's the exception message:
System.Windows.Markup.XamlParseException: Set property 'System.Windows.ResourceDictionary.DeferrableContent' threw an exception. Line number '197' and line position '11'.
InnerException
NotImplementedException: The method or operation is not implemented.
And here is the full stacktrace:
PresentationFramework.dll!System.Windows.Baml2006.Baml2006SchemaContext.ResolveBamlType(System.Windows.Baml2006.Baml2006SchemaContext.BamlType bamlType, short typeId) Line 582
PresentationFramework.dll!System.Windows.Baml2006.Baml2006SchemaContext.GetXamlType(short typeId) Line 187
PresentationFramework.dll!System.Windows.Baml2006.Baml2006Reader.Process_ConstructorParameterType() Line 1111
PresentationFramework.dll!System.Windows.Baml2006.Baml2006Reader.Process_OneBamlRecord() Line 547
PresentationFramework.dll!System.Windows.Baml2006.Baml2006Reader.ReadKeys() Line 296
PresentationFramework.dll!System.Windows.ResourceDictionary.SetDeferrableContent(System.Windows.DeferrableContent deferrableContent) Line 1113
PresentationFramework.dll!System.Windows.Baml2006.WpfSharedBamlSchemaContext.Create_BamlProperty_ResourceDictionary_DeferrableContent.AnonymousMethod__297_0(object target, object value) Line 6707
PresentationFramework.dll!System.Windows.Baml2006.WpfKnownMemberInvoker.SetValue(object instance, object value) Line 46
System.Xaml.dll!MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetValue(System.Xaml.XamlMember member, object obj, object value) Line 294
System.Xaml.dll!MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetValue(object inst, System.Xaml.XamlMember property, object value) Line 279
System.Xaml.dll!System.Xaml.XamlObjectWriter.SetValue(object inst, System.Xaml.XamlMember property, object value) Line 2205
System.Xaml.dll!System.Xaml.XamlObjectWriter.Logic_ApplyPropertyValue(MS.Internal.Xaml.Context.ObjectWriterContext ctx, System.Xaml.XamlMember prop, object value, bool onParent) Line 1619
System.Xaml.dll!System.Xaml.XamlObjectWriter.Logic_DoAssignmentToParentProperty(MS.Internal.Xaml.Context.ObjectWriterContext ctx) Line 2053
System.Xaml.dll!System.Xaml.XamlObjectWriter.WriteEndMember() Line 813
System.Xaml.dll!System.Xaml.XamlWriter.WriteNode(System.Xaml.XamlReader reader) Line 50
PresentationFramework.dll!System.Windows.Markup.WpfXamlLoader.TransformNodes(System.Xaml.XamlReader xamlReader, System.Xaml.XamlObjectWriter xamlWriter, bool onlyLoadOneNode, bool skipJournaledProperties, bool shouldPassLineNumberInfo, System.Xaml.IXamlLineInfo xamlLineInfo, System.Xaml.IXamlLineInfoConsumer xamlLineInfoConsumer, MS.Internal.Xaml.Context.XamlContextStack<System.Windows.Markup.WpfXamlFrame> stack, System.Windows.Markup.IStyleConnector styleConnector) Line 267
PresentationFramework.dll!System.Windows.Markup.WpfXamlLoader.Load(System.Xaml.XamlReader xamlReader, System.Xaml.IXamlObjectWriterFactory writerFactory, bool skipJournaledProperties, object rootObject, System.Xaml.XamlObjectWriterSettings settings, System.Uri baseUri) Line 148
PresentationFramework.dll!System.Windows.Markup.WpfXamlLoader.LoadBaml(System.Xaml.XamlReader xamlReader, bool skipJournaledProperties, object rootObject, System.Xaml.Permissions.XamlAccessLevel accessLevel, System.Uri baseUri) Line 43
PresentationFramework.dll!System.Windows.Markup.XamlReader.LoadBaml(System.IO.Stream stream, System.Windows.Markup.ParserContext parserContext, object parent, bool closeStream) Line 1115
PresentationFramework.dll!System.Windows.Application.LoadBamlStreamWithSyncInfo(System.IO.Stream stream, System.Windows.Markup.ParserContext pc) Line 575
PresentationFramework.dll!System.Windows.Application.LoadComponent(System.Uri resourceLocator, bool bSkipJournaledProperties) Line 531
PresentationFramework.dll!System.Windows.Application.LoadComponent(System.Uri resourceLocator) Line 487
[... my code]
This has worked in the past, but stopped working recently when I upgraded the project files from .NET Framework 4.7.2 to target .NET 6.
There is no mention of a possible NotImplementedException
in the documentation for Application.LoadComponent.
I have reduced my ResDict.xaml down to the minimal content which triggers the problem. And it looks like this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyNamespace">
<DataTemplate DataType="{x:Type local:MyDataModel}" />
</ResourceDictionary>
It contains a single empty DataTemplate
for a type in the same assembly. I can't see anything very special about that type, it's a pretty normal datamodel. I have tens of similar classes and corresponding DataTemplates
, and I only see the crash for this particular one, no matter the content of the DataTemplate
including when it's empty.
Any ideas how to debug?
The outer exception about 'Set property DeferrableContent' occurs in dozens of StackOverflow questions in all kinds of circumstances, so I have a hunch the inner exception is more relevant.
I can see other questions which mention the Baml2006 NotImplementedException
, but they don't exactly apply to my case:
Upvotes: 2
Views: 1042
Reputation: 1228
Loading the xaml failed because the runtime could not locate an assembly referenced by the DataTemplate
's target type. The .NET code has (in my opinion) horrendous behaviour where it doesn't report the true problem -- the NotImplementedException
appears to be a placeholder for some important code that they just never wrote!
Since this exception hides any number of actual underlying exceptions, here is how I diagnosed the problem.
First I switched on step-through of .NET source code in the debugger. Then I could see the source line in Baml2006SchemaContext.cs that was throwing the exception. You can see the source here. I assume I cannot copy it into my answer for copyright reasons, so here is pseudocode:
private XamlType ResolveBamlType(string assemblyName)
{
// Can't step into below voodoo method for which source is unavailable
System.Reflection.Assembly ass = MS.Internal.GetLoadedAssembly(assemblyName);
if (ass != null)
{
return new XamlType(ass);
}
// Here in the source appears an extended comment about how they should finish implementing the method
throw new NotImplementedException();
}
What it should do in my opinion is return some information about why it couldn't resolve the assembly. But it gave me a clue. I added a couple of lines to my code before loading the xaml file:
var ass = System.Reflection.Assembly.Load("MyAssemblyName");
var _ = ass.DefinedTypes; // Access property and discard value
var uri = new Uri("/MyAssemblyName;component/MyNamespace/ResDict.xaml", UriKind.Relative);
System.Windows.Application.LoadComponent(uri);
The second line above throws a meaningful exception:
System.Reflection.ReflectionTypeLoadException: 'Unable to load one or more of the requested types. Could not load file or assembly 'Microsoft.Office.Interop.Excel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c'. The system cannot find the file specified.
OK, that's a real error I can now investigate! This is the exception I should have got instead of the NotImplementedException
.
An assembly could fail to load properly for a variety of reasons so if you have this problem, try adding the above lines to see the real error.
Weird side note 1: in my modified code above, my call to Assembly.Load is loading the very same assembly which contains the currently-executing lines of code... how can it fail if it's already running?
Weird side note 2: Assembly.Load
succeeds without throwing an exception. It's only when I access certain properties on the returned object that an exception is thrown.
Upvotes: 5