WPF - controlless style: how to access dependent control properties from second level ControlTemplates?
I am extending ItemsControl
( class EnhancedItemsControl : ItemsControl
) because I want to add a few dependecy properties to it - for example AlternativeContent
, which will be displayed when there are no items in the collection (think about "enter search terms" and click "search label" in the controlcontrol for search results).
I subclassed ItemsControl
and added AlternativeContent
dep. type property FrameworkElement
. Now I want to provide the default styling in Themes / Generic.xaml (I added ThemeInfoAttribute
in AsseblyInfo and provided metadata in the static costructor as said in this excellent tutorial ).
The style contains ControlTemplate
and I need to use the second one ControlTemplate
inside the ItemsControl template where I add ContentPresenter
which should show AlternativeContent
.
Now, my problem is, how can I tell ContentPresenter
it to get its content from the top level EnhancedItemsControl
? If I was inside a style ControlTemplate
I would use:
Content="{Binding AlternativeContent, RelativeSource={RelativeSource TemplatedParent}}"
but since i'm in ItemsControl
ControlTemplate
inside style ControlTemplate
this obviously doesn't work, i will need to refer not to the parent template but to the grandma template, however TemplateBinding
doesn 't have a parameter AncestorLevel
.
I've also tried:
Content="{Binding AlternativeContent, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type WPFControls:EnhancedItemsControl}}}"
but this also results in empty ContentPresenter
. I cannot name TemplatedParent
(because it is outside ControlTemplate
), so I cannot refer to it by name. I can't use TemplatedParent
RelativeBinding
because it doesn't reach two levels of control patterns. And RelativeSource
FindAncestor
strangely it doesn't work.
Any ideas how to solve this? Thank!
Generic.xaml (excerpt):
<Style TargetType="{x:Type WPFControls:EnhancedItemsControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type WPFControls:EnhancedItemsControl}">
<ItemsControl
x:Name="RootItemsControl"
ItemsSource="{Binding}"
ItemTemplate="{TemplateBinding ItemTemplate}"
Background="{TemplateBinding Background}"
HorizontalContentAlignment="Stretch"
>
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer
x:Name="ContentScrollViewer"
CanContentScroll="False"
>
<StackPanel
x:Name="InnerPanel"
>
<ItemsPresenter
Width="{Binding ActualWidth, ElementName=InnerPanel}"
MaxWidth="{Binding ActualWidth, ElementName=InnerPanel}"
HorizontalAlignment="Stretch"
/>
<ContentPresenter
Content="{Binding AlternativeContent, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type WPFControls:EnhancedItemsControl}}}"
>
<ContentPresenter.Style>
<Style>
<Setter Property="ContentPresenter.Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger
Binding="{Binding Items.Count, ElementName=RootItemsControl}"
Value="0">
<Setter Property="ContentPresenter.Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentPresenter.Style>
</ContentPresenter>
</StackPanel>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Control code:
public class EnhancedItemsControl : ItemsControl
{
static EnhancedItemsControl()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(EnhancedItemsControl),
new FrameworkPropertyMetadata(typeof(EnhancedItemsControl)));
}
public FrameworkElement AlternativeContent
{
get { return (FrameworkElement)GetValue(AlternativeContentProperty); }
set { SetValue(AlternativeContentProperty, value); }
}
// Using a DependencyProperty as the backing store for AlternativeContent. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AlternativeContentProperty =
DependencyProperty.Register("AlternativeContent", typeof(FrameworkElement), typeof(EnhancedItemsControl), new UIPropertyMetadata(null));
}
Usage (a is List<string>
provided as DataContext
):
<WPFControls:EnhancedItemsControl Height="120" x:Name="EnhancedCollection"
>
<WPFControls:EnhancedItemsControl.AlternativeContent>
<WPFControls:CenteredLabel>
Alternative content
</WPFControls:CenteredLabel>
</WPFControls:EnhancedItemsControl.AlternativeContent>
<WPFControls:EnhancedItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</WPFControls:EnhancedItemsControl.ItemTemplate>
</WPFControls:EnhancedItemsControl>
source to share