Search code examples
c#wpfxamldatatemplatexamlparseexception

XAMLParser-created DataTemplate: Correct way to reference a StaticResource


I'm creating a DataTemplate in code using a XamlReader:

public DataTemplate CreateDataTemplate()
{
    string template = @"<DataTemplate >
                            <StackPanel>        
                                <ComboBox ItemsSource=""{Binding Source={StaticResource collectibleTypeFromEnum}}"" />              
                            </StackPanel>
                        </DataTemplate>";

    ParserContext context = new ParserContext();
    context.XamlTypeMapper = new XamlTypeMapper(new string[0]);
    context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
    context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");

    // This is meant to provide reference to where collectibleTypeFromEnum lives
    context.XamlTypeMapper.AddMappingProcessingInstruction("myview", "MyProgram.View", "MyProgram, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
    context.XmlnsDictionary.Add("myview", "myview");

    return XamlReader.Parse(template, context) as DataTemplate;
}

The XAMLParser successfully parses the string and returns a DataTemplate, but it then crashes at runtime ('System.Windows.Markup.XamlParseException': "Provide value on 'System.Windows.Markup.StaticResourceHolder'"). I need help providing the correct reference to that StaticResource, and I can't figure it out.

I'm trying to provide the correct namespace/reference via the ParserContext (see above), but clearly I'm doing it wrong. If I retrieve the ObjectDataProvider from the XAML and add it to the Application's global resources instead (Application.Current.Resources.Add()) everything works. But it seems to me that I should be able to directly reference the XAML resource.

The converter in question is defined in a user control (the same one the DataTemplate initially lived in, so the DT had no problem finding it):

<UserControl x:Class="MyProgram.View.CollectibleDetail"
             [...] >
    <UserControl.Resources>
    <ObjectDataProvider x:Key="collectibleTypeFromEnum" MethodName="GetValues" ObjectType="{x:Type System:Enum}">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="model:ECollectibleType"/>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</UserControl.Resources>

Solution

  • StaticResource doesn't support forward referencing. You could either add the resource to Application.Current.Resources in order to make it available throughout your entire application or you could use {DynamicResource}:

    string template = @"<DataTemplate >
                        <StackPanel>        
                            <ComboBox ItemsSource=""{DynamicResource collectibleTypeFromEnum}"" />              
                        </StackPanel>
                    </DataTemplate>";