Loading Loose Xaml with custom controls on WinRT f

2020-08-02 19:15发布

问题:

In ReactiveUI, I run this code at a certain point:

const string template = "<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:routing='using:ReactiveUI.Routing'>" +
    "<routing:ViewModelViewHost ViewModel=\"{Binding}\" VerticalContentAlignment=\"Stretch\" HorizontalContentAlignment=\"Stretch\" IsTabStop=\"False\" />" +
"</DataTemplate>";

var theTemplate = XamlReader.Load(template);

On other platforms, this works great (the xmlns declaration is different of course), but on {WinRT / Metro / Windows Store}, this throws an Unspecified Error:

WinRT information: The type 'ViewModelViewHost' was not found. [Line: 1 Position: 253]

The Twist

However, if you include a dummy resource on the page:

<Page.Resources>
    <DataTemplate x:Name="Foo">
        <routing:ViewModelViewHost ViewModel="{Binding}" />
    </DataTemplate>
</Page.Resources>

...then it works! What gives?

回答1:

The "twist" makes me think this must be because the application does not have correct XAML metadata for the type being instantiated - rather than using reflection to resolve types in XAML files like WPF/Silverlight, WinRT uses code generation to resolve via the IXamlMetadataProvider interface (there's a decent description here; this sounds like what you're doing, see also the followup). Adding the reference forces this metadata code to be generated properly. If this is the case, you should be able to achieve the same effect by simply adding the type itself to the resources under some unused key, without the data template.

Have a look in your application's "obj" directory, Visual Studio generates a XamlTypeInfo.g.cs file to implement IXamlMetadataProvider. This should contain an entry for the type that is failing - in the case where you have added a dummy reference, there should be full details required to instantiate the type. Without this, I've found it's possible to have some reference to type type, but insufficient information - however this prevents the fallthrough behaviour (looking up the type in a dependent DLL which might have a custom metadata provider).

Other than adding a dummy reference to the library type in the final application itself, the only solution I found for this is to apply the Bindable attribute to the type. While this is supposed to relate to C++, I found this can be used in C# to force a type to always appear in the code generated for XAML type metadata.