簡體   English   中英

C#/ WPF:獲取DataTemplate中元素的綁定路徑

[英]C#/WPF: Get Binding Path of an Element in a 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"/>

獲取“普通”GridViewColumnHeader.DisplayMemberBinding的綁定路徑是

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

如何在TextBlock.Text的綁定路徑中獲得相同的內容?

這是一個很好的問題。 代碼與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>

第二個策略是打開SnoopWPF Inspector 目標是以編程方式在可視樹中搜索感興趣的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();
    }
}

現在,通過可視樹執行兩次搜索,第一次搜索結果充當第二次搜索的根。 從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元素可以具有任意復雜的視覺合成。 但是,這是一個很好的起點,可以考慮如何在任何情況下解決問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM