【问题标题】:Replacing DependencyProperty by AttachedProperty in class hierarchy - is that possible?用类层次结构中的附加属性替换依赖属性 - 这可能吗?
【发布时间】:2017-04-22 18:23:10
【问题描述】:

我希望我的一些 ButtonToggleButtonRadioButton 具有 Geometry 属性,以便我可以在 ControlTemplates 中使用以避免在将特定于实例的几何图形分配给这些控件时避免样板。

例如,目前我可以这样写:

<my:GeometryButton Geometry="{StaticResource OneGeometry}"/>
<my:GeometryButton Geometry="{StaticResource OtherGeometry}"/>

<!-- ...and inside the Style for GeometryButton: -->
<ContentControl TargetType="{x:Type my:GeometryButton}">
    <Border>
        <Path Data={TemplateBinding Geometry}/>
    </Border>
</ContentControl>

使用这个 GeometryButton 类:

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


    public Geometry Geometry
    {
        get { return (Geometry)GetValue(GeometryProperty); }
        set { SetValue(GeometryProperty, value); }
    }

    public static readonly DependencyProperty GeometryProperty =
        DependencyProperty.Register("Geometry",
                                    typeof(Geometry), 
                                    typeof(GeometryButton), 
                                    new PropertyMetadata(default(Geometry)));

}

问题是,如果我要定义 GeometryToggleButtonGeometryRadioButton 类,我应该在每个类中重复 DependencyProperty 代码,违反 DRY。 另外,由于 RadioButton 派生自 ToggleButton,而后者和 Button 又派生自 ButtonBase,我想我可以利用这一点,但如果我需要分别从每个类继承,我根本不会从继承中受益。

所以我考虑使用AttachedProperties,但是教程和示例中通常会提到DockPanel.DockGrid.LeftControl.Foreground之类的示例,暗示存在一些“Parent”,所以我不确定:

  • AttachedProperties 概念是否首先适用于我的用例?
  • 如果是,我应该如何实施?

【问题讨论】:

    标签: c# wpf xaml dependency-properties attached-properties


    【解决方案1】:

    创建一个常规的附加属性。在您的控件模板中,使用它。

    不严重,没有比这更多的了。

    例如,我编写了一个附加的CornerRadius 属性,以便许多不同的控件样式可以指定一个CornerRadius,它们的模板将使用该CornerRadius

    public static class Attached
    {
        public static readonly DependencyProperty CornerRadiusProperty
                = DependencyProperty.RegisterAttached(
                    "CornerRadius",
                    typeof(CornerRadius), 
                    typeof(Attached),
                    new FrameworkPropertyMetadata(
                        new CornerRadius(0), 
                        FrameworkPropertyMetadataOptions.AffectsRender 
                            | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, 
                        PropertyChanged)
                    );
    
        public static CornerRadius GetCornerRadius(DependencyObject uie)
        {
            return (CornerRadius)uie.GetValue(CornerRadiusProperty);
        }
    
        public static void SetCornerRadius(DependencyObject uie, CornerRadius value)
        {
            uie.SetValue(CornerRadiusProperty, value);
        }
    }
    

    XAML

    注意 Binding(edcorpext:Attached.CornerRadius) 周围的括号很关键,因此它理解字符串是一个不可分割的路径段,指的是附加属性;否则,它会尝试将其解析为Binding.Source 属性的路径,命中:,并引发异常。

    <ControlTemplate x:Key="EdCorpButtonTemplate" TargetType="{x:Type Button}">
        <Grid>
            <Border 
                x:Name="PART_BackgroundBorder"
                CornerRadius="{Binding (edcorpext:Attached.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}"
                BorderThickness="1.3"
                BorderBrush="{StaticResource ControlBorderBrush}"
                Background="{StaticResource EdCorpGrayMediumGradientBrush}"
                SnapsToDevicePixels="True"
                />
            <!-- etc. etc. etc. -->
    
    <Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
        <Setter Property="edcorpext:Attached.CornerRadius" Value="{StaticResource ButtonCornerRadius}" />
        <Setter Property="Template" Value="{StaticResource EdCorpButtonTemplate}" />
    
        <!-- etc. etc. etc. -->
    

    他们告诉我,我们需要这个应用程序的 UI 看起来“更现代”,因为我们没有真正的设计师知道他在做什么,所以我在东西上设置了不对称的圆角。之前的情况其实差了很多。

    【讨论】:

    • 有趣!您认为通过您提供的实现可以直接在按钮实例中声明 CornerRadius 吗?例如&lt;Button CornerRadius="{StaticResource SmallRadius}"/&gt;&lt;Button CornerRadius="{StaticResource LargeRadius}"/&gt; ?
    • @heltonbiker &lt;Button edcorpext:Attached.CornerRadius="{StaticResource LargeRadius}"/&gt;。就像任何依赖属性一样。这就是它的美丽!使用相同的机制。模板获取值(也就是说,如果它请求它,它当然会获取它)。
    • 好的,试试看并发表一些反馈!谢谢!
    • @heltonbiker 酷。小心你给Binding.Path的东西;它需要括号来理解ns:ClassName.PropName 是一个指示附加属性的标识符。
    猜你喜欢
    • 1970-01-01
    • 2020-09-10
    • 2015-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多