Jos*_*nel 9 c# wpf binding datatemplate
如何在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"/>
Run Code Online (Sandbox Code Playgroud)
获取"普通"GridViewColumnHeader.DisplayMemberBinding的绑定路径是
var field = (string)((Binding)((GridViewColumnHeader)e.OriginalSource).Column.DisplayMemberBinding).Path.Path;
Run Code Online (Sandbox Code Playgroud)
如何才能获得相同的绑定路径TextBlock.Text?
Ale*_*erg 10
这是一个很好的问题.代码与XAML之间存在分离,而且,代码方面,从哪里开始寻找并不是很明显.此外,DataTemplate被编译为BAML,因此在运行时无法访问它.
找到绑定路径至少有两种策略.
第一种策略是将路径保存为某处的静态变量.
代码隐藏:
namespace TempProj
{
using System.Windows;
public partial class MainWindow : Window
{
static public readonly PropertyPath BindingPath = new PropertyPath("X");
public MainWindow()
{
InitializeComponent();
}
}
}
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
在第二个策略是开放史努比或WPF督察.目标是以编程方式在可视树中搜索感兴趣的TextBlock.但是,ListView中可能有许多TextBlock.实际上,Header可能正在使用一个.因此,第一步是确定单元格 TextBlock 的唯一祖先.查看可视化树,有两个不错的候选者:ScrollContentPresenter(具有模板部件名称,应该是唯一的)和GridViewRowPresenter.最好让祖先接近感兴趣的TextBlock.这降低了其他TextBlocks扭曲搜索结果的可能性.因此,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();
}
}
Run Code Online (Sandbox Code Playgroud)
现在,通过可视树执行两次搜索,第一次搜索结果充当第二次搜索的根.从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;
Run Code Online (Sandbox Code Playgroud)
重要的是要注意ListView的ControlTemplates和DataTemplates必须膨胀到它们的实际可视元素中,以便搜索起作用.如果没有发生通货膨胀,那么这些要素就不存在了.您可以通过首先在主窗口的构造函数中尝试搜索然后在窗口的OnSourceInitialized中尝试搜索来测试它.此外,为简洁起见,省略了所有错误检查.
最后,这第二个策略甚至没有远程防弹.当使用新的ControlTemplates和DataTemplates时,WPF元素可以具有任意复杂的视觉合成.但是,这是一个很好的起点,可以考虑如何在任何情况下解决问题.