WPF DataTemplateSelector.SelectTemplate not called for a ContentControl-derived type
Asked Answered
U

3

6

I'm trying to build a ContentControl-derived control (let's call it MyContentControl) that will have its ControlTemplate set by an instance of a DataTemplateSelector-derived type (let's call it MyTemplateSelector).

When I try to this:

ContentControl contentControl = new ContentControl();
contentControl.ContentTemplateSelector = new MyTemplateSelector();
contentControl.Content = "Some ContentControl Content";

MyContentControl myContentControl = new MyContentControl();    
myContentControl.ContentTemplateSelector = new MyTemplateSelector();
myContentControl.Content = "Some MyControl Content";

I expect that, when I set content on those controls, MyTemplateSelector's override of DataTemplateSelector.SelectTemplate() method gets called for both contentControl and myContentControl.

In reality, it gets called only for contentControl. What do I need to do (and why!) to make it work for myContentControl too?

(Not sure if it's relevant, but for the moment MyContentControl does not do anything with DependencyProperties other than overriding metadata information for DefaultStyleKeyProperty.

EDIT (moved content from other post to original question):

Here is a bit more elaborated example:

  1. Create MyContentControl:

    public class MyContentControl : ContentControl
    {
      static MyContentControl()
      {
        DefaultStyleKeyProperty.OverrideMetadata(typeof (MyContentControl),
                                             new FrameworkPropertyMetadata(typeof (MyContentControl)));
      }
      public MyContentControl() {}
    }
    
  2. Create MyTemplateSelector:

    public class MyTemplateSelector : DataTemplateSelector
    {
      public override DataTemplate SelectTemplate(object item, DependencyObject container)
      {
        return null;  // <== Place the breakpoint here
      }
    }
    
  3. Add ContentControl and MyContent control to your main window (for example):

    <StackPanel>
        <local:MyContentControl x:Name="myContentControl" />
        <ContentControl x:Name="contentControl" />
    </StackPanel>
    
  4. Add this code somewhere after InitializeComponent (or in Loaded handler):

    myContentControl.ContentTemplateSelector = new MyTemplateSelector();
    myContentControl.Content = "123";
    
    contentControl.ContentTemplateSelector = new MyTemplateSelector();
    contentControl.Content = "ABC";
    

The breakpoint mentioned in step (2) gets hit only once, for content="ABC" and contentControl element.

Underachieve answered 17/7, 2009 at 7:19 Comment(0)
C
2

I got the same problem before, and I solve it with this (Notify DataTemplateSelector about the change) hint.

My problem was, I want a ContentPresenter which changes embedded UserControl when the ComboBox selection changed.

The Combobox+ContentPresenter XAML is

        <ComboBox Name="comboBoxControl" Grid.Row="1" Grid.Column="1" SelectionChanged="comboBox_SelectionChanged">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectionChanged">
                <cmd:EventToCommand Command="{Binding Path=ChangeControlCommand, Mode=OneWay}" CommandParameter="{Binding Path=SelectedItem.Content, ElementName=comboBoxControlType}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
        <ComboBoxItem>UserControl-1-</ComboBoxItem>
        <ComboBoxItem>UserControl-2-</ComboBoxItem>
    </ComboBox>
<ContentPresenter Name="contentPresenter" ContentTemplateSelector="{Binding Source={StaticResource controlCueTemplateSelector}}" 
                      Content="{Binding}" />

As you can see, the command binding with MVVM manner was my approach. Although you might not want to write a code-behind, kindly write a code-behind with appropriate event as below.

    private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var content = contentPresenter.Content;
        contentPresenter.ClearValue(ContentPresenter.ContentProperty);
        contentPresenter.SetValue(ContentPresenter.ContentProperty, content);
    }

Bottomline is, you need to reset the binded target object (in my case, the Content property).

Coaptation answered 16/8, 2010 at 7:20 Comment(0)
C
2

I just had the same problem and the reason that the DataTemplateSelector has been applied for a ContentControl but not for my derived Control was hidden in the ControlTemplate for my derived Control. I simply forgot to add the template binding for the ContentTemplateSelector:

<ControlTemplate TargetType="{x:Type local:UniControl}">
<Border Background="{TemplateBinding Background}"
        BorderBrush="{TemplateBinding BorderBrush}"
        BorderThickness="{TemplateBinding BorderThickness}">
    <ContentPresenter Content="{TemplateBinding Content}"
                        ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"/>
</Border>

Hope this helps.

Cookery answered 30/9, 2011 at 14:32 Comment(0)
S
0

You might need to post more of your code, because I just created a simple example and it worked fine. My DataTemplate only contains a TextBox, my DataTemplateSelector always returns that DataTemplate, and both a ContentControl and a class derived from ContentControl use my DataTemplateSelector. In both cases a TextBox was displayed.

Sonnnie answered 17/7, 2009 at 11:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.