2009-08-19 5 views
9

DataTemplate内の要素のバインディングパスを取得するにはどうすればよいですか? 私のXAMLは、このようになります:「ノーマル」GridViewColumnHeader.DisplayMemberBindingのための結合パスを取得するにはC#/ WPF:DataTemplate内の要素のバインディングパスを取得する

<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"/> 

私はTextBlock.Textの結合パスのための同じを取得できますか

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

のですか?

答えて

10

これは大きな質問です。コードとXAMLの間には区別があり、コードワイズでは、どこから見始めるべきかがすぐに分かりません。また、DataTemplateはBAMLにコンパイルされているため、実行時にはアクセスできません。

バインディングのパスを見つけるための戦略が少なくとも2つあります。

最初の戦略は、パスを静的変数としてどこかに保存しています。

コードビハインド:

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が存在する可能性があります。実際、ヘッダーはおそらく1つを使用しています。したがって、最初のステップは、セルの TextBlockのユニークな祖先を特定することです。ビジュアルツリーを見ると、ScrollContentPresenter(テンプレートパーツ名が一意である必要があります)とGridViewRowPresenterという2つの適切な候補があります。祖先が関心のあるTextBlockの近くにいることが最善です。これにより、他のTextBlocksによる検索結果の歪みの可能性が減少します。したがって、GridViewRowPresenterが適しています。

enter image description here

つまたは2つのユーティリティメソッドは、ビジュアルツリーの検索を実行するために追加されます。今

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(); 
    } 
} 

、ビジュアルツリーを介して2件の検索は、2回目の探索のためのルートとして動作する最初の検索結果と、実行されます。 ListViewから、GridViewRowPresenterが見つかりました。そのGridViewRowPresenterから、TextBlockが見つかります。そのテキストバインディングが照会され、パスに最終的にアクセスされます。

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で試してみてください。また、すべてのエラーチェックは簡潔にするために省略されています。

最後に、この第2の戦略は、でもリモートではありません防弾です。 WPF要素は、新しいControlTemplatesとDataTemplateを使用すると、任意の複雑なビジュアルコンポジションを持つことができます。しかし、どのような状況であっても、どのように問題を解決するかを考え始めるのは良い出発点です。

+1

@ Andrew-Van-Berg OMG!ありがとうございました!スヌープとWPFインスペクタはこれまで最高のものです! –

+0

@Alexander Van Berg - ありがとうございました – Peter

関連する問題