WPF:创建自定义控件时如何正确重写方法

发布于 2024-08-25 01:01:34 字数 2658 浏览 4 评论 0原文

我正在创建一个派生自 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>

I am creating a custom control Toolbox that is derived from ItemsControl. This toolbox is supposed to be filled with icons coming from the database. The definition looks like this:

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

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

Toolboxitem is derived from ContentControl.

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

Since the number of icons stored in a database is not known I want to use the data template:

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

Then I want the Toolbox to use the template.

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

I'm using ADO.NET entity framework to connect to a database. The code behind:

SystemicsAnalystDBEntities db = new SystemicsAnalystDBEntities();

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

However, there is a problem. When the code is executed, it displays the object from the database (as the ItemSource property is set to the object from the database) and not the images. It does not use the template. When I use the static images source it works in the right way

I found out that I need to override the PrepareContainerForItemOverride method.But I don't know how to add the template to it.

Thanks a lot for any comments.

Additional Information

Here is the ControlTemplate for 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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

滴情不沾 2024-09-01 01:01:34

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。

ToolboxItem is overriding the default style for ContentControl. You haven't posted the overridding style (from generic.xaml), but I suspect your problem is with the template defined in that style. Your ToolboxItem template needs to contain a ContentPresenter, e.g.:

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

Alternatively, if you don't need to do anything special in the ToolboxItem UI, just remove the DefaultStyleKeyProperty.OverrideMetadata call.

Note that you do not need to override PrepareItemForContainerOverride.

瑾兮 2024-09-01 01:01:34

您已经正确实施了这些方法。正如我怀疑的那样,问题出在您最近发布的 ToolBoxItem ControlTemplate 中。如果它使用普通的 就可以了。您遇到了 ContentPresenter 的“神奇”属性,这些属性只有在您不设置任何属性时才会自动设置。

以下是 ControlTemplate 中的问题代码:

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

问题在于您正在设置 Content 属性,但未设置 ContentTemplate 属性。 ContentPresenter 具有自定义代码,可自动为其 ContentContentTemplateContentTemplateSelector 属性创建绑定,但仅当 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 自动为您绑定,则会丢失该属性。

You have correctly implemented the methods. The problem is, as I suspected, in your ToolBoxItem ControlTemplate which you posted recently. If it had used an ordinary <ContentPresenter /> you would have been fine. You ran into ContentPresenter's "magic" properties which are only set automatically if you don't set any of them.

Here is the problem code in your ControlTemplate:

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

The problem is that you are setting the Content property but not setting the ContentTemplate property. ContentPresenter has custom code that automatically creates bindings for its Content, ContentTemplate, and ContentTemplateSelector properties, but only if the Content property is not set manually.

In your case, the Content property is being set manually, so the automatic mechanism is disabled and so ContentTemplate is null.

Although it would be possible to manually set all three automatic properties like this:

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

Your best choice is to omit them entirely and just accept ContentPresenter's default behavior, like this:

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

Note: NET Framework 3.5 adds a fouth automatically-bound property, ContentStringFormat, which would be missed if you manually bound the three properties instead of letting ContentPresenter do it for you automatically.

情深已缘浅 2024-09-01 01:01:34

这个代码是直接从你的项目中复制的吗?如果是这样,则

ItemTemplate="ToolBoxtemplate"

应该是:

ItemTemplate="{StaticResource ToolBoxTemplate}"

我不完全确定,但您可能需要在PrepareContainerForItemOverride中显式设置工具箱容器的ContentTemplate,因为您可能已经覆盖了自动设置模板的行为。您可能需要将其设置为 Binding,因为我不确定如果 ItemTemplate 发生更改,是否会重新生成容器。

Is this code directly copied from your project? If so, the following

ItemTemplate="ToolBoxtemplate"

should be:

ItemTemplate="{StaticResource ToolBoxTemplate}"

I'm not entirely sure, but you might need to set the ContentTemplate of your Toolbox container explicitly in PrepareContainerForItemOverride, since you may have overridden the behavior that automatically sets the template. You may need to set it as a Binding, as I'm not sure if the containers are re-generated if the ItemTemplate changes.

聽兲甴掵 2024-09-01 01:01:34

看来您的问题可能是您的 url 属性未在 ToolBoxItem 中公开。当您的项目直接绑定到 ToolBox 时,url 属性将直接暴露给 DataTemplate。

为了使您的示例正常工作,ToolBoxItem 需要具有:

public ImageTypeHere url { get; private set; }

如果这确实是一个简单的实现,那么使用(或至少派生自)ListBox 并为 ListBoxItems 使用自定义 DataTemplate 和样式可能会给您带来更多好处,而不是创建您自己的控件。

It looks like your problem could be that your url property is not exposed within ToolBoxItem. When your items are bound directly to ToolBox the url property is directly exposed to the DataTemplate.

In order for your example to work, ToolBoxItem would need to have:

public ImageTypeHere url { get; private set; }

If this is really a simple implementation it would probably benefit you more to use (or at least derive from) a ListBox and use a custom DataTemplate and Style for your ListBoxItems rather than creating your own control.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文