70

Suppose you have a nested element structure, for example a ContextMenu with MenuItems:

<ContextMenu Style="{StaticResource FooMenuStyle}">
    <MenuItem Style="{StaticResource FooMenuItemStyle}"/>
    ...
</ContextMenu>

You can easily apply styles or templates to the ContextMenu or MenuItem elements. But if the MenuItem style belongs to the Menu style it is quite cumbersome and redundant to add it to every MenuItem element.

Is there any way to apply those automatically to child elements? So that you can simply write this:

<ContextMenu Style="{StaticResource FooMenuStyle}">
    <MenuItem/>
    ...
</ContextMenu>

It would be neat if FooMenuStyle could style containing MenuItem elements, but that does not seem to be possible.

Edit: The Menu example is probably misleading since I was unaware of ItemContainerStyle and the intent was for a general solution. Based on the two answers I have come up with two solutions: one general variant and one for ItemContainerStyle and the like:

<Style x:Key="FooMenuItem" TargetType="{x:Type MenuItem}">
    ...
</Style>

<Style x:Key="FooMenu" TargetType="{x:Type ContextMenu}">
    <!-- Variant for specific style attribute -->
    <Setter Property="ItemContainerStyle"
            Value="{StaticResource FooMenuItem}"/>

    <!-- General variant -->
    <Style.Resources>
        <Style TargetType="{x:Type MenuItem}"
               BasedOn="{StaticResource FooMenuItem}"/>
    </Style.Resources>
</Style>

<ContextMenu Style="{StaticResource FooMenu}">
    <MenuItem/>
</ContextMenu>
gix
  • 5,737
  • 5
  • 34
  • 40

4 Answers4

178

Just to complete the original answer, I think it is clearer adding the nested style inside the parent like that:

<Style x:Key="WindowHeader" TargetType="DockPanel" >
    <Setter Property="Background" Value="AntiqueWhite"></Setter>
    <Style.Resources>
        <Style TargetType="Image">
            <Setter Property="Margin" Value="6"></Setter>
            <Setter Property="Width" Value="36"></Setter>
            <Setter Property="Height" Value="36"></Setter>
        </Style>
        <Style TargetType="TextBlock">
            <Setter Property="TextWrapping" Value="Wrap"></Setter>
        </Style>
    </Style.Resources>
</Style>
Noam M
  • 3,156
  • 5
  • 26
  • 41
Juan Calero
  • 4,124
  • 5
  • 31
  • 45
  • 11
    This is the most appropriate answer. No where on web one can fine. You rock! thanks. – Rohit Dec 10 '10 at 11:30
  • 4
    Thanks, this info is really hard to find. – Matěj Zábský Dec 19 '10 at 20:57
  • I used this example to help me apply a style to all textblocks nested within a tooltip - setting a maximum width and enforcing wrapping so that long messages are better formatted. – sfuqua Oct 14 '11 at 22:37
  • @Juan Calero, This is perfect. However, how can we refer the parent element in child here in style? I tried `relativesource findancestor` but it can't find the source – Anup Sharma Dec 06 '17 at 13:46
  • @Juan Calero, that saved me a lot of lines in my code ! – Lucy82 Dec 04 '19 at 09:37
  • 1
    For reference, if anyone needs to target specific types, this can be done with the `DynamicResource` property, as explained here: https://stackoverflow.com/a/31045455 – maxp Feb 18 '21 at 17:23
  • (Treat me as a newbie) What does this do? What is a style inside a style and how is it used? – Daniel Möller Aug 13 '22 at 01:44
31
<ContextMenu>
   <ContextMenu.Resources>
      <Style TargetType="{x:Type MenuItem}">
         <!--Setters-->
      </Style>
   </ContextMenu.Resources>
   <MenuItem/>
   <!--Other MenuItems-->
</ContextMenu>

The style will be applied to all MenuItem objects within the ContextMenu.

Josh G
  • 14,068
  • 7
  • 62
  • 74
5
<ContextMenu ItemContainerStyle="{StaticResource FooMenuItemStyle}">
    <MenuItem/>
</ContextMenu>
Kent Boogaart
  • 175,602
  • 35
  • 392
  • 393
  • I think my menu example was a bit misleading (since I did not know about ItemContainerStyle), and the initial intent was for arbitrary elements. But since I actually have a menu this is the way to go. – gix Mar 21 '09 at 11:46
0

The way I accomplished this was to create a keyed ResourceDictionary inside the global resource dictionary and then only apply it to the parent element.

Inside app.xaml:

<Application.Resources>
  <ResourceDictionary>
    ...

    <ResourceDictionary x:Key="menuChildrenStyles">
      <Style TargetType="MenuItem">
        <!--Setters-->
      </Style>
    </ResourceDictionary>

    ...
  </ResourceDictionary>
</Application.Resources>

Then inside your other xaml views:

<ContextMenu Resources="{StaticResource menuChildrenStyles}">
  <MenuItem />
  <MenuItem />
  <MenuItem />
  <MenuItem />
</ContextMenu>

This will apply the MenuItem style to all the MenuItem elements inside the parent element.

You can also add additional styles into the "menuChildrenStyles" dictionary like for TextBlock, etc.

Kyle B
  • 2,328
  • 1
  • 23
  • 39