views:

375

answers:

2

Hi, I am subclassing an ItemsControl (let's call it EnhancedItemsControl), and I would like to expose ScrollViewerTemplate dependency property, which would allow the user to optionally specify his own template for used ScrollViewer. I am doing it like this:

public ControlTemplate ScrollViewerTemplate { get { return (ControlTemplate)GetValue(ScrollViewerTemplateProperty); } set { SetValue(ScrollViewerTemplateProperty, value); } }

public static readonly DependencyProperty ScrollViewerTemplateProperty = DependencyProperty.Register( "ScrollViewerTemplate", typeof(ControlTemplate), typeof(EnhancedItemsControl), new UIPropertyMetadata(new ScrollViewer().GetValue(ScrollViewer.TemplateProperty))); //This doesn't work for me

In my default style for my EnhancedItemsControl, I then include the ScrollViewer like this:

This works when the user specifies the ScrollViewerTemplate, but when he leaves it at default value, the ScrollViewer is not displayed (presumably because it's Template is empty). How can I tell WPF Use the Template only when it is non-null, otherwise use default one? (it occured to me that I could use triggers to set the Template only when it is not null, but I don't like the idea of having a trigger for every custom property in each of my controls...)

There is similar problem with styles - if I wanted to let user specify the ScrollViewer style, but the user didn't specify it, the value of ScrollViewerStyle would be null (equal to <ScrollViewer Style="{x:Null}" />), which would stop the default style from being applied!

How to solve this? Thank you!

+1  A: 

Instead of using TemplateBinding you can use Binding with RelativeSource of TemplatedParent. This way you will be able to use converter in your Binding. Now declare a Converter(IValueConverter) for your Binding and return the default Template while the ScrollViewerTemplate property is null.

More Information

viky
Thanks, I know about possibility of replacing the TemplateBinding with normal binding, but without Aviad's post I still wouldn't know how to get the default value of Template.
Tomáš Kafka
+1  A: 

You're doing everything right except one little bit, the default value you are specifying in your UIPropertyMetadata is actually null, because it's null in that new ScrollViewer as well by default.

Instead of defining a ScrollViewerTemplate property, define a ScrollViewerStyle property:

public Style ScrollViewerStyle
{
    get { return (Style)GetValue(ScrollViewerTemplateProperty); }
    set { SetValue(ScrollViewerTemplateProperty, value); }
}

public static readonly DependencyProperty ScrollViewerTemplateProperty =
    DependencyProperty.Register(
        "ScrollViewerStyle", 
        typeof(Style), 
        typeof(EnhancedItemsControl), 
        new UIPropertyMetadata(null));

And in your default style for the control, specify a default value for the style as such:

<Setter Property="ScrollViewerStyle" Value="{StaticResource {x:Type ScrollViewer}}"/>

This will actually default to the ScrollViewer style as defined by the current theme.

Aviad P.
Thank you, you're the man! I didn't know that I can get the default style from resource dictionary indexed by type, that's pretty unintuitive - thanks again for showing me, that's much better than assigning the style/template with trigger when they are not null.
Tomáš Kafka
While everything else is uncertain, one thing is sure, I am the man :)
Aviad P.