如何以编程方式绑定DataTemplate内部控件的(依赖)属性?

时间:2014-02-13 12:52:21

标签: c# wpf binding datatemplate

TextBlock位于DataTemplate,因此我无法通过其名称来引用它。那么如何以编程方式绑定其(例如)Text属性?

XAML:

<UserControl x:Class="MyNameSpace.MyCustomControl" ... >
    ...
    <ListBox ItemsSource="{Binding Path=ItemsSource}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    ...
</UserControl>

代码:

public partial class MyCustomControl : UserControl {
    ...

    public static readonly DependencyProperty DataSourceProperty =
        DependencyProperty.Register("DataSource", typeof (IEnumerable),
                                    typeof (MyCustomControl),
                                    new PropertyMetadata(default(IEnumerable)));

    public IEnumerable DataSource {
        get { return (IEnumerable) GetValue(DataSourceProperty); }
        set { SetValue(DataSourceProperty, value); }
    }

    public static readonly DependencyProperty MemberPathProperty =
        DependencyProperty.Register("MemberPath", typeof (string),
                                    typeof (MyCustomControl),
                                    new PropertyMetadata(default(string)));

    public string MemberPath {
        get { return (string) GetValue(MemberPathProperty); }
        set { SetValue(MemberPathProperty, value); }
    }
    ...
    public MyCustomControl() {
        InitializeComponent();

        var binding = new Binding(MemberPath);
        BindingOperations.SetBinding(/*how do I refer to the TextBlock here ???*/,
                                     TextBox.TextProperty, binding);
    }
    ...
}

预期用法示例:

<my:MyCustomControl DataSource="{Binding Path=SomeModelCollection}" MemberPath="Name"

其中SomeModelCollection是某些数据模型属性,例如ObservableCollection<SomeModel>SomeModel有一个名为Name的属性)

1 个答案:

答案 0 :(得分:1)

您可以使用TextBlock获取VisualTreeHelper。此方法将为您提供listBoxItem的Visual树中存在的所有TextBlock:

public IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj)
            where T : DependencyObject
{
   if( depObj != null )
   {
       for( int i = 0; i < VisualTreeHelper.GetChildrenCount( depObj ); i++ )
       {
          DependencyObject child = VisualTreeHelper.GetChild( depObj, i );
          if( child != null && child is T )
          {
              yield return (T)child;
          }

          foreach( T childOfChild in FindVisualChildren<T>( child ) )
          {
             yield return childOfChild;
          }
       }
    }
}

用法:

TextBlock textBlock = FindVisualChildren<TextBlock>(listBoxItem)
                       .FirstOrDefault();

但我仍然建议在XAML中进行绑定,而不是在后面的代码中进行绑定。

如果ItemSourceObservableCollection<MyModel>MyModel包含属性Name,则可以在XAML中完成,如下所示:

<DataTemplate>
   <StackPanel Orientation="Horizontal">
      <TextBlock Text="{Binding Name}"/>
   </StackPanel>
 </DataTemplate>

由于DataContext的{​​{1}}将为ListBoxItem,因此您可以直接绑定到Name属性,如上所述。