如何使用Child-deined Attached Properties?

Cla*_*law 5 wpf dependency-properties attached-properties


1. 问题

我们知道,Attached Property在wpf中广泛扩展了属性系统.但是我们熟悉的所有示例几乎都是父对象的,例如DockPanel.Dock/Grid.Row等.但是在MSDN中查看文档之后,我发现其他一些附属物的用法:

从MSDN:附加属性概述/如何使用附加属性由拥有类型

1.定义附加属性的类型被设计为使得它可以是将为附加属性设置值的元素的父元素.然后,类型通过内部逻辑对某些对象树结构迭代其子对象,获取值,并以某种方式对这些值进行操作.(母公司定义)

2.定义附加属性的类型将用作各种可能的父元素和内容模型的子元素.(儿童定义)

3.定义附加属性的类型表示服务.其他类型设置附加属性的值.然后,当在服务的上下文中评估设置属性的元素时,通过服务类的内部逻辑获得附加属性值.(用作公共服务)


2.试用

由于附加属性可以由用户定义,我认为也许我们可以使用"CallBackMethod"来处理它.所以我编写了一些试验以验证我的想法(第4.部分代码):

1.自定义一个子控件("Son"),它定义了一个名为"CellBorderThicknessProperty"的附加属性,并使用"PropertyChangedCallBack"来更新布局;

2.创建一个父控件("父"),其模板包含子控件.

3.在Window中使用父控件并设置child.CellBorderThickness的值;


3.问题

1.如你所见,在"儿童类型"中暴露"父类型"并不是一个好方法,特别是我们不会有多少父母会...

2.本试验没有奏效,'当"PropertyChangedCallBack"被解雇时,父亲的模板尚未应用!所以,Father.SetBorderThickness()将什么都不做!

是否有任何使用Child-Defined附属财产的例子?它是如何运作的?

我非常渴望了解MS开发人员如何处理Child-Defined问题.

例如:WPFToolkit中的ScrollViwer.VerticalScrollBarVisibility:DataGrid


4.代码

儿子控制(儿童)

<Style TargetType={x:Type Son}>
   <Setter Property="Template">
     <Setter.Value>
       <ControlTemplate>
         <Border BorderThickness={TemplateBinding CellBorderThickness}>
           ...
         </Border>
       </ControlTemplate>
     <Setter.Value>
   </Setter>
Run Code Online (Sandbox Code Playgroud)

 public class Son: Control
 {
      public static readonly DependencyProperty CellBorderThicknessProperty = DependencyProperty.RegisterAttached("CellBorderThickness", typeof(Thickness), typeof(Son), new FrameworkPropertyMetadata(new Thickness(0.2), FrameworkPropertyMetadataOptions.AffectsRender, CellBorderThicknessProperty_ChangedCallBack));

      public static void SetCellBorderThickness(UIElement obj, Thickness value)
      {
        obj.SetValue(Son.CellBorderThicknessProperty, value);
      }

      public static Thickness GetCellBorderThickness(UIElement obj)
      {
        return (Thickness)obj.GetValue(Son.CellBorderThicknessProperty);
      }

      public Thickness CellBorderThickness
      {
        //With this, CellBorderThickness can be used as a normal dependency property.
        get { return (Thickness)GetValue(CellBorderThicknessProperty); }
        set { SetValue(CellBorderThicknessProperty, value); }
      }

      static void CellBorderThicknessProperty_ChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
      {
        if ((d as Father) != null)
        {
            // Try to update the Son's CellBorderThickness which is the child element of  the Father.
            d.SetBorderThickness(e.NewValue);
        }
      }
 }
Run Code Online (Sandbox Code Playgroud)

父亲控制(父母)

 <Style TargetType={x:Type Father}>
   <Setter Property="Template">
     <Setter.Value>
       <ControlTemplate>
         <Border>
           <Son></Son>
         </Border>
       </ControlTemplate>
     <Setter.Value>
   </Setter>
Run Code Online (Sandbox Code Playgroud)

 public class Father:Control
 {
   private Son childControl;

   public void override OnApplyTemplate()
   {
     childControl=(Son)GetTemplateChild("PART_ChildControl");//Here is a problem!!
   }

   public void SetBorderThickness(Thickness value)
   {
     if(childControl==null)
       childControl.CellBorderThickness=value;
   }
 }
Run Code Online (Sandbox Code Playgroud)

窗口

 <Window>
   <Grid>
     <Father Son.CellBorderThichness="5"></Father>
   </Grid>
 <Window>
Run Code Online (Sandbox Code Playgroud)

Ana*_*aev 5

我把你的例子作为基础,删除了一点,并得到了这个例子.我删除它们以显示最小的工作示例.

首先,我删除了CellBorderThickness属性,因为已经附加了依赖属性.

Son

// Removed
public Thickness CellBorderThickness
{
    get { return (Thickness)GetValue(CellBorderThicknessProperty); }
    set { SetValue(CellBorderThicknessProperty, value); }
}
Run Code Online (Sandbox Code Playgroud)

在我父亲的控件中我删除了OnApplyTemplate(),并在函数中SetBorderThickness()使用附加依赖属性的机会来设置值:

Father

// Removed
OnApplyTemplate() { ... }

// Add
Son.SetCellBorderThickness(childControl, value);
Run Code Online (Sandbox Code Playgroud)

以下是一个完整的例子.结构示例:

在此输入图像描述

XAML

Styles

儿子

<Style TargetType="{x:Type SonNamespace:Son}">
    <Setter Property="Background" Value="Gainsboro" />
    <Setter Property="BorderBrush" Value="Black" />
    <Setter Property="Width" Value="100" />
    <Setter Property="Height" Value="100" />
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="HorizontalContentAlignment" Value="Center" />
    <Setter Property="VerticalContentAlignment" Value="Center" />

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate>
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding SonNamespace:Son.CellBorderThickness}">

                    <ContentPresenter Content="I'am a Son" 
                                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
Run Code Online (Sandbox Code Playgroud)

父亲

<Style TargetType="{x:Type FatherNamespace:Father}">
    <Setter Property="Background" Value="AliceBlue" />
    <Setter Property="BorderBrush" Value="Black" />
    <Setter Property="Width" Value="100" />
    <Setter Property="Height" Value="100" />
    <Setter Property="HorizontalAlignment" Value="Right" />
    <Setter Property="HorizontalContentAlignment" Value="Center" />
    <Setter Property="VerticalContentAlignment" Value="Center" />

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate>
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding SonNamespace:Son.CellBorderThickness}">

                    <ContentPresenter Content="I'am a Father" 
                                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
Run Code Online (Sandbox Code Playgroud)

主窗口

<Grid>
    <SonNamespace:Son />

    <FatherNamespace:Father SonNamespace:Son.CellBorderThickness="6" />
</Grid>
Run Code Online (Sandbox Code Playgroud)

Code

儿子

public class Son : Control
{
    public static readonly DependencyProperty CellBorderThicknessProperty =
                                              DependencyProperty.RegisterAttached("CellBorderThickness",
                                              typeof(Thickness), typeof(Son),
                                              new FrameworkPropertyMetadata(new Thickness(2),
                                                                            FrameworkPropertyMetadataOptions.AffectsRender,
                                                                            CellBorderThicknessProperty_ChangedCallBack));

    public static void SetCellBorderThickness(UIElement obj, Thickness value)
    {
        obj.SetValue(Son.CellBorderThicknessProperty, value);
    }

    public static Thickness GetCellBorderThickness(UIElement obj)
    {
        return (Thickness)obj.GetValue(Son.CellBorderThicknessProperty);
    }

    private static void CellBorderThicknessProperty_ChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Father father = d as Father;

        if (father != null)
        {
            father.SetBorderThickness((Thickness)e.NewValue);
        }
    }
}    
Run Code Online (Sandbox Code Playgroud)

父亲

public class Father : Control
{
    private Son childControl; 

    public void SetBorderThickness(Thickness value)
    {
        if (childControl != null)
        {
            Son.SetCellBorderThickness(childControl, value);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Output

在此输入图像描述

项目可在此链接中找到.