我正在创建一个派生自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方法。但我不知道如何将模板添加到它。
非常感谢任何评论。
其他信息
以下是ToolboxItem的ControlTemplate:
<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>
答案 0 :(得分:3)
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 UI中执行任何特殊操作,只需删除DefaultStyleKeyProperty.OverrideMetadata
来电。
请注意,您不需要覆盖PrepareItemForContainerOverride。
答案 1 :(得分:1)
您已正确实施这些方法。正如我所怀疑的,问题在于您最近发布的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
为空。
虽然可以手动设置所有三个自动属性,如下所示:
<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自动为您执行此操作,则会遗漏该属性。
答案 2 :(得分:0)
此代码是否直接从您的项目中复制?如果是这样,以下
ItemTemplate="ToolBoxtemplate"
应该是:
ItemTemplate="{StaticResource ToolBoxTemplate}"
我不完全确定,但您可能需要在PrepareContainerForItemOverride中显式设置Toolbox容器的ContentTemplate,因为您可能已经覆盖了自动设置模板的行为。您可能需要将其设置为Binding,因为我不确定在ItemTemplate更改时是否重新生成容器。
答案 3 :(得分:0)
看起来您的问题可能是您的url属性未在ToolBoxItem中公开。当您的项直接绑定到ToolBox时,url属性将直接暴露给DataTemplate。
为了使您的示例有效,ToolBoxItem需要具有:
public ImageTypeHere url { get; private set; }
如果这实际上是一个简单的实现,那么使用(或至少从中派生)ListBox并为ListBoxItems使用自定义DataTemplate和Style而不是创建自己的控件可能会让您受益更多。