【问题标题】:Custom control's properties not changing when used in a template在模板中使用时自定义控件的属性不会改变
【发布时间】:2013-08-26 19:44:59
【问题描述】:

我创建了一个自定义控件(继承控件),它公开了一个枚举的 DependencyProperty。默认控件模板根据使用触发器打开/关闭元素的属性的选定值以不同方式呈现。该控件在直接放入 UserControl 以在 UI 中查看时效果很好。但是,该控件的要点是作为大型复合控件的一部分存在,因此它也用于另一个自定义控件的 ControlTemplate。当我这样做时,控件无法识别对依赖属性的更改。我通过向依赖属性添加一个 PropertyChangedCallback 并设置一个永远不会命中的断点来验证这一点。

例如,当我在这样的模板中使用“CustomControl”时:

<ControlTemplate>
    <my:CustomControl EnumProperty="EnumValue" />
</ControlTemplate>

EnumProperty(它是一个 DependencyProperty)没有更改为“EnumValue”,它仍然是默认值。而且,正如我所说,DP 的 PropertyChangedCallback 中的断点永远不会被调用。

我错过了什么?

更新

这是我的控件的清理版本:

public class CustomControl : Control
{
    static CustomControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl), new FrameworkPropertyMetadata(typeof(CustomControl)));
    }

    public StandardIcon()
        : base()
    {
        BorderType = BorderType.None;
    }

    public static readonly DependencyProperty BorderTypeProperty = DependencyProperty.Register("BorderType", typeof(BorderType), typeof(CustomControl), new PropertyMetadata(BorderType.None));

    public BorderType BorderType
    {
        get { return (BorderType)GetValue(BorderTypeProperty); }
        set { SetValue(BorderTypeProperty, value); }
    }
}


<Style TargetType="{x:Type local:CustomControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:CustomControl}">
                <Border x:Name="Rectangle"
                        BorderBrush="{TemplateBinding Foreground}"
                        BorderThickness="0"
                        HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch">
                    <ContentPresenter ContentSource="Content" />
                </Border>

                <ControlTemplate.Triggers>
                    <Trigger Property="BorderType" Value="Rectangle">
                        <Setter Property="BorderThickness" TargetName="Rectangle" Value="2" />
                    </Trigger>
                    <Trigger Property="BorderType" Value="RoundedRectangle">
                        <Setter Property="BorderThickness" TargetName="Rectangle" Value="2" />
                        <Setter Property="CornerRadius" TargetName="Rectangle" Value="5" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

这就是它在另一个控件中的使用方式(请注意,它在 DataTemplate 中,而不是我最初指出的 ControlTemplate 中)。

<Style TargetType="{x:Type local:OtherControl}">
    <Setter Property="FontFamily" Value="{x:Static theme:StandardFonts.FontFamily}" />
    <Setter Property="FontSize" Value="{x:Static theme:StandardFonts.FontSizeXS}" />
    <Setter Property="FontWeight" Value="Bold" />
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <local:CustomControl BorderType="{Binding TemplatedParent.BorderType, RelativeSource={RelativeSource TemplatedParent}}"
                                     Foreground="{Binding TemplatedParent.Foreground, RelativeSource={RelativeSource TemplatedParent}}" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

然后是这样使用的:

<controls:OtherControl Foreground="Red" BorderType="Rectangle" />

Foreground 属性正在按预期变化。当我更改 OtherControl 的 Foreground 时,CustomControl 的 Foreground 会更改。但是没有遵守 BorderType 属性 - 它始终使用默认的 BorderType.None 值呈现。

【问题讨论】:

    标签: wpf wpf-controls wpf-4.0


    【解决方案1】:

    您的 ControlTemplate 的父级需要为您的 CustomControl 绑定一些东西。然后,将模板中的 CustomControl 绑定到父级。

    在以下示例中,我使用 Border 来模板化一个 Button,它将其 BorderBrush 绑定到 Button 的背景:

    <ControlTemplate TargetType="{x:Type Button}">
        <Border BorderBrush="{TemplateBinding Background}" />
    </ControlTemplate>
    

    将 Button 替换为您的“大型复合控件”,将 Border 替换为 my:CustomControl,您应该已设置...

    【讨论】:

    • 查看我的更新,我相信我已经在按照您的建议进行操作了。不同之处在于我发现我们在 DataTemplate 中使用控件而不是 ControlTemplate(在这种情况下)。不知道这有什么不同。
    • 您的 CustomControl 绑定到 TemplatedParent 的 TemplatedParent 的 BorderType。我猜你的 Foreground 发生了变化,因为该父控件具有一个 Foreground 属性,该属性会传播给它的子控件。尝试删除“TemplatedParent”。在绑定路径的开头...
    • 不幸的是,RelativeSource 实际上解析为 ContentPresenter,因此是第二个“跃点”。当我从绑定路径的开头删除“TemplatedParent”时,我在“输出”窗口中收到以下错误:BindingExpression path error: 'BorderType' property not found on 'object' ''ContentPresenter'
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多