1
votes

I'd like to know whether there's a simple (I believe there's a complex workaround for everything) way to style a group of potentially nested elements while referencing just one style on the parent element level in XAML/WPF.

In HTML/CSS it is possible to do:

<div class="levels"><!--1st level; only reference to the style-->
  <div><!--2nd level-->
    <div></div><!--3rd level-->
  </div>
  <div></div><!--2nd level-->
</div>

and then style it by:

.levels {
  width: 400px; height: 400px;
  background-color:red;}

.levels div {
  width: 100px; height: 100px;
  background-color:green;}

.levels div div {
  width: 50px; height: 50px;
  background-color:yellow;}

This makes it possible to reference the style "levels" only once on the parent element and then worry about the referencing no more, so when a new element is added later under the parent element (either in xaml or dynamically in code) you don't need keep in mind to also add "class=levelx" to the new element.

Is the same possible in XAML/WPF? The BasedOn property doesn't seem to be what I want as: a) I'm not looking for a property inheritance, b) unless the new style has a defined x:Key it is applied to all elements of given TargetType and if it does, then once again you need to reference it on the given element (Style="{static resource levelx}"). <Setter Property="Grid.Grid.Background" Value"Red"> unfortunately doesn't work.

What is then the proper way to style such a group of elements? Referencing a specific style on each nested element seems to me unnecessarily messy.

Here's a concrete example of an element structure, but I consider this to be a general question for many different situations:

<Grid Style="{StaticResource Levels}"><!--1st level-->
    <Grid><!--2nd level-->
        <Grid></Grid><!--3rd level-->
        <Image Source="/Resources/xxx.png"/><!--3rd level-->
    </Grid>
    <Grid><!--2nd level-->
        <Grid></Grid><!--3rd level-->
        <Image Source="/Resources/yyy.png" x:Name="yyy"/><!--3rd level-->
    </Grid>
    <Grid><!--2nd level-->
        <Image Source="/Resources/zzz.png"/><!--3rd level-->
    </Grid>
</Grid>

This is probably a duplicate, but I couldn't find an answer.

2
What sort of properties do you aim to share among the nested elements? something like width, height, margin and such? It may be just me but your XAML example doesn't exactly show the duplication in properties you wish to avoid. Could you please elaborate on the things you wish to narrow down?MichaelThePotato
@MichaelThePotato Yes, such properties exactly. For example, I'd like the parent grid to have red background, while ANY nested grid on the 2nd level to have green background and ANY grid on 3rd level to have yellow background or ANY image on 3rd level (meaning only under 2nd-lvl grid) to be of certain height/width and so on without having to specify a reference to style for each of these elements. Just like the CSS in the example.Demo
What's your exact definition of "level" exactly? I assume the parent grid is the first level, and do you mean all the direct children grids as the second level? Or do you mean that the one that owns the XXX image is the second level, the one that owns the YYY is the third and so on?MichaelThePotato
@MichaelThePotato I've edited the example in my post. The wrapper grid is the 1st lvl, grids containing images are 2nd and all elements contained by 2nd lvl grids are 3rd level (added 3rd level grids now).Demo
Just saw your edit. thanks for the clarification, but I regret to inform you that to the best of my knowledge, relative style application as you wish it to be in a simple manner, doesn't exist in XAML.MichaelThePotato

2 Answers

1
votes

Did you mean something like this.

<Grid Margin="20">
  <Grid.Resources>
  <Style TargetType="Grid">
  <Setter Property="Background" Value="Blue"></Setter>
  </Style>
  </Grid.Resources>
  <Grid.RowDefinitions>
  <RowDefinition Height="Auto"/>
  <RowDefinition Height="Auto"/>
  <RowDefinition Height="Auto"/>
  </Grid.RowDefinitions>
    <Grid Margin="20" Height="20" Grid.Row="0">
    </Grid>
    <Grid Margin="20" Height="20" Grid.Row="1" Background="Yellow">
    </Grid>
    <Grid Margin="20" Height="20" Grid.Row="2">
    </Grid>
</Grid>
0
votes

What you want might not be exactly possible. Particularly for n levels. Something like this would give you desired behavior over two levels.

CONTENT

    <Grid Style="{StaticResource Levels}">
        <Grid VerticalAlignment="Top" Margin="20 20 0 0" Height="60">
            <Grid Height="40" VerticalAlignment="Center">
                <Grid Height="20" VerticalAlignment="Center"></Grid>
                <Label></Label>
            </Grid>
        </Grid>
        <Grid VerticalAlignment="Top" Margin="20 100 0 0" Height="60">
            <Grid Height="40" VerticalAlignment="Center">
                <Grid Height="20" VerticalAlignment="Center"></Grid>
            </Grid>
        </Grid>
        <Grid VerticalAlignment="Top" Margin="20 180 0 0" Height="60">
            <Grid Height="40" VerticalAlignment="Center">
                <Grid Height="20" VerticalAlignment="Center"></Grid>
            </Grid>
        </Grid>
    </Grid>       

STYLE DEFINITION

  <Style x:Key="Levels" TargetType="Grid">
        <Setter Property="Background" Value="Blue"></Setter>
        <Setter Property="Width" Value="400"></Setter>
        <Style.Resources>
            <Style TargetType="Grid">
                <Setter Property="Grid.Background" Value="Purple"/>
                <Setter Property="Width" Value="200"></Setter>
                <Style.Resources>
                    <Style TargetType="Grid">
                        <Setter Property="Background" Value="Yellow"></Setter>
                        <Style.Resources>
                            <Style TargetType="Grid">
                                <Setter Property="Background" Value="Tomato"></Setter>
                            </Style>
                            <Style TargetType="Label">
                                <Setter Property="Height" Value="20"/>
                                <Setter Property="Width" Value="20"/>
                                <Setter Property="Background" Value="Azure"/>
                            </Style>
                        </Style.Resources>
                    </Style>
                </Style.Resources>
            </Style>
        </Style.Resources>
    </Style>