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>

      

+2


source to share


1 answer


Oh my bad

Content="{Binding AlternativeContent, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type WPFControls:EnhancedItemsControl}}}" 

      



does work (but my markup was more complex than the example and the content was not shown due to another error ...)

+1


source







All Articles