WPF: как правильно переопределить методы при создании пользовательского элемента управления - PullRequest
0 голосов
/ 10 марта 2010

Я создаю пользовательский набор элементов управления, который является производным от ItemsControl. Предполагается, что этот набор инструментов будет заполнен значками, поступающими из базы данных. Определение выглядит так:

public class Toolbox : ItemsControl
{              
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new ToolboxItem();
    }

    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return (item is ToolboxItem);
    }
}

Toolboxitem является производным от ContentControl.

public class ToolboxItem : ContentControl
{               
    static ToolboxItem()
    {
        FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(ToolboxItem), new FrameworkPropertyMetadata(typeof(ToolboxItem)));
    }
}

Поскольку количество значков, хранящихся в базе данных, неизвестно, я хочу использовать шаблон данных:

<DataTemplate x:Key="ToolBoxTemplate">
    <StackPanel>
        <Image Source="{Binding Path=url}" />
    </StackPanel>
</DataTemplate>

Тогда я хочу, чтобы Панель инструментов использовала шаблон.

<Toolbox x:Name="NewLibrary" ItemsSource="{Binding}" ItemTemplate="ToolBoxtemplate">
</Toolbox> 

Я использую инфраструктуру сущностей ADO.NET для подключения к базе данных. Код позади:

SystemicsAnalystDBEntities db = new SystemicsAnalystDBEntities();

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    NewLibrary.ItemsSource = from c in db.Components select c;
}

Однако есть проблема. Когда код выполняется, он отображает объект из базы данных (поскольку свойство ItemSource установлено для объекта из базы данных), а не изображения. Он не использует шаблон. Когда я использую источник статических изображений, он работает правильно

Я обнаружил, что мне нужно переопределить метод PrepareContainerForItemOverride. Но я не знаю, как добавить в него шаблон.

Большое спасибо за любые комментарии.

Дополнительная информация

Вот шаблон ControlTemplate для ToolboxItem:

         <ControlTemplate TargetType="{x:Type s:ToolboxItem}"> 
            <Grid> 
                <Rectangle Name="Border" 
                           StrokeThickness="1" 
                           StrokeDashArray="2" 
                           Fill="Transparent" 
                           SnapsToDevicePixels="true" /> 
                <ContentPresenter Content="{TemplateBinding ContentControl.Content}" 
                                  Margin="{TemplateBinding Padding}" 
                                  SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" /> 
            </Grid> 
            <ControlTemplate.Triggers> 
                <Trigger Property="IsMouseOver" 
                         Value="true"> 
                    <Setter TargetName="Border" 
                            Property="Stroke" 
                            Value="Gray" /> 
                </Trigger> 
            </ControlTemplate.Triggers> 
        </ControlTemplate>

Ответы [ 4 ]

3 голосов
/ 11 марта 2010

ToolboxItem переопределяет стиль по умолчанию для ContentControl. Вы не опубликовали переопределяющий стиль (из generic.xaml), но я подозреваю, что ваша проблема связана с шаблоном, определенным в этом стиле. Ваш шаблон ToolboxItem должен содержать ContentPresenter, например ::

<Style TargetType="{x:Type local:ToolboxItem}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type local:ToolboxItem}">
        <Border Background="{TemplateBinding Background}"
                BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="{TemplateBinding BorderThickness}">
          <ContentPresenter />
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

В качестве альтернативы, если вам не нужно делать ничего особенного в пользовательском интерфейсе ToolboxItem, просто удалите вызов DefaultStyleKeyProperty.OverrideMetadata.

Обратите внимание, что не необходимо переопределить PrepareItemForContainerOverride.

1 голос
/ 11 марта 2010

Вы правильно реализовали методы. Проблема, как я и подозревал, в вашем ToolBoxItem ControlTemplate, который вы недавно опубликовали. Если бы он использовал обычный <ContentPresenter />, с вами все было бы в порядке. Вы столкнулись с «волшебными» свойствами ContentPresenter, которые устанавливаются автоматически, только если вы не установили ни одно из них.

Вот код проблемы в вашем ControlTemplate:

<ContentPresenter
  Content="{TemplateBinding ContentControl.Content}"  
  Margin="{TemplateBinding Padding}"  
  SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />

Проблема в том, что вы устанавливаете свойство Content, но не устанавливаете свойство ContentTemplate. ContentPresenter имеет пользовательский код, который автоматически создает привязки для его свойств Content, ContentTemplate и ContentTemplateSelector, но , только если свойство Content не установлено вручную.

В вашем случае свойство Content устанавливается вручную, поэтому автоматический механизм отключен и поэтому ContentTemplate имеет значение null.

Хотя можно было бы вручную установить все три автоматических свойства следующим образом:

<ContentPresenter
  Content="{TemplateBinding Content}"  
  ContentTemplate="{TemplateBinding ContentTemplate}"
  ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
  Margin="{TemplateBinding Padding}"  
  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />

Ваш лучший выбор - полностью их опустить и просто принять поведение ContentPresenter по умолчанию, например:

<ContentPresenter
  Margin="{TemplateBinding Padding}"  
  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />

Примечание. В NET Framework 3.5 добавлено новое автоматически связанное свойство, ContentStringFormat, которое будет пропущено, если вы вручную ограничите три свойства, а не позволите ContentPresenter сделать это автоматически.

0 голосов
/ 11 марта 2010

Похоже, что ваша проблема может заключаться в том, что ваше свойство url не отображается в ToolBoxItem. Когда ваши элементы связаны напрямую с ToolBox, свойство url напрямую предоставляется DataTemplate.

Чтобы ваш пример работал, ToolBoxItem должен иметь:

public ImageTypeHere url { get; private set; }

Если это действительно простая реализация, вам, вероятно, будет выгоднее использовать (или, по крайней мере, наследовать) ListBox и использовать пользовательские DataTemplate и Style для своих ListBoxItems вместо создания собственного элемента управления.

0 голосов
/ 10 марта 2010

Этот код напрямую скопирован из вашего проекта? Если так, то следующее

ItemTemplate="ToolBoxtemplate"

должно быть:

ItemTemplate="{StaticResource ToolBoxTemplate}"

Я не совсем уверен, но вам может понадобиться явно установить ContentTemplate вашего контейнера Toolbox в PrepareContainerForItemOverride, поскольку вы, возможно, изменили поведение, которое автоматически устанавливает шаблон. Возможно, вам придется установить его как Binding, так как я не уверен, что контейнеры будут заново сгенерированы при изменении ItemTemplate.

...