WPF DataTemplateSelector.SelectTemplate не вызывается для производного типа ContentControl - PullRequest
6 голосов
/ 17 июля 2009

Я пытаюсь создать элемент управления ContentControl (давайте назовем его MyContentControl), для которого ControlTemplate будет установлен экземпляром типа DataTemplateSelector (давайте назовем его MyTemplateSelector ).

Когда я пытаюсь это сделать:

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

Я ожидаю, что, когда я устанавливаю содержимое для этих элементов управления, переопределение MyTemplateSelector метода DataTemplateSelector.SelectTemplate() вызывается для contentControl и myContentControl.

В действительности он вызывается только для contentControl. Что мне нужно сделать (и почему!), Чтобы это работало и для myContentControl?

(Не уверен, что это актуально, но на данный момент MyContentControl ничего не делает с DependencyProperties, кроме переопределения метаданных для DefaultStyleKeyProperty.

РЕДАКТИРОВАТЬ (перенес содержание из другого сообщения в исходный вопрос):

Вот немного более сложный пример:

  1. Создать MyContentControl:

    public class MyContentControl : ContentControl
    {
      static MyContentControl()
      {
        DefaultStyleKeyProperty.OverrideMetadata(typeof (MyContentControl),
                                             new FrameworkPropertyMetadata(typeof (MyContentControl)));
      }
      public MyContentControl() {}
    }
    
  2. Создать MyTemplateSelector:

    public class MyTemplateSelector : DataTemplateSelector
    {
      public override DataTemplate SelectTemplate(object item, DependencyObject container)
      {
        return null;  // <== Place the breakpoint here
      }
    }
    
  3. Добавьте ContentControl и MyContent элемент управления в главное окно (например):

    <StackPanel>
        <local:MyContentControl x:Name="myContentControl" />
        <ContentControl x:Name="contentControl" />
    </StackPanel>
    
  4. Добавьте этот код где-нибудь после InitializeComponent (или в обработчике Loaded):

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

Точка останова, упомянутая в шаге (2), получает удар только один раз, для элементов content="ABC" и contentControl.

Ответы [ 3 ]

2 голосов
/ 16 августа 2010

У меня раньше была та же проблема, и я решаю ее с помощью этой подсказки ( Notify DataTemplateSelector об изменении ).

Моя проблема заключалась в том, что я хочу ContentPresenter, который меняет встроенный UserControl при изменении выбора ComboBox.

XAML Combobox + ContentPresenter составляет

        <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}" />

Как вы можете видеть, связывание команд в манере MVVM было моим подходом. Хотя вы, возможно, не захотите писать код позади, любезно пишите код с соответствующим событием, как показано ниже.

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

Суть в том, что вам нужно сбросить объект привязки (в моем случае это свойство Content).

2 голосов
/ 30 сентября 2011

У меня была та же проблема, и причина, по которой DataTemplateSelector был применен для ContentControl, но не для моего производного элемента управления, скрыта в ControlTemplate для моего производного элемента управления. Я просто забыл добавить привязку шаблона для 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>

Надеюсь, это поможет.

0 голосов
/ 17 июля 2009

Возможно, вам потребуется опубликовать больше вашего кода, потому что я только что создал простой пример, и он работал нормально. My DataTemplate содержит только TextBox, my DataTemplateSelector всегда возвращает это DataTemplate, и оба ContentControl и класс, полученный из ContentControl, используют my DataTemplateSelector. В обоих случаях было отображено TextBox.

...