locked
Change DataTemplate at runtime without using DataTemplateSelector? RRS feed

  • Question

  • Hi,

     

    I having been searching all over for information on how to change my DataTemplate from c# without using a DataTemplateSelector.    My data templates are in XAML but when I access them from the this.Resources[] I get back a data template that has a VisualTree property that is null.

     

    I can't use a DataTemplateSelector because there isn't anything in my data that the DataTemplateSelector could use to determine which DataTemplate to use.

     

    I saw that there was a similar thread on the forum but it was answered in a way to solve my problem.

     

    Anyone have any ideas?

     

    Cheers,

    Clint

    Friday, April 6, 2007 4:21 PM

Answers

  • Well,

     

    I think I have found work around.  If I create a xaml file or an inline string with my datatemplate, I am able to load it with XamlReader.Load() and apply it directly to the ItemTemplate of my ItemsControl object.  It seems like a strange work around since I would have expected to get the same result just by accessing the DataTemplate via the this.Resources[] section of my control.  Of course this might still be possible but so far I haven't figured it out yet.

     

    I also had started creating the template in code using FrameworkElementFactory but it turned out to be a pain.

     

    Oh well...

     

    Cheers,

    Clint

    Monday, April 9, 2007 6:28 AM

All replies

  • On what condition/event do you want to change the datatemplate?
    Friday, April 6, 2007 4:30 PM
  • I have made a modified wrap panel which I want to host an arbitrary collection of data attached to the ItemsSource.  Because I want to use the control generically I would like to pass the data as an array or list and attach the appropriate DataTemplate at runtime to render that specific data.

     

    Cheers,

    Clint

    Friday, April 6, 2007 11:03 PM
  • Well,

     

    I think I have found work around.  If I create a xaml file or an inline string with my datatemplate, I am able to load it with XamlReader.Load() and apply it directly to the ItemTemplate of my ItemsControl object.  It seems like a strange work around since I would have expected to get the same result just by accessing the DataTemplate via the this.Resources[] section of my control.  Of course this might still be possible but so far I haven't figured it out yet.

     

    I also had started creating the template in code using FrameworkElementFactory but it turned out to be a pain.

     

    Oh well...

     

    Cheers,

    Clint

    Monday, April 9, 2007 6:28 AM
  •  

    Clint, would you be able to share your code here .. I tried to something similar as you are doing, using XamlReader.Load() but getting exception.

     

    I have been looking for this information all over but found nothing that really helps

    Tuesday, October 23, 2007 4:33 PM
  • I did something similar to this yesterday.  We're creating a framework using WPF, and I want users of our framework to be able to create a data template in a particular situation that I can then supplement/mess with inside the framework. 

     

    After some research and messing around (including puzzling over why VisualTree was null for a DataTemplate I loaded from the resources, as specified earlier in the thread), I determined that the best way to handle it did seem to be to use XamlWriter/XamlReader.

     

    Here's some simplified code to show you what I did.  In this example I'm simply letting the user use an empty ContentControl as the placeholder that I replace with my custom DataTemplate code.  For the purposes of this example, you can think of the DataTemplate as a generic DataTemplate the user is creating that I'm going to use to bind to a variety of different columns in a GridView.  In this example I'm simply going to use "MyColumn" as the name of the data column I'm binding to within the DataTemplate.

     

    This code is running inside a class derived from ListView, in case you're curious.  I'm not copying the code directly so I can simplify it for this example, so I can't guarantee there aren't any bugs.

     

    Code Block

    // Get the user's initial DataTemplate from the Resources. 

    // This let's me customize their template instead of

    // creating one from scratch, which enhances flexibility.

    DataTemplate usersTemplate = TryFindResource("CustomCellTemplate");

     

    // Serialize the data template into a string.

    string usersTemplateSource = XamlWriter.Save(usersTemplate);

     

    // Modify the string to suit my needs. Normally "MyColumn"

    // wouldn't be hard-coded, of course.

    string revisedTemplate = usersTemplateSource.Replace(

    "<ContentControl />",

    "<ContentControl Content=\"{Binding Path=MyColumn}\" />");

     

    // Load the revised DataTemplate string using XamlReader.Load.

    byte[] bytes = System.Text.Encoding.ASCII.GetBytes(revisedTemplate);

    MemoryStream stream = new MemoryStream(bytes);

     

    // newTemplate will be the new DataTemplate, and I can use

    // that as I please.

    DataTemplate newTemplate = (DataTemplate)XamlReader.Load(stream);

     

     

    Hopefully that helps!

     

    David Cater
    Wednesday, October 24, 2007 4:00 PM
  • Hi,

     

    I've been looking for a way to do this.  I've found similar code samples, but for some reason, the binding doesn't work.  The rest of the template will display without issue, but the bound data won't.  And no errors.  Do you have any idea what I should be looking for?  I'm binding as normal: <TextBox Text="{Binding Path=MemberName}"/>

     

    One of those things where I know I'm just doing one simple thing wrong.

     

    I've proven I can set the DataTemplate dynamically from the ResourceDictionary, so the process works, just not the conversion of XAML to a DataTemplate object.

     

    Any direction you can give would be greatly appreciated.

     

    Thanks,

     

    Jerry

    Wednesday, February 6, 2008 3:05 AM
  • Jerry,

     

    I would probably need to see your code to make any intelligent observations. It's a bit hard to imagine in the abstract.  Can you post something simple that illustrates the problem you're having with the binding?

     

    David

     

    Wednesday, February 6, 2008 4:44 PM
  • Hi,

     

    Here's a sample of the C# code I'm using to convert XAML into a DataTemplate object.

     

    After posting, I gave up for the time being and went back to calling the DataTemplates from the App.xaml file (which previously worked), and encountered the same behavior: the static portions of the template would render, but no binding would occur.

     

    Code Snippet

    MemoryStream sr = null;

    ParserContext pc = null;

     

    string xaml = "<Grid><Grid.RowDefinitions><RowDefinition Height=\"auto\"/><RowDefinition Height=\"auto\"/><RowDefinition Height=\"auto\"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width=\"auto\"/><ColumnDefinition Width=\"auto\"/></Grid.ColumnDefinitions><TextBlock Text=\"Summary\" Grid.Row=\"0\" Grid.Column=\"2\"/><TextBlock Text=\"Id:\" Grid.Row=\"1\" Grid.Column=\"0\"/><TextBlock Text=\"{Binding Path=InstanceId}\" Grid.Row=\"1\" Grid.Column=\"1\"/><TextBlock Text=\"Name:\" Grid.Row=\"2\" Grid.Column=\"0\"/><TextBlock Text=\"{Binding Path=InstanceName}\" Grid.Row=\"2\" Grid.Column=\"1\"/></Grid>"

     

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

    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");

    DataTemplate datatemplate = XamlReader.Load(sr, pc) as DataTemplate;

     

     

    I then assign the DataTemplate object to the control's ContentTemplate, and the Grid will render, but the TextBlocks with binding will be empty.

     

    What's more, this works (worked) with a ContentPresenter, but would fail with an Expander when I was using the routine where it accessed the templates from the ResourceDictionary.  Neither would work when using the "generated" XAML/DataTemplate.

     

    Kinda frustrating because I know it works in theory (I've seen the code postings, which are consistent), I've seen the process work one way but not another, and I've seen it work with one control but NOT another.  Too many variables to deal with, and I'm too much of a newbie to be able to tell exactly which part is failing.

     

    Thanks for any help you can give.

    Wednesday, February 6, 2008 6:07 PM
  • I don't know why this works, but it works.

     

    What I was trying to do is have a person select a category from a ComboBox, which would populate a list of records for that category in a ListBox .  Once the person clicked on one of the listbox items, a ContentPresenter would have a DataTemplate (based on category) applied to it, and then the specific item from the ListBox bound to it to give a more complete display of the data.

     

    It wasn't working, and being a newbie, I wasn't sure exactly which part was failing, especially when all the debugging was coming back as expected.  As it turns out, it was order of operations, for lack of a more specific/satisfying description.

     

    To be clear, I originally had the DataTemplate being applied and the ContentPresenter bound to the selected item on the Click event for a button that was appearing for each ListBoxItem.  Stepping through my logic, I determined that it was a waste of resources to apply the DataTemplate when a ListBoxItem was selected when the DataTemplate to be applied was associated with the category from the ComboBox.  So I moved the application of the DataTemplate to the ComboBox's SelectionChanged event, and to my amazement, it all worked.  The information displayed in the ContentPresenter as I'd been wanting it to all along.

     

    SO, I'm not sure why a DataTemplate couldn't be applied in the same event as a binding, and I'm not sure if that's true across the board, but just in case anyone else is trying this and getting as frustrated as I was, you may want to try splitting out the tasks.

     

    Of course, if anyone has an explanation as to why this might be, I'd really appreciate it.

     

    Thank you for your time and consideration.

     

     

    Friday, February 15, 2008 2:18 AM