How to style all Telerik WPF RadExpander Header Controls?

1 Answer 518 Views
Expander Styling
Johnathan
Top achievements
Rank 1
Johnathan asked on 27 May 2022, 05:27 PM

   This question is for Telerik UI for WPF, version R2 2022.  Development environment is Windows 10 Pro 64-bit, Visual Studio 2022 64-bit version 17.2.2.  WPF application targeting .NET Framework 4.8.

I use many Telerik RadExpanders throughout my application.  Rather than style the header of each one individually, I would like to apply a master style to the Application.xaml so it will apply to all of them.  

   An example of one of my RadExpanders is:

xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" 

        <telerik:RadExpander x:Name="radExpGeneral" IsExpanded="True" 
                             telerik:AnimationManager.IsAnimationEnabled="False" telerikControls:StyleManager.Theme="Office_Blue">
            <telerik:RadExpander.Header>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Steps"/>
                </StackPanel>
            </telerik:RadExpander.Header>
        </telerik:RadExpander>

   I'm attempting to style with the following in my Application.xaml:

xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" 

        <Style TargetType="{x:Type telerik:RadExpander}">
            <Style.Resources>
                <Style TargetType="{x:Type HeaderedContentControl}">
                    <Style.Resources>
                        <Style TargetType="{x:Type TextBlock}">
                            <Setter Property="FontSize" Value="12"/>
                            <Setter Property="FontWeight" Value="DemiBold"/>
                        </Style>
                    </Style.Resources>
                </Style>
            </Style.Resources>
        </Style>

   The idea is that this style first targets all RadExpanders, then targets only the header, then applies the style to the textblocks inside of it.  The problem seems to be targeting the header only, not the contents.  This style does not work.  Can anyone advise how to target just the radexpander headers?  Thank you!

Stenly
Telerik team
commented on 01 Jun 2022, 03:50 PM

Hello Johnathan,

I am not sure that I fully understand what needs to be achieved. Would it be possible to share a bit more information regarding this matter?

Johnathan
Top achievements
Rank 1
commented on 02 Jun 2022, 04:38 PM

Stenly,

   My RadExpanders look like this:

   I want them all to be bolded like this:

   I don't want to manually set the FontSize and FontWeight for every single RadGridView Header.  I want to use a XAML style in my Application.xaml file to apply the FontSize and FontWeight properties for ALL ReadGridView Header items.

Stenly
Telerik team
commented on 07 Jun 2022, 02:55 PM

Since there is a custom code set for the Header property of the RadExpander control, in order for the TextBlock element to be styled, it would have to be correctly targeted. With the shared implementation of the mentioned property:

<telerik:RadExpander.Header>
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="Steps"/>
    </StackPanel>
</telerik:RadExpander.Header>

You could use the following Style to set the needed properties for this TextBlock only:

<Style TargetType="telerik:RadExpander">
    <Style.Resources>
        <Style TargetType="StackPanel">
            <Style.Resources>
                <Style TargetType="TextBlock">
                    <Setter Property="FontWeight" Value="SemiBold"/>
                    <Setter Property="Foreground" Value="Red"/>
                </Style>
            </Style.Resources>
        </Style>
    </Style.Resources>
</Style>

The produced result is as follows:

With this said, could you give this suggestion a try and let me know how it goes?

Johnathan
Top achievements
Rank 1
commented on 10 Jun 2022, 06:36 PM

Stenly,

   Thank you, that does appear to mostly work, but I believe that's because my RadExpander's contents do not include any other StackPanels.  For example, if I had the following XAML:

<telerik:RadExpander>
  <telerik:RadExpander.Header>
    <StackPanel Orientation="Horizontal">
      <TextBlock Text="Expander Header"/>
    </StackPanel>
  </telerik:RadExpander.Header>
  <telerik:RadExpander.Content>
    <StackPanel>
<TextBlock Text="Test"/>
    </StackPanel>
  </telerik:RadExpander.Content>
</telerik:RadExpander>

   I would end up with both the header textblock and the contents textblock inheriting the style.  What we really need is one more layer to only target the header part of the RadExpander, not the whole thing which includes the contents.  Hence why I was originally trying to target the HeaderedContentControl.

Stenly
Telerik team
commented on 15 Jun 2022, 01:24 PM

What comes to my mind, would be to use a spying utility, such as Snoop, in order to view the visual tree of the RadExpander element. Then, create a style based on the elements that are used inside the Header property of the RadExpanders in your application.

Alternatively, you could create a new class that derives from the TextBlock element and use it instead of the TextBlock control, inside of the Header. Then, you could create a style that targets this type and apply the needed settings, such as FontWeight, Foreground, FontSize, etc.

public class MyCustomTextBlock : TextBlock { }
<telerik:RadExpander>
    <telerik:RadExpander.Resources>
        <Style TargetType="local:MyCustomTextBlock">
            <Setter Property="Foreground" Value="Red"/>
            <Setter Property="FontWeight" Value="SemiBold"/>
        </Style>
    </telerik:RadExpander.Resources>
    <telerik:RadExpander.Header>
        <local:MyCustomTextBlock Text="Hello From Custom"/>
    </telerik:RadExpander.Header>
</telerik:RadExpander>

With this said, could you give these suggestions a try?

Johnathan
Top achievements
Rank 1
commented on 22 Jun 2022, 11:26 PM

Stetley,

   Thank you.  I'm aware that I could create a custom TextBlock class and target that, or I could create a custom style key and apply a named style to the TextBlock and/or StackPanel.  The problem with doing both is that it requires me to make custom changes to every single instance of the RadExpander header.  I would then have to either use my custom TextBlock or target the custom style in every header.
   The point in using Application.xaml WPF style targets is to set styles in one place, target them everywhere, and make changes easier without having to go back and customize each Header record.  I was hoping an expert from Telerik could help me target just the header portion.

   I used the Live Visual Tree built-in to Visual Studio and turned off "Just My XAML" to see the structure of the RadExpander.  It showed me the following:

   However, none of these items in the tree appear to be targetable.  The only one I was able to target was the HeaderButton which is of type RadToggleButton, but targeting that doesn't seem to work either:

        <Style TargetType="telerik:RadExpander">
            <Setter Property="telerik:AnimationManager.IsAnimationEnabled" Value="False"/>
            <Setter Property="telerikControls:StyleManager.Theme" Value="Office_Blue"/>
            <Style.Resources>
                <Style TargetType="telerik:RadToggleButton">
                    <Style.Resources>
                        <Style TargetType="TextBlock">
                            <Setter Property="FontSize" Value="12"/>
                            <Setter Property="FontWeight" Value="SemiBold"/>
                            <Setter Property="Foreground" Value="Pink"/>
                        </Style>
                    </Style.Resources>
                </Style>
            </Style>

1 Answer, 1 is accepted

Sort by
0
Martin Ivanov
Telerik team
answered on 27 Jun 2022, 09:34 AM

Hello Johnathan,

To achieve your requirement, you can use the HeaderButtonStyle property of RadExpander. This will allow you to target only the header of the control, which is a RadToggleButton element. If you set its Foreground and FontWeight properties the settings will be propagated to the TextBlock in the header. For example:

<Application.Resources>
	<ResourceDictionary>
		<ResourceDictionary.MergedDictionaries>
			<ResourceDictionary Source="/Telerik.Windows.Controls;component/Themes/GenericOfficeBlack.xaml"/>
		</ResourceDictionary.MergedDictionaries>
		<Style TargetType="telerik:RadExpander">
			<Setter Property="HeaderButtonStyle">
				<Setter.Value>
					<Style TargetType="telerik:RadToggleButton" BasedOn="{StaticResource ExpanderHeaderButtonStyle}">
						<Setter Property="FontWeight" Value="Bold"/>
						<Setter Property="Foreground" Value="LightCoral" />
					</Style>
				</Setter.Value>
			</Setter>
		</Style>
	</ResourceDictionary>       
</Application.Resources>

Additionally, in the RadToggleButton style, you can use the TextBlock and TextElement attached properties. For example:

<Setter Property="TextElement.FontWeight" Value="Bold"/>

I've attached a small sample showing the HeaderButtonStyle approach I am talking about. I hope that helps.

Regards,
Martin Ivanov
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Johnathan
Top achievements
Rank 1
commented on 29 Jun 2022, 04:56 PM

   Thank you Martin!  I can't say I understand it exactly (not your fault, just XAML structure in general), but it definitely works!  I really appreciate the help you and Stenly provided!
Martin Ivanov
Telerik team
commented on 29 Jun 2022, 05:11 PM

It is good to hear that the suggested idea worked.

As for the way it is working here is a brief description that I hope it is going to be helpful. Defining a Style element in WPF without setting its x:Key property will apply it to all controls of the TargetType of the Style in the scope of the style. The scope of the style is the visual tree (the child visual elements) of the element in which Resources collection you added the Style. For example the following Style will be applied to all RadExpander elements in the concrete Grid object.

<Grid>
	<Grid.Resources>
		<Style TargetType="telerik:RadExpander">
			<Setter Property="HeaderButtonStyle">
				<Setter.Value>
					<Style TargetType="telerik:RadToggleButton" BasedOn="{StaticResource ExpanderHeaderButtonStyle}">
						<Setter Property="FontWeight" Value="Bold"/>
						<Setter Property="Foreground" Value="LightCoral" />
					</Style>
				</Setter.Value>
			</Setter>
		</Style>
	</Grid.Resources>
<!-- other elements here -->
</Grid>

The example from my previous reply will apply the Style to all RadExpanders in the application scope. This includes all visual elements in all Windows of the application.

The GenericOfficeBlack.xaml file is embedded in the Telerik.Windows.Controls.dll and it contains the Style for the Telerik controls in the associated dll. This includes all styles for RadExpander and its elements. I need this in order to get access to the ExpanderHeaderButtonStyle. If I don't apply this to the BasedOn property of the Style, it will use the default Style for RadToggleButton which looks different than the expand/collapse button in RadExpander.

I hope that this information helps. 

Tags
Expander Styling
Asked by
Johnathan
Top achievements
Rank 1
Answers by
Martin Ivanov
Telerik team
Share this question
or