Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataTemplate with Converter in Code Behind

Tags:

c#

wpf

I'm trying to load a DataTemplate in code-behind, but it works fine if I remove the Converter... but as soon as I put it in there, it blows. Now, I did set my state my namespace and placed the reference to my converter in XAML. for example:

<Window.Resources>
     <local:StatCellConverter x:Key="myConverter" />
</Window.Resources>

and this is my method where I generate a DataTemplate:

private DataTemplate GenerateStatRowDataTemplate()
{
    ParserContext pc = new ParserContext();
    pc.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
    pc.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
    pc.XmlnsDictionary.Add("xcdg", "http://schemas.xceed.com/wpf/xaml/datagrid");

    string statRowTemplate = "<DataTemplate><xcdg:StatRow>";
    statRowTemplate += "<xcdg:StatCell FieldName=\"Column4\" ResultPropertyName=\"AvgColumn4\">";
    statRowTemplate += "<xcdg:StatCell.ContentTemplate>";
    statRowTemplate += "<DataTemplate>";
    statRowTemplate += "<TextBlock Text=\"{Binding ., Converter={StaticResource ResourceKey=myConverter}}\" />";
    statRowTemplate += "</DataTemplate>";
    statRowTemplate += "</xcdg:StatCell.ContentTemplate>";
    statRowTemplate += "</xcdg:StatCell>";
    statRowTemplate += "</xcdg:StatRow>";
    statRowTemplate += "</DataTemplate>";

    StringReader stringReader = new StringReader(statRowTemplate);
    XmlReader xmlReader = XmlReader.Create(stringReader);
    MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(statRowTemplate.ToString()));
    DataTemplate dt = (DataTemplate)XamlReader.Load(ms,pc);
    dt.LoadContent();
    return dt;
}

What am i doing wrong? Could it be that I would have to define my converter in code behind as well?

My Converter

public class StatCellConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Debug.WriteLine(value);

            if (value.Equals("#DIV/0#"))
                return "0";
            return value;
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

I get an exception saying that it cannot load the DataTemplate

like image 304
Nerd in Training Avatar asked Oct 19 '11 16:10

Nerd in Training


2 Answers

This in fact is a bug in the framework. Adding the local name space through the XmlnsDictionary wouldn't work. It has to be added within the template definition with the assembly and namespace defined:

as in the comment above by @Nerd In Training this should work:

string statRowTemplate = "<DataTemplate >"; 

private DataTemplate GenerateStatRowDataTemplate()
{
    ParserContext pc = new ParserContext();
    pc.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
    pc.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
    pc.XmlnsDictionary.Add("xcdg", "http://schemas.xceed.com/wpf/xaml/datagrid");

    string statRowTemplate = "<DataTemplate xmlns:local=\"clr-namespace:MyTest;assembly=MyTest\" ><xcdg:StatRow>";
    statRowTemplate += "<xcdg:StatCell FieldName=\"Column4\" ResultPropertyName=\"AvgColumn4\">";
    statRowTemplate += "<xcdg:StatCell.ContentTemplate>";
    statRowTemplate += "<DataTemplate>";
    statRowTemplate += "<TextBlock Text=\"{Binding ., Converter={StaticResource ResourceKey=myConverter}}\" />";
    statRowTemplate += "</DataTemplate>";
    statRowTemplate += "</xcdg:StatCell.ContentTemplate>";
    statRowTemplate += "</xcdg:StatCell>";
    statRowTemplate += "</xcdg:StatRow>";
    statRowTemplate += "</DataTemplate>";

    StringReader stringReader = new StringReader(statRowTemplate);
    XmlReader xmlReader = XmlReader.Create(stringReader);
    MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(statRowTemplate.ToString()));
    DataTemplate dt = (DataTemplate)XamlReader.Load(ms,pc);
    dt.LoadContent();
    return dt;
}
like image 160
Dahdahm Avatar answered Oct 06 '22 00:10

Dahdahm


The full version

    var ms = new MemoryStream(Encoding.UTF8.GetBytes(@"<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
                                                                     xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""                                                                             
                                                                     xmlns:c=""clr-namespace:MyApp.Converters;assembly=MyApp"">
            <DataTemplate.Resources>
                <c:MyConverter x:Key=""MyConverter""/>
            </DataTemplate.Resources>
            <TextBlock Text=""{Binding ., Converter={StaticResource MyConverter}}""/>
          </DataTemplate>"));
    var template = (DataTemplate)XamlReader.Load(ms);

    var cb = new ComboBox { };
    //Set the data template
    cb.ItemTemplate = template;
like image 42
Pavlo Datsiuk Avatar answered Oct 06 '22 00:10

Pavlo Datsiuk