Dummy01
Dummy01

Reputation: 1995

Applying default style for TextBlock without affecting ComboBox

I want to have a default style for all TextBlock controls in my application that uses the Royal theme. For example:

<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
    <Setter Property="Margin" Value="4"/>        
</Style>

This works great inherited from the Royal theme but unfortunately also affects the style of TextBlock that is used inside the templates of other controls like ComboBox and I don't want that.

I already tried to place my style one level down (for example inside Grid.Resources) but with no luck.

Is there a way to do that? Of course I don't want to name my style (using x:key) because I don't want to have to explicitly apply to each and every TextBlock of my application the custom style. And without creating subclasses for overwriting the style there.

Any ideas? Thank you in advance!

P.S. I already looked at questions that might be similar but no answer there worked for me.

EDIT:

Thanks for all the answers. I hoped there is some way that I miss with which I can distinguish the TextBlock used inside other controls templates.

Upvotes: 3

Views: 2004

Answers (3)

aifarfa
aifarfa

Reputation: 3939

if You're familiar with HTML and CSS styling. it's common to have specific css style in all element eg. <div class="foo bar"> <input class="boo bar" especially in professional/premium theme.

WPF and XAML implements the same concept. style without using x:key can't satisfy all your needs for complex app UI.

for less writing define data template for combobox and apply specific Style.

    <ComboBox ItemsSource="{Binding Items}">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Style="{StaticResource myComboBoxStyle}" Text="{Binding Path}" /> 
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

Upvotes: 1

Leo
Leo

Reputation: 7449

(sorry for my bad english)

One way is to "force" the TextBlock inside the ComboBox and ComboBoxItem to use another style. It is not very beautiful but it works :)

Just add this to your ResourceDictionary and now you can adjust the looks of the TextBlock inside the ComboBox anyway you want

<!-- Default for all TextBlock -->
   <Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
    <Setter Property="Margin" Value="4"/>
    <Setter Property="Foreground" Value="Green"/>
</Style>

<!-- Applied only to TextBlocks inside ComboBox -->
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}" x:Key="ComboBoxTextBlockStyle">
    <Setter Property="Margin" Value="0"/>
    <Setter Property="Foreground" Value="Blue"/>
</Style>


<Style  TargetType="{x:Type ComboBox}">
    <Setter Property="FocusVisualStyle">
        <Setter.Value>
            <Style>
                <Setter Property="Control.Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Rectangle Margin="4,4,21,4" SnapsToDevicePixels="True" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/>
    <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
    <Setter Property="BorderBrush" Value="#FFA7A6AA"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Padding" Value="0,1"/>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
    <Setter Property="ScrollViewer.PanningMode" Value="Both"/>
    <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ComboBox}">

                <Grid SnapsToDevicePixels="True">

                    <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="1">
                        <Grid Grid.IsSharedSizeScope="True">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="1"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition SharedSizeGroup="ComboBoxButton" Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <Border x:Name="SelectedItemBorder" Grid.ColumnSpan="2" Margin="{TemplateBinding Padding}"/>
                            <ContentPresenter ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" Content="{TemplateBinding SelectionBoxItem}" Grid.Column="1" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">

                                <!-- ADD THIS HERE (SELECTED ITEM)-->
                                <ContentPresenter.Resources>
                                    <Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource ComboBoxTextBlockStyle}"/>
                                </ContentPresenter.Resources>

                            </ContentPresenter>
                            <ToggleButton Grid.ColumnSpan="3" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
                                <ToggleButton.Style>
                                    <Style TargetType="{x:Type ToggleButton}">
                                        <Setter Property="MinWidth" Value="0"/>
                                        <Setter Property="MinHeight" Value="0"/>
                                        <Setter Property="Width" Value="Auto"/>
                                        <Setter Property="Height" Value="Auto"/>
                                        <Setter Property="Background" Value="Transparent"/>
                                        <Setter Property="Focusable" Value="False"/>
                                        <Setter Property="ClickMode" Value="Press"/>
                                        <Setter Property="Template">
                                            <Setter.Value>
                                                <ControlTemplate TargetType="{x:Type ToggleButton}">
                                                    <Grid Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                                                        <Grid.ColumnDefinitions>
                                                            <ColumnDefinition Width="*"/>
                                                            <ColumnDefinition SharedSizeGroup="ComboBoxButton" Width="Auto"/>
                                                        </Grid.ColumnDefinitions>
                                                        <Microsoft_Windows_Themes:ScrollChrome x:Name="Chrome" Grid.Column="1" HasOuterBorder="False" Padding="1,0,0,0" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsChecked}" Microsoft_Windows_Themes:ScrollChrome.ScrollGlyph="DownArrow" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}"/>
                                                    </Grid>
                                                </ControlTemplate>
                                            </Setter.Value>
                                        </Setter>
                                    </Style>
                                </ToggleButton.Style>
                            </ToggleButton>
                        </Grid>
                    </Border>
                    <Popup x:Name="PART_Popup" AllowsTransparency="True" Focusable="False" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
                        <Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{TemplateBinding ActualWidth}">
                            <Border x:Name="DropDownBorder" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
                                <ScrollViewer x:Name="DropDownScrollViewer">
                                    <Grid RenderOptions.ClearTypeHint="Enabled">
                                        <Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
                                            <Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=DropDownBorder}" Height="{Binding ActualHeight, ElementName=DropDownBorder}" Width="{Binding ActualWidth, ElementName=DropDownBorder}"/>
                                        </Canvas>
                                        <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                    </Grid>
                                </ScrollViewer>
                            </Border>
                        </Microsoft_Windows_Themes:SystemDropShadowChrome>
                    </Popup>
                </Grid>
                <ControlTemplate.Triggers>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsSelectionBoxHighlighted" Value="True"/>
                            <Condition Property="IsDropDownOpen" Value="False"/>
                        </MultiTrigger.Conditions>
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                    </MultiTrigger>
                    <Trigger Property="IsSelectionBoxHighlighted" Value="True">
                        <Setter Property="Background" TargetName="SelectedItemBorder" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                    </Trigger>
                    <Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="True">
                        <Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
                        <Setter Property="Color" TargetName="Shdw" Value="#71000000"/>
                    </Trigger>
                    <Trigger Property="HasItems" Value="False">
                        <Setter Property="MinHeight" TargetName="DropDownBorder" Value="95"/>
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="BorderBrush" TargetName="Bd" Value="#FF335EA8"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                    </Trigger>
                    <Trigger Property="IsGrouping" Value="True">
                        <Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
                    </Trigger>
                    <Trigger Property="CanContentScroll" SourceName="DropDownScrollViewer" Value="False">
                        <Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}"/>
                        <Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="IsEditable" Value="True">
            <Setter Property="IsTabStop" Value="False"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ComboBox}">

                        <Grid SnapsToDevicePixels="True">
                            <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="1">
                                <Grid Grid.IsSharedSizeScope="True">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="1"/>
                                        <ColumnDefinition Width="*"/>
                                        <ColumnDefinition SharedSizeGroup="ComboBoxButton" Width="Auto"/>
                                    </Grid.ColumnDefinitions>
                                    <TextBox x:Name="PART_EditableTextBox" Grid.Column="1" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsReadOnly="{Binding IsReadOnly, RelativeSource={RelativeSource TemplatedParent}}" Margin="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
                                        <TextBox.Style>
                                            <Style TargetType="{x:Type TextBox}">
                                                <Setter Property="OverridesDefaultStyle" Value="True"/>
                                                <Setter Property="AllowDrop" Value="True"/>
                                                <Setter Property="MinWidth" Value="0"/>
                                                <Setter Property="MinHeight" Value="0"/>
                                                <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
                                                <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
                                                <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
                                                <Setter Property="Template">
                                                    <Setter.Value>
                                                        <ControlTemplate TargetType="{x:Type TextBox}">
                                                            <ScrollViewer x:Name="PART_ContentHost" Background="Transparent" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" />
                                                        </ControlTemplate>
                                                    </Setter.Value>
                                                </Setter>
                                            </Style>
                                        </TextBox.Style>
                                    </TextBox>
                                    <ToggleButton Background="{x:Null}" Grid.ColumnSpan="3" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
                                        <ToggleButton.Style>
                                            <Style TargetType="{x:Type ToggleButton}">
                                                <Setter Property="MinWidth" Value="0"/>
                                                <Setter Property="MinHeight" Value="0"/>
                                                <Setter Property="Width" Value="Auto"/>
                                                <Setter Property="Height" Value="Auto"/>
                                                <Setter Property="Background" Value="Transparent"/>
                                                <Setter Property="Focusable" Value="False"/>
                                                <Setter Property="ClickMode" Value="Press"/>
                                                <Setter Property="Template">
                                                    <Setter.Value>
                                                        <ControlTemplate TargetType="{x:Type ToggleButton}">
                                                            <Grid Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                                                                <Grid.ColumnDefinitions>
                                                                    <ColumnDefinition Width="*"/>
                                                                    <ColumnDefinition SharedSizeGroup="ComboBoxButton" Width="Auto"/>
                                                                </Grid.ColumnDefinitions>
                                                                <Microsoft_Windows_Themes:ScrollChrome x:Name="Chrome" Grid.Column="1" HasOuterBorder="False" Padding="1,0,0,0" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsChecked}" Microsoft_Windows_Themes:ScrollChrome.ScrollGlyph="DownArrow" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}"/>
                                                            </Grid>
                                                        </ControlTemplate>
                                                    </Setter.Value>
                                                </Setter>
                                            </Style>
                                        </ToggleButton.Style>
                                    </ToggleButton>
                                </Grid>
                            </Border>
                            <Popup x:Name="PART_Popup" AllowsTransparency="True" Focusable="False" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
                                <Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{TemplateBinding ActualWidth}">
                                    <Border x:Name="DropDownBorder" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
                                        <ScrollViewer x:Name="DropDownScrollViewer">
                                            <Grid RenderOptions.ClearTypeHint="Enabled">
                                                <Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
                                                    <Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=DropDownBorder}" Height="{Binding ActualHeight, ElementName=DropDownBorder}" Width="{Binding ActualWidth, ElementName=DropDownBorder}"/>
                                                </Canvas>
                                                <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                            </Grid>
                                        </ScrollViewer>
                                    </Border>
                                </Microsoft_Windows_Themes:SystemDropShadowChrome>
                            </Popup>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="HasItems" Value="False">
                                <Setter Property="MinHeight" TargetName="DropDownBorder" Value="95"/>
                            </Trigger>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="BorderBrush" TargetName="Bd" Value="#FF335EA8"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="False">
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                                <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                            </Trigger>
                            <Trigger Property="IsGrouping" Value="True">
                                <Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
                            </Trigger>
                            <Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="True">
                                <Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
                                <Setter Property="Color" TargetName="Shdw" Value="#71000000"/>
                            </Trigger>
                            <Trigger Property="CanContentScroll" SourceName="DropDownScrollViewer" Value="False">
                                <Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}"/>
                                <Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Trigger>
    </Style.Triggers>
</Style>



<Style  TargetType="{x:Type ComboBoxItem}">
    <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ItemsControl}}}"/>
    <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ItemsControl}}}"/>
    <Setter Property="Padding" Value="3,0"/>
    <Setter Property="Background" Value="Transparent"/>

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ComboBoxItem}">
                <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
                    <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">

                        <!-- ADD THIS HERE (ITEMS LIST DROPDOWN)-->
                        <ContentPresenter.Resources>
                            <Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource ComboBoxTextBlockStyle}"/>
                        </ContentPresenter.Resources>

                    </ContentPresenter>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsHighlighted" Value="True">
                        <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Upvotes: 2

Emond
Emond

Reputation: 50672

By this exclusion:

Of course I don't want to name my style (using x:key) because I don't want to apply to each and every TextBlock of my application the custom style. And without creating subclasses for overwriting the style there.

you pretty much ask the impossible. The style you created will be applied to all TextBlocks in the visual tree below the dictionary that contains the style.

If you want to make exceptions you will have to specify them one way or another.

Apparently your requirement "to have a default style for all TextBlock controls" isn't true. You do NOT want ALL the TextBlocks to have this style.

Moving the style one or more levels down could be a solution if you want the style applied from that level on.

There is no way to specify that you want to apply the style to specific TextBlocks and not to others unless you are able to distinguish between them them in some way.

Upvotes: 1

Related Questions