C#/ WPF:获取元素的绑定路径在一个DataTemplate [英] C#/WPF: Get Binding Path of an Element in a DataTemplate

查看:353
本文介绍了C#/ WPF:获取元素的绑定路径在一个DataTemplate的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我怎样才能得到一个元素在一个DataTemplate绑定路径?
我的XAML是这样的:

How can I get the Binding Path of an Element in a DataTemplate? My XAML looks like this:

<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是

To get the Binding Path for the "normal" GridViewColumnHeader.DisplayMemberBinding is

var field = (string)((Binding)((GridViewColumnHeader)e.OriginalSource).Column.DisplayMemberBinding).Path.Path;

我如何获得 TextBlock.Text

推荐答案

这是一个很大的问题。还有的code和XAML和,code-明智之间的分离,这不是显而易见的地方开始寻找。而且,所以它不是在运行时十分便利的DataTemplate中被编译成BAML。

This is a great question. There's a separation between the code and the XAML, and, code-wise, it's not immediately obvious where to start looking. Also, the DataTemplate is compiled into BAML so it's not very accessible at runtime.

有寻找绑定的路径至少有两个策略。

There are at least two strategies for finding the binding's path.

第一个策略的保存路径某处的静态变量。

The first strategy is saving the path as a static variable somewhere.

code-背后:

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>


第二个策略正在打开史努比或的 WPF督察。目标是编程查询的可视树感兴趣的TextBlock的。然而,有许多可能的TextBlocks在ListView。事实上,头可能是使用一个。因此,第一步骤是确定的细胞的的TextBlock的一个独特的祖先。纵观可视化树,有两个像样的候选人:一个ScrollContent presenter(与模板零件名称,它应该是唯一的)和一个GridViewRow presenter。这是最好的祖先接近感兴趣的TextBlock的。这降低了其他的TextBlocks歪曲搜索结果的可能性。因此,GridViewRow presenter是preferable。


The second strategy is opening Snoop or WPF Inspector. The goal is to programmatically search the visual tree for the TextBlock of interest. However, there could many TextBlocks in the ListView. In fact, the Header is probably using one. So, the first step is to identify a unique ancestor of the cell's TextBlock. Looking at the visual tree, there are two decent candidates: a ScrollContentPresenter (with a template part name, which should be unique) and a GridViewRowPresenter. It's best for the ancestor to be close to the TextBlock of interest. This decreases the likelihood of other TextBlocks distorting the search results. Thus, the GridViewRowPresenter is preferable.

添加一个或两个实用的方法来执行可视化树搜索。

One or two utility methods are added to perform the visual tree search.

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的开始,一个GridViewRow presenter被找到。与GridViewRow presenter开始,一个TextBlock被找到。它的文本绑定查询和路径终于访问。

Now, two searches through the visual tree are performed, with the first search result acting as the root for the second search. Starting with the ListView, a GridViewRowPresenter is found. Starting with that GridViewRowPresenter, a TextBlock is found. Its Text binding is queried and the path is finally accessed.

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测试。此外,所有的错误检查一直留出简洁。

It's important to note that the ListView's ControlTemplates and DataTemplates must be inflated into their actual visual elements for the search to work. If the inflation hasn't happened, the elements don't exist. You can test this by first trying the search in the main window's contructor and then trying it in the window's OnSourceInitialized. Also, all error checking has been left out for brevity.

最后,本次战略的丝毫没有的防弹。当使用新的CONTROLTEMPLATES和WPF的DataTemplates元素可以有任意复杂的视觉成分。但是,它是思考你将如何解决你在任何情况下这个问题一个很好的起点。

Finally, this second strategy is not even remotely bulletproof. WPF elements can have arbitrarily complex visual compositions when new ControlTemplates and DataTemplates are used. However, it's a good starting point for thinking about how you might solve the problem in whatever situation you're in.

这篇关于C#/ WPF:获取元素的绑定路径在一个DataTemplate的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆