Silverlight中Binding属性RelativeSource

本文介绍如何在XAML中使用RelativeSource指定binding的source和target之间的位置关系,包括Self、TemplatedParent和FindAncestor三种模式,并通过一个具体的案例展示其在datagrid模板中的应用。

本文github:https://github.com/kiwiwin/silverlight-demo,文件夹:domain-service-duplex-by-auto-refresh-demo


RelativeSource可以用来指定binding的source和binding的target之间的位置关系。

RelativeSource的三种模式:

1.Self模式

目标元素应用作此绑定的源。当要将元素的一个属性绑定到同一元素的另一个属性时,上述这点很有用。

<object property="{Binding RelativeSource={RelativeSource Self} ...}" .../>


2.TemplatedParent模式

在其中应用 ControlTemplate 的控件是此绑定的源。这一点可用来在模板级别应用绑定中的验证错误信息。

<object property="{Binding RelativeSource={RelativeSource TemplatedParent} ...}" .../>


3.FindAncestor模式

无论何时使用FindAncestor模式,通常会指定AncestorType的值。如果树遍历中存在多义性,可指定一个AncestorLevel。

<object property="{Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=typeNameString, AncestorLevel=levelInt} ...}" .../>


备注:

在绑定中,Source、RelativeSource 和 ElementName是相互排斥的。如果已设置这些属性中的一种,则在绑定中设置其他两种属性的任何一种(通过 XAML 或代码)将导致异常。

例:

我们期望datagrid中的template column中的Button随着State的改变而改变是否为Enabled,同时对比datagrid外的一个Test Button在binding时与datagrid中的button的区别

MainPage.xaml

<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
 x:Class="binding_to_relative_source.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300"
 d:DesignWidth="400">

 <Grid x:Name="LayoutRoot" Background="White">
 <Button Content="Change" Click="ChangeButton_OnClick" Width="300" Height="30" VerticalAlignment="Top"/>
 <Button Content="Test" IsEnabled="{Binding State}" Width="300" Height="30" VerticalAlignment="Top" Margin="0,40,0,0"/>
 <sdk:DataGrid Name="kiwiDataGrid" AutoGenerateColumns="False" Width="300" Height="200" VerticalAlignment="Top" Margin="0,80,0,0">
 <sdk:DataGrid.Columns>
 <sdk:DataGridTextColumn Binding="{Binding Name}" Width="150"/>
 <sdk:DataGridTemplateColumn>
 <sdk:DataGridTemplateColumn.CellTemplate>
 <DataTemplate>
 <Button Content="Dummy Button" IsEnabled="{Binding State, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
 </DataTemplate>
 </sdk:DataGridTemplateColumn.CellTemplate>
 </sdk:DataGridTemplateColumn>
 </sdk:DataGrid.Columns>
 </sdk:DataGrid>
 </Grid>
</UserControl>

MainPage.xaml.cs

  public partial class MainPage : UserControl, INotifyPropertyChanged
    {
        public bool State { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;

        public void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public MainPage()
        {
            InitializeComponent();

            DataContext = this;

            var kiwis = new List<Kiwi>();
            kiwis.Add(new Kiwi {Name = "a"});
            kiwis.Add(new Kiwi {Name = "b"});
            kiwis.Add(new Kiwi {Name = "c"});
            kiwis.Add(new Kiwi {Name = "d"});

            kiwiDataGrid.ItemsSource = kiwis;

            State = true;
        }

        private void ChangeButton_OnClick(object sender, RoutedEventArgs e)
        {
            State = !State;
            NotifyPropertyChanged("State");
        }
    }

    public class Kiwi
    {
        public String Name { get; set; }
    }

运行效果:

Enabled

Disable



<think> 我们正在讨论WPF中的RelativeSource绑定。根据用户之前的提问和引用内容,用户已经了解了RelativeSource的几种模式,现在需要详细的使用方法和示例。结合引用内容,特别是引用[1]和[3]中关于RelativeSource的几种模式的介绍,我们来组织回答。 RelativeSource绑定主要用于在绑定中指定相对于绑定目标的源。它有四种模式:Self、FindAncestor、TemplatedParent和PreviousData。下面我们将逐一解释每种模式的使用方法和提供示例。 ### 1. Self模式 **用途**:将绑定源设置为绑定目标元素自身。通常用于将同一个元素的某个属性绑定到另一个属性上。 **示例**:将一个TextBox的Text属性绑定到它自己的Tag属性上。 ```xaml <TextBox Tag="Hello, Self!" Text="{Binding RelativeSource={RelativeSource Self}, Path=Tag}"/> ``` 这样,TextBox就会显示"Hello, Self!",因为Text属性绑定了自身的Tag属性。 ### 2. FindAncestor模式 **用途**:在可视化树中向上查找特定类型的祖先元素,并绑定到该祖先的属性。 **参数**: - `AncestorType`:要查找的祖先元素的类型。 - `AncestorLevel`(可选):指定向上查找的层级(默认为1,即最近的祖先)。 **示例1**:绑定到父级StackPanel的Background属性。 ```xaml <StackPanel Background="LightBlue"> <TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StackPanel}}, Path=Background}"/> </StackPanel> ``` 此时TextBlock的Text将显示父StackPanel的背景颜色(如`#FFADD8E6`)。 **示例2**:绑定到更高级别的祖先(如Window的标题)。 ```xaml <Window x:Class="WpfApp.MainWindow" Title="My Application"> <StackPanel> <TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=Title}"/> </StackPanel> </Window> ``` TextBlock将显示窗口的标题"My Application"。 ### 3. TemplatedParent模式 **用途**:在控件模板(ControlTemplate)中使用,绑定到应用模板的控件(即模板的父级)的属性。 **注意**:仅当在控件模板内部使用时才有效。 **示例**:在自定义Button模板中绑定到Button的Content属性。 ```xaml <ControlTemplate TargetType="Button"> <Border Background="LightGreen"> <ContentPresenter Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"/> </Border> </ControlTemplate> ``` 这样,模板中的ContentPresenter就会显示Button的实际内容。 ### 4. PreviousData模式 **用途**:在数据列表(如ItemsControl)中绑定到前一项的数据项。适用于需要访问列表中前一数据项的场景(如显示数据变化趋势)。 **示例**:在ListBox中显示当前项与前一项的差值。 ```xaml <ListBox ItemsSource="{Binding Numbers}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding}"/> <TextBlock Text=" - 前一项: "/> <TextBlock Text="{Binding RelativeSource={RelativeSource PreviousData}, Converter={StaticResource SubtractConverter}}"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> ``` 注意:需要创建一个转换器(SubtractConverter)来计算差值。 ### 特殊用法:绑定到其他ViewModel上的命令 有时在嵌套的ViewModel结构(如主ViewModel包含子ViewModel列表)中,需要将子项中的命令绑定到父级的ViewModel上。这时可以使用`FindAncestor`模式: ```xaml <ListBox ItemsSource="{Binding ChildViewModels}"> <ListBox.ItemTemplate> <DataTemplate> <Button Content="执行父级命令" Command="{Binding DataContext.ParentCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox> ``` ### 小结 RelativeSource绑定在以下场景特别有用: - 需要绑定到自身属性(Self) - 访问祖先元素(FindAncestor) - 在控件模板中访问模板化父级(TemplatedParent) - 处理列表中的相邻数据项(PreviousData) 掌握这些绑定技巧能显著提升WPF开发的灵活性[^1][^3]。 §§相关问题§§ 1. WPF中如何绑定到祖父级元素(即跳过一级父元素)? 2. TemplatedParent模式在自定义控件开发中有哪些典型应用? 3. PreviousData模式在动态数据更新时如何保持同步? </think> ### WPF中RelativeSource绑定的使用详解 RelativeSource绑定是WPF中解决特殊绑定场景的核心技术,通过`RelativeSource`属性指定相对于绑定目标的源。以下是四种模式的使用方法和示例: --- #### 1. **Self模式** **用途**:绑定到当前控件自身的属性 **场景**:控件的一个属性需要关联自身另一个属性时 ```xaml <!-- 将TextBlock的宽度绑定到自身高度 --> <TextBlock Height="100" Width="{Binding RelativeSource={RelativeSource Self}, Path=Height}" Text="正方形文本区域"/> ``` *效果*:宽度与高度同步为100px,形成正方形文本区域[^1][^3]。 --- #### 2. **FindAncestor模式** **用途**:在可视化树中查找祖先元素 **参数**: - `AncestorType`:目标祖先类型(必需) - `AncestorLevel`:向上查找的层级(默认1) ```xaml <!-- 绑定到祖父级StackPanel的背景色 --> <StackPanel Background="LightBlue"> <Border> <TextBlock Text="继承祖父背景色" Background="{Binding RelativeSource={RelativeSource AncestorType={x:Type StackPanel}}, Path=Background}"/> </Border> </StackPanel> ``` *效果*:TextBlock背景色变为浅蓝色[^1][^3]。 --- #### 3. **TemplatedParent模式** **用途**:在控件模板中访问应用模板的父控件 ```xaml <!-- 自定义按钮模板 --> <ControlTemplate TargetType="Button"> <Border Background="LightGreen"> <ContentPresenter Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"/> <!-- 显示按钮原始内容 --> </Border> </ControlTemplate> ``` *原理*:`TemplatedParent`指向使用该模板的Button实例[^3]。 --- #### 4. **PreviousData模式** **用途**:在列表项中访问前一项数据 ```xaml <ListBox ItemsSource="{Binding SalesData}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel> <TextBlock Text="{Binding CurrentValue}"/> <!-- 显示与前一项的差值 --> <TextBlock Foreground="Red" Text="{Binding RelativeSource={RelativeSource PreviousData}, Path=CurrentValue, Converter={StaticResource DiffConverter}}"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> ``` *效果*:计算当前项与前一项数据的差值[^1][^3]。 --- ### 进阶技巧:混合使用模式 ```xaml <!-- 在DataGrid单元格中绑定到列标题 --> <DataGridTextColumn> <DataGridTextColumn.CellStyle> <Style TargetType="DataGridCell"> <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridColumnHeader}}, Path=Content}"/> </Style> </DataGridTextColumn.CellStyle> </DataGridTextColumn> ``` *效果*:单元格悬停时显示所属列的标题文本[^1]。 --- ### 核心原理 RelativeSource通过**可视化树**或**逻辑树**导航: ```mermaid graph TD A[绑定目标] --> B{模式选择} B -->|Self| C[自身属性] B -->|FindAncestor| D[向上遍历父节点] B -->|TemplatedParent| E[模板持有者] B -->|PreviousData| F[列表前项数据] ``` > **关键区别**: > - `ElementName`:通过名称查找元素(需命名) > - `RelativeSource`:通过层级关系查找元素(无需命名) > - `Source`:直接指定数据源对象 --- ### 常见错误解决方案 **错误**:`FindAncestor找不到祖先元素` **原因**: 1. 目标类型`AncestorType`拼写错误 2. 祖先层级`AncestorLevel`超过实际层级 3. 目标元素不在同一个可视化树中 **修复**: ```xaml <!-- 显式指定层级 --> <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Grid}, AncestorLevel=2}, <!-- 明确向上2级 --> Path=Tag}"/> ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值