Hello, I am extending the ItemsControl (class EnhancedItemsControl : ItemsControl), because I want to add several dependecy properties to it - like AlternativeContent which will be displayed when there are no items in collection (think of 'enter a search terms and hit search' label in a itemscontrol for results of search).
I have subclassed ItemsControl and added an AlternativeContent dep. property of type FrameworkElement to it. Now I want to provide default style in Themes/Generic.xaml (I have added ThemeInfoAttribute to AsseblyInfo, and provided metadata in static costructor as said in this excellent tutorial).
The style contains a ControlTemplate, and I need to use second ControlTemplate inside of ItemsControl template, where I add a ContentPresenter that should show the AlternativeContent.
Now, my problem is how do I tell the ContentPresenter that it should take it's content from the top-level EnhancedItemsControl? If I were inside style's ControlTemplate, I would use
Content="{Binding AlternativeContent, RelativeSource={RelativeSource TemplatedParent}}"
but as I am in ItemsControl's ControlTemplate inside style's ControlTemplate, this obviously doesn't work, I'd need to refer not to parent template, but to grandparent template, however, TemplateBinding doesn't have the AncestorLevel parameter.
I also tried
Content="{Binding AlternativeContent, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type WPFControls:EnhancedItemsControl}}}"
but that results in empty ContentPresenter as well. I cannot name the TemplatedParent (because it is outside the ControlTemplate), so I cannot refer to it by name. I cannot use TemplatedParent RelativeBinding, because that doesn't reach over two levels of controltemplates. And RelativeSource FindAncestor strangely doesn't work.
Any idea how to solve this? Thank you!
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 List is 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>