在进行Binding的时候,如果能够明确到数据源属性的Path(Name),就可用Source、ElementName进行指定,但是有时候需要绑定的数据源可能没有明确的Path(Name),此时就需要利用Binding对象的RelativeSource属性来进行绑定源属性的指定,说白了,就是指定当前绑定目标与绑定源树状结构下的层级关系,relative to the position of the binding target.

Binding对象的RelativeSource的属性是RelativeSource类型的,不妨看看它的定义

//     relative to the position of the binding target.
[MarkupExtensionReturnType(typeof(RelativeSource))]
    public class RelativeSource : MarkupExtension, ISupportInitialize
{
        //     Initializes a new instance of the System.Windows.Data.RelativeSource class.
        public RelativeSource();
        //     One of the System.Windows.Data.RelativeSourceMode values.
        public RelativeSource(RelativeSourceMode mode);
        //     One of the System.Windows.Data.RelativeSourceMode values. For this signature
        //     to be relevant, this should be System.Windows.Data.RelativeSourceMode.FindAncestor.
        //
        //   ancestorType:
        //     The System.Type of ancestor to look for.
        //
        //   ancestorLevel:
        //     The ordinal position of the desired ancestor among all ancestors of the given
        //     type.
        public RelativeSource(RelativeSourceMode mode, Type ancestorType, int ancestorLevel);
        //     A static System.Windows.Data.RelativeSource.
        public static RelativeSource PreviousData { get; }
        //     A static System.Windows.Data.RelativeSource.
        public static RelativeSource Self { get; }
        //     A static System.Windows.Data.RelativeSource.
        public static RelativeSource TemplatedParent { get; }
        //     The ancestor level. Use 1 to indicate the one nearest to the binding target element.
        public int AncestorLevel { get; set; }
        // 摘要:
        //     Gets or sets the type of ancestor to look for.
        //
        // 返回结果:
        //     The type of ancestor. The default value is null.
        public Type AncestorType { get; set; }
        //     Gets or sets a System.Windows.Data.RelativeSourceMode value that describes the
        //     location of the binding source relative to the position of the binding target.
        [ConstructorArgument("mode")]
        public RelativeSourceMode Mode { get; set; }
        //     Returns an object that should be set as the value on the target object's property
        //     for this markup extension. For System.Windows.Data.RelativeSource, this is another
        //     System.Windows.Data.RelativeSource, using the appropriate source for the specified
        public override object ProvideValue(IServiceProvider serviceProvider);
        //     true if the property value has changed from its default; otherwise, false.
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeAncestorLevel();
        //     true if the property value has changed from its default; otherwise, false.
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeAncestorType();
}

1. 绑定源是自己 Self

说明绑定源是自身,需要完成的需求是将自身的一个属性绑定到另外一个属性,绑定源与绑定目标都是自己,使用中的绑定目标属性必须是DependencyProperty,重要的事情多说一次,虽然WPF控件中的属性基本都是依赖属性,但是也不排除我们自己开发了控件有些属性不是依赖属性的情况。

比如我们将textBox2的目标属性TextProperty绑定到它的Name属性(源属性)

  • 后台代码的方式

    textBox2.SetBinding(TextBox.TextProperty, new Binding()
    {
        RelativeSource = new RelativeSource()
        {
            Mode = RelativeSourceMode.Self,
        },
        Path = new PropertyPath("Name")
    });
    
  • 前台xaml的方式

    <TextBox x:Name="textBox2" Text="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Name}" MinWidth="120" Margin="5"/>
    

    哦豁,有没有发现后台代码中是和绑定定义的4个元素(绑定源、绑定源属性、绑定目标、绑定目标属性)是一致的TextBox.TextProperty这个依赖属性,那么为什么xaml中绑定目标属性的写法的Text呢?猜想这个与MarkupExtension有关,这里的内容就不讲解了。

    思考:通过xaml的绑定写法发现”{}”这个花括号代表了一个对象实列而紧随”{“的是类型名,”{Binding RelativeSource={RelativeSource Mode=Self}, Path=Name}”其中没有加粗的RelatvieSource是Binding对象的属性名,这里是通过观察到的现象,当然清楚这个原理写xaml的时候也会是一个有据可循的依据。

2. 绑定源是父级容器 FindAncestor

说明绑定源是当前绑定目标的父级容器,可以指定明确的父容器的类型或层级关系,查找的顺序是由近到远。

  • 后台代码的方式

    tbFindAncestor.SetBinding(TextBox.TextProperty, new Binding()
    {
        RelativeSource = new RelativeSource()
        {
            Mode = RelativeSourceMode.FindAncestor,
            AncestorType = typeof(WrapPanel),
            //AncestorLevel = 1
        },
        Path = new PropertyPath("Name")
    });
    
  • 前台xaml的方式

    <WrapPanel x:Name="WrapPanelName">
        <Border BorderThickness="1" BorderBrush="Blue">
            <TextBox x:Name="tbFindAncestor" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type WrapPanel}}, Path=Name}" MinWidth="120"/>
        </Border>
    </WrapPanel>
    

    可以看到AncestorLevel的值可以不需要提供,没有指定它会使用节点上最近的对象作为绑定源,另外通过后台代码与xaml的比较,xaml的可视化会更好一些,在vs中可以展示绑定完成后的数据展示,但是代码的方式有助于对概念上的理解以及对于MarkupExtension的理解。

    注意:AncestorLevel指的是以Bingding目标控件为起点的层级偏移量,Border的偏移量是1,WrapPanel的偏移量是2, AncestorType指的是要找的目标对象的类型,AncestorLevel必须参考AncestorType使用,比如设置了AncestorType={x:Type WrapPanel},则Bingding在寻找时会忽略非WrapPanel的控件,此时WrapPanel的偏移量是1,Border不是WrapPanel类型所以被忽略

3. 绑定源是先前的对象 PreviousData

PreviousData使用较少,它用于特定的情况;这里先不做详细的介绍,后面碰到合适的用例时再补充。

4. 绑定源是关联的模板属性 TemplatedParent

注意我们这里说的是ControlTemplate不是DataTemplate,这里讲解”{Binding RelativeSource={RelativeSource Mode=TemplatedParent}”,主要的用途是我们编写了一个ControlTemplate需要在这个ControlTemplate中使用应用这个ControlTemplate的控件的属性值的情况,比如在ControlTemplate将应用模板的控件作为绑定源给ControlTemplate中的设计元素的属性绑定,可以是原始已经有的属性,也可以是没有需要去扩展控件的;另外也可以通过代码的方式获取ControlTemplate中设计的控件元素(var control = YourControl.Template.FindName("elementControl", YourControl;所以这里对于控件自定义、或者对已控件做形态表现上的修改是很重要的。

  • 下面为Button定义一个圆形的ControlTemplate,使用TemplatedParent的绑定让ControlTemplate中的Ellipse的FillProptery等于使用这个ControlTemplate的Background属性作为绑定源的属性

    <Button Width="64" Height="64" Content="Ellipse" Background="OrangeRed">
        <Button.Template>
            <ControlTemplate TargetType="Button">
                <Grid>
                    <Ellipse Fill="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Background}"/>
                    <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/>
                </Grid>
            </ControlTemplate>
        </Button.Template>
    </Button>
    

注意:这里是为了讲解TemplatedParent的使用方式,实际上处理上述需要可以简单的写成<Ellipse Fill="{TemplateBinding Background}"/>;是不是比<Ellipse Fill="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Background}"/>简化了很多, 它们表示的意思是一样的。

原文地址:http://www.cnblogs.com/linxmouse/p/16848155.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性