views:

920

answers:

1

What's a good way to get at the controls in a DataTemplate? I've used the technique of handing the Loaded event on the control of interest as well as using VisualTreeHelper to walk the visual tree and neither of those is very elegant. What's a good way to access DataTemplate controls?

In one example, I need to add a binding whos ConverterParameter isn't know at design time, and since binding to ConverterParameters isn't supported I need to create the binding in code. Ideally I'd like to be able to do this somewhere other than the Loaded event hander for the control in the datatemplate.

In fact, in this scenario handling events doesn't work at all and causes the an OutOfMemoryException. Here's my attempt:

generic.xaml:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:SilverlightTest">


    <Style TargetType="local:TemplatedControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:TemplatedControl">
                    <ListBox ItemsSource="{TemplateBinding ListBoxItemsSource}">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <TextBlock x:Name="SomeTextBlock"
                                    Loaded="SomeTextBlock_Loaded"/>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

templatedcontrol.cs:

public class TemplatedControl : Control
    {
        public object ListBoxItemsSource
        {
            get { return (object)GetValue(ListBoxItemsSourceProperty); }
            set { SetValue(ListBoxItemsSourceProperty, value); }
        }

        public static readonly DependencyProperty ListBoxItemsSourceProperty =
            DependencyProperty.Register
            ("ListBoxItemsSource", typeof(object),
             typeof(TemplatedControl), new PropertyMetadata(null));

        public TemplatedControl()
        {
            this.DefaultStyleKey = typeof(TemplatedControl);
        }

        public void SomeTextBlock_Loaded(object sender, RoutedEventArgs ea)
        {
        }
    }
+1  A: 

You could have another control in your DataTemplate to handle that, but that's kind of messy also with the caveat of "unless you really believe the logic justifies it".

You might want to rethink your approach. In my opinion (and it's just an opinion!), one should only be binding in code in more exotic situations.

Maybe instead of using a IValueConverter, bind to a property on the a ViewModel (assuming your ItemsSource is a collection of ViewModels), and let your VM convert your values accordingly. Let your default style for this control be generic and ugly and maybe use specific styles for cases when you need to bind to specific properties.

Jeremiah Morrill