20

I set up a ContentControl.DataTemplateSelector to my desired one.
I want that according to a command or whatever, call the ContentControl to reselect the template from the selector by either xaml or code.

Thank

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632

4 Answers4

21

Late to the party, I know. =)

When faced with this problem, I found it easiest to explicitly set a new TemplateSelector like

MyContentControl.ContentTemplateSelector =
     new MyDataTemplateSelector();
Jens
  • 25,229
  • 9
  • 75
  • 117
  • +1 it's never too late! unlike other posts, which are depressing, because they tell you that there is no way to do what you want!your solution works, and gave me a great idea, I'll post it in a bit, when I have time today. – denis morozov Apr 30 '12 at 15:49
  • What I actually did, is storing every presenter that calls SelectTemplate (as a weak reference) in my DataTemplateSelector and provide a static method to refresh all these. – Jens May 11 '12 at 19:13
  • What happens if you raise the property changed event on the bound property (if you're binding to your own class)? – Monstieur Jun 21 '13 at 12:57
  • If the content's type did not change, I believe it is rendered using the current template instead of asking the template selector again. – Jens Jun 21 '13 at 19:06
  • This is making the component completely rerender again, even if the template selected is the same :/ – Bruno Lemos Sep 17 '16 at 21:56
14

I guess I am even later to the party, but for a different idea that may help someone...

You could also try using a ValueConverter on the ContentControls ContentTemplate property instead of a DataTemplateSelector.

Just have a property in your DataContext to bind, like ScreenNumber for example. Then in the ValueConverter return the DataTemplate that is associated with the ScreenNumber.

Example ValueConverter:

public class ValueDataTemplateConverter : IValueConverter
{
    public DataTemplate TemplateA { get; set; }
    public DataTemplate TemplateB { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is ValueType valueType)
            switch (valueType)
            {
                case ValueType.TypeA:
                    return TemplateA;
                case ValueType.TypeB:
                    return TemplateB;
             }

        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Example xaml resource:

<converters:ValueDataTemplateConverter x:Key="ValueDataTemplateConverter">
    <converters:ValueDataTemplateConverter.TemplateA>
        <DataTemplate>
            <TextBox Text="{Binding Value}" />
        </DataTemplate>
    </converters:ValueDataTemplateConverter.TemplateA>
    <converters:ValueDataTemplateConverter.TemplateB>
        <DataTemplate>
            <CheckBox IsChecked="{Binding Value}" />
        </DataTemplate>
    </converters:ValueDataTemplateConverter.TemplateB>
</converters:ValueDataTemplateConverter>
Peter van Kekem
  • 1,387
  • 1
  • 12
  • 30
fraggy
  • 141
  • 1
  • 2
  • 1
    Thank you for updating this years later. I wouldn't have thought to use a converter and this solution doesn't require code-behind. Very nice. – Seanba Oct 29 '19 at 01:25
11

I'm not aware of any (non-kludgy) way to do this: the DataTemplateSelector is called when WPF needs to select the template, and that's a one-off decision as far as WPF is concerned. (You can kludge it by making WPF think the content has changed, e.g. by setting the content to null and then back again -- I think that would work but haven't tested it -- but this is pretty ugly!) If there is a nice way to do this I too would be interested to know!

However, there is an alternative way to change how content is displayed that does update in response to data changes, and that is through triggers. You can use DataTriggers in your DataTemplate.Triggers collection to show and hide elements depending on the content data. To change the entire display, you could e.g. set up two renderings in a Grid, and use triggers to control which one is visible. You could even make your data template a ContentControl, and use a trigger to change the ContentTemplate. Of course this depends on the criteria for changing the template being bindable properties, which may not always be the case.

Here's some brief discussion of selectors vs. triggers, albeit in a slightly different context.

itowlson
  • 73,686
  • 17
  • 161
  • 157
  • 1
    I am having problems using it with DataTrigger, please take a look: http://stackoverflow.com/questions/2090148/unable-to-set-contenttemplate-via-datatrigger – Shimmy Weitzhandler Jan 19 '10 at 00:27
6

Similar to Jens answer, instead of creating a new instance , you can use the existing instance of the DataTemplateSelector.

var currentSelector = MyContentControl.ContentTemplateSelector;     
MyContentControl.ContentTemplateSelector = null;
MyContentControl.ContentTemplateSelector = currentSelector;
Goldorak84
  • 3,714
  • 3
  • 38
  • 62