C#/WPF:获取 DataTemplate 中元素的绑定路径
Posted
技术标签:
【中文标题】C#/WPF:获取 DataTemplate 中元素的绑定路径【英文标题】:C#/WPF: Get Binding Path of an Element in a DataTemplate 【发布时间】:2010-11-20 20:40:05 【问题描述】:如何获取 DataTemplate 中元素的绑定路径? 我的 XAML 如下所示:
<GridViewColumn Header="Double">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="Binding TotalValues, Mode=OneWay, StringFormat=\0:0\'0.00\, Converter=StaticResource GridValueConverter" TextAlignment="Right" Width="auto"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Comments" DisplayMemberBinding="Binding Path=Comments, Mode=OneWay" Width="auto"/>
获取“普通”GridViewColumnHeader.DisplayMemberBinding的绑定路径是
var field = (string)((Binding)((GridViewColumnHeader)e.OriginalSource).Column.DisplayMemberBinding).Path.Path;
TextBlock.Text
的绑定路径如何获得相同的结果?
【问题讨论】:
【参考方案1】:这是一个很好的问题。代码和 XAML 之间存在分离,而且,就代码而言,从哪里开始查找并不是很明显。此外,DataTemplate 被编译成 BAML,因此在运行时不是很容易访问。
至少有两种查找绑定路径的策略。
第一个策略是将路径保存为静态变量。
代码隐藏:
namespace TempProj
using System.Windows;
public partial class MainWindow : Window
static public readonly PropertyPath BindingPath = new PropertyPath("X");
public MainWindow()
InitializeComponent();
XAML:
<Window x:Class="TempProj.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TempProj"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Vector3DCollection x:Key="Coordinates">
<Vector3D X="1" Y="0" Z="0"/>
<Vector3D X="0" Y="22" Z="0"/>
<Vector3D X="0" Y="0" Z="333"/>
<Vector3D X="0" Y="4444" Z="0"/>
<Vector3D X="55555" Y="0" Z="0"/>
</Vector3DCollection>
</Window.Resources>
<ListView x:Name="lv" ItemsSource="StaticResource Coordinates">
<ListView.View>
<GridView>
<GridViewColumn Header="x:Static local:MainWindow.BindingPath">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="Binding Path=x:Static local:MainWindow.BindingPath"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Window>
第二种策略是打开Snoop 或WPF Inspector。目标是以编程方式在可视化树中搜索感兴趣的 TextBlock。但是,ListView 中可能有许多 TextBlock。事实上,Header 很可能是在使用一个。因此,第一步是识别 cell 的 TextBlock 的唯一祖先。查看可视化树,有两个不错的候选者:一个 ScrollContentPresenter(具有模板部件名称,应该是唯一的)和一个 GridViewRowPresenter。祖先最好靠近感兴趣的 TextBlock。这降低了其他 TextBlock 扭曲搜索结果的可能性。因此,GridViewRowPresenter 更可取。
添加了一个或两个实用方法来执行可视化树搜索。
static public class ControlAux
static public IEnumerable<T> GetVisualDescendants<T>(this DependencyObject item) where T : DependencyObject
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(item); ++i)
DependencyObject child = VisualTreeHelper.GetChild(item, i);
if (typeof(T) == (child.GetType()))
yield return (T)child;
foreach (T descendant in GetVisualDescendants<T>(child))
yield return descendant;
static public T FindVisualDescendant<T>(this DependencyObject item, string descendantName) where T : DependencyObject
return
GetVisualDescendants<T>(item).Where(
descendant =>
var frameworkElement = descendant as FrameworkElement;
return frameworkElement != null ? frameworkElement.Name == descendantName : false;
).
FirstOrDefault();
现在,通过可视化树执行两次搜索,第一个搜索结果作为第二次搜索的根。从 ListView 开始,找到一个 GridViewRowPresenter。从那个 GridViewRowPresenter 开始,找到一个 TextBlock。查询其Text绑定,最终访问路径。
GridViewRowPresenter gvrp = lv.GetVisualDescendants<GridViewRowPresenter>().FirstOrDefault();
TextBlock tb = gvrp.GetVisualDescendants<TextBlock>().FirstOrDefault();
string path = BindingOperations.GetBinding(tb, TextBlock.TextProperty).Path.Path;
请务必注意,ListView 的 ControlTemplates 和 DataTemplates 必须膨胀到它们的实际可视元素中才能进行搜索。如果没有发生通货膨胀,那么这些元素就不存在。您可以通过首先尝试在主窗口的构造函数中进行搜索,然后在窗口的 OnSourceInitialized 中进行尝试来测试这一点。此外,为简洁起见,所有错误检查都被省略了。
最后,第二个策略甚至不是远程防弹的。当使用新的 ControlTemplates 和 DataTemplates 时,WPF 元素可以具有任意复杂的视觉组合。但是,这是思考在任何情况下如何解决问题的一个很好的起点。
【讨论】:
@Andrew-Van-Berg OMG!谢谢! Snoop 和 WPF Inspector 是有史以来最好的东西! @Alexander Van Berg - 谢谢先生以上是关于C#/WPF:获取 DataTemplate 中元素的绑定路径的主要内容,如果未能解决你的问题,请参考以下文章
WPF -- DataTemplate与ControlTemplate结合使用
WPF 菜单事件绑定 DataTemplate下button Command事件绑定 DataTemplate遍历实体数据