XamlReader and {StaticResource }

Hi,

I'm trying to dynamically create a DataTemplate from an XAML string using XamlReader, but I cannot reference a value converter static resource. If I omit staticresource references it compiles and loads correctly.

What is the correct way of linking the resources of the application into the xaml being loaded I have tried ParserContext with Parent set to the ListBox that the dataTemplate will be assigned to.

I was trying xaml similar to this which works when used in the standard non-dynamic way.

<DataTemplate xmlns="..." >

<StackPanel>

<Image Source={Bind XPath=@Id, Converter={StaticResource IdToImageConverter}}/>

</StackPanel>

</DataTemplate>

Many thanks,

Alec



Answer this question

XamlReader and {StaticResource }

  • Gareth D

    You're passing XamlReader.Load a constant string, isn't it easier to just include that in the original xaml

    Anyhow, I don't know why the DynamicResource doesn't resolve, could be that we aren't reevaluating the dynamic resource reference after the TextBlock has been added to the main tree. You might try adding the text box to the tree before adding the dynamic resource reference. Or just set the property value in code --

    TextBox blocks = new Textbox();

    box.Style = ThePanel.FindResource("MyDynamicStyle");



  • RichWood

    This line of code isn't doing what you'd expect:

    pc.Parent = ThePanel;

    The XamlReader loads the tree in without understanding that context that you appeared to set. We'll file a bug and debate how/if we can handle this.

    Thanks for bringing this up.

    Thx, Rob Relyea
    WPF, PM
    http://longhornblogs.com/rrelyea


  • Zoop

    a workaround for now...use {DynamicResource ...}

    StaticResource must be resolved at load time.
    DynamicResource can wait until somebody queries for the property value.


  • Dan Moreira

    Thanks Rob, DynamicResource works well.

    As an alternative, I was trying to use local classes and created the following class

    public class MyTextBlock: TextBlock{}

    and noted that if I tried (using the above example)

    pc.XmlnsDictionary.Add( "l", "clr-namespace:WindowsApplication1;assembly=WindowsApplication1");

    and parsing the following string

    string xaml = "<l:MyTextBlock Style=\"{DynamicResource MyStaticStyle}\"></l:MyTextBlock>";

    that the namespace wasn't recognised, but if I parsed the following string:

    string xaml = "<l:MyTextBlock xmlns:l=\"clr-namespace:WindowsApplication1;assembly=WindowsApplication1\" Style=\"{DynamicResource MyStaticStyle}\"></l:MyTextBlock>";

    It works. Obviously I'm passing the incorrect value to the xmlns dictionary on the ParseContext - what would be the correct value

    Thanks again,

    Alec


  • RWeeden

    Hi,

    I have a basic Style which would be a StaticResource. I need to modify this Style at runtime. I found it was not possible to dynamically add Setters to a Style. So, I tried creating a DynamicResource Style BasedOn the StaticResource Style. But, this gives me a "Cannot find Resource Error". I have taken the sample in this thread and modified it as given below.

    XAML:

    <Window x:Class="WindowsApplication1.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="WindowsApplication1" Height="300" Width="300"

    >

    <Viewbox><StackPanel Name="ThePanel">
    <StackPanel.Resources>
    <Style x:Key="MyStaticStyle">
    <Setter Property="TextBlock.Text" Value="My Text Block Text"/>
    </Style>
    </StackPanel.Resources>
    <Button Content="From C#" Click="ClickCSharpButtonHandler"></Button>

    <Button Content="From Xaml" Click="ClickXamlButtonHandler"></Button>

    <TextBlock Style="{StaticResource MyStaticStyle}"></TextBlock>

    </StackPanel></Viewbox>

    </Window>

    CODE:

    private void ClickCSharpButtonHandler(object sender, EventArgs e)
    {
    TextBlock t = new TextBlock();
    t.Style = (Style)((FrameworkElement)sender).FindResource("MyStaticStyle");
    ThePanel.Children.Add( t );
    }

    MemoryStream sr = null;
    ParserContext pc = null;
    string xaml = string.Empty;
    private void ClickXamlButtonHandler(object sender, EventArgs e)
    {
    try
    {
    if (sr == null)
    {
    xaml = "<Style BasedOn=\"{StaticResource MyStaticStyle}\"><Setter Property=\"TextBlock.Foreground\" Value=\"LightGreen\"/></Style>";
    sr = new MemoryStream(Encoding.ASCII.GetBytes(xaml));
    pc = new ParserContext();
    pc.Parent = ThePanel;
    pc.XmlnsDictionary.Add("", "
    http://schemas.microsoft.com/winfx/2006/xaml/presentation");
    pc.XmlnsDictionary.Add("x", "
    http://schemas.microsoft.com/winfx/2006/xaml");
    Style dynamicStyle = (Style)XamlReader.Load(sr, pc);
    ThePanel.Resources.Add("MyDynamicStyle", dynamicStyle);
    }
    xaml = "<TextBlock Style=\"{DynamicResource MyDynamicStyle}\"/>";
    sr = new MemoryStream(Encoding.ASCII.GetBytes(xaml));
    ThePanel.Children.Add((TextBlock)XamlReader.Load(sr, pc));
    }
    catch (XamlParseException ex)
    {
    MessageBox.Show(ex.ToString());
    }
    }


    - RAM



  • Shahedul Huq Khandkar

    Yes, DynamicResources don't work if the property (Converter in this case) are normal CLR properties.

    It works if the property is backed by a dependencyProperty.

    Putting everything in App.Resources is a good solution for now.

    We'll take a look at your earlier post (2 posts ago) to see why clr-namespace doesn't work there...

    Thx, Rob


  • shecla

    Is IdToImageConverter defined before that DataTemplate

    StaticResources don't support forward referencing.


  • bangaram

    Sorry, I can't get DynamicResource to work in this nested situation:

    <TextBlock Text="{Binding XPath=@WireFeedId, Converter={DynamicResource IdToNameConverter}}" />

    Can't convert DynamicResourceExtension to IValueConverter or similar.

    In the end (for the moment), I put all the converters in App.Resources and everything works.

    Thanks,

    Alec


  • Dato0011

    Thanks Rob,

    here is some code that shows the problem (I think)

    Regards,

    Alec

    <Window x:Class="WindowsApplication1.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="WindowsApplication1" Height="300" Width="300"

    >

    <Viewbox>

    <Viewbox.Resources>

    <Style x:Key="MyStaticStyle">

    <Setter Property="TextBlock.Text" Value="My Text Block Text"/>

    </Style>

    </Viewbox.Resources>

    <StackPanel Name="ThePanel">

    <Button Content="From C#" Click="ClickCSharpButtonHandler"></Button>

    <Button Content="From Xaml" Click="ClickXamlButtonHandler"></Button>

    <TextBlock Style="{StaticResource MyStaticStyle}"></TextBlock>

    </StackPanel>

    </Viewbox>

    </Window>

    With the code behind being:

    private void ClickCSharpButtonHandler(object sender, EventArgs e)

    {

    TextBlock t = new TextBlock();

    t.Style = (Style)((FrameworkElement)sender).FindResource("MyStaticStyle");

    ThePanel.Children.Add( t );

    }

    private void ClickXamlButtonHandler(object sender, EventArgs e)

    {

    string xaml = "<TextBlock Style=\"{StaticResource MyStaticStyle}\"/>";

    try

    {

    MemoryStream sr = new MemoryStream(Encoding.ASCII.GetBytes(xaml));

    ParserContext pc = new ParserContext();

    pc.Parent = ThePanel;

    pc.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");

    pc.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");

    ThePanel.Children.Add((TextBlock)XamlReader.Load(sr, pc));

    }

    catch (XamlParseException ex)

    {

    MessageBox.Show(ex.ToString());

    }

    }


  • MannuBhai

    Good news and bad news.

    Good news: The problem is fixed.
    Bad news: It was fixed by removing the Parent property from Parser Context (for similar reason).

    This means that the scenario you were looking for is difficult to do with StaticResource for our first version.

    DynamicResource is probably the best way to do this...


  • XamlReader and {StaticResource }