How to programmatically bind a (dependency) property of a control that's inside a DataTemplate?

别等时光非礼了梦想. 提交于 2019-12-20 04:12:23

问题


The TextBlock resides in a DataTemplate, thus I can't refer to it by its name. So how do I bind its (e.g.) Text property programmatically?

XAML:

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

Code:

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

Intended usage example:

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

Where SomeModelCollection is some data-model property like ObservableCollection<SomeModel> (SomeModel has a property called Name)


回答1:


You can get TextBlock using VisualTreeHelper. This method will get you all TextBlockes present in Visual tree of listBoxItem:

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

Usage :

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

But I would still suggest to do the binding in XAML instead of doing it in code behind.

In case ItemSource is ObservableCollection<MyModel> and MyModel contains property Name, it can be done in XAML like this:

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

Since DataContext of ListBoxItem will be MyModel, hence you can bind directly to Name property like mentioned above.



来源:https://stackoverflow.com/questions/21754814/how-to-programmatically-bind-a-dependency-property-of-a-control-thats-inside

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!