Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to customize the WPF Ribbon 4.5 (styles, templates, etc.)

I try to customize System.Windows.Controls.Ribbon from the .Net Framework 4.5 so it can be used with the Expression Dark theme (dark colors like in default theme of the Blend). I've tried following ideas, but until now without any progress:

  • change the Background of the ribbon: will change only the main Color, but leaves all other glossy colors, highlight colos etc.
  • change the styles and templates: I couldn't find any default templates for the Ribbon 4.5. I've tried to get them via Tools like ShowMeTheTemplate, but it seems that they use some internal classes.
  • customizing the templates with Blend for VS2012: I get always an error "Copy Template failed."
  • use the .net 4 ribbon from the RibbonControlLibrary: the RibbonWindow Looks ugly in the Windows 8 (see WPF RibbonWindow + Windows 8 - control box looks bad), that I can't solve

Any help would be appreciated, all suggestions are welcome.

like image 655
Alexander Zwitbaum Avatar asked Jul 05 '13 11:07

Alexander Zwitbaum


People also ask

How do I add a ribbon to a WPF project?

1 Step 1: Open Visual Studio 12, then create a new WPF Project. 2 Step 2: Add a Ribbon Bar Reference to right-click on the Project Solution Explorer then select "Add reference" and... 3 Step 3: Add the ribbon control to the code window. More ...

How do I create a ribbon in Visual Studio 12?

Step-by-step Ribbon creates one Ribbon sample Example. Step 1: Open Visual Studio 12, then create a new WPF Project. Step 2: Add a Ribbon Bar Reference to right-click on the Project Solution Explorer then select "Add reference" and search for the system.windows.controls.ribbon dll. Step 3: Add the ribbon control to the code window.

Where is the help button located in WPF ribbon?

Help Icon : The help button is located always on the right side of the Ribbon bar. Step-by-step Ribbon creates one Ribbon sample Example. Step 1: Open Visual Studio 12, then create a new WPF Project.

Can I modify the default controltemplate for the button control?

You can modify the default ControlTemplate to give the control a unique appearance. For more information, see Create a template for a control. The Button control does not have any named parts.


2 Answers

I was able to extract a fully working template using Show me the templates. To do that I modified it to extract templates from "System.Windows.Controls.Ribbon" (rather than the main framework assembly).

It gives me the following:

https://gist.github.com/drayde/75526b570a266f5f8f38 (too long to paste here)

Just add this to your resources and use it like this:

    <Ribbon Template="{StaticResource ribbonTemplate}">
       ...
    </Ribbon>

By modifying the template you should have full control over how your ribbon is displayed.

like image 20
Andreas Kahler Avatar answered Oct 07 '22 15:10

Andreas Kahler


I followed this answer to get a template from VS.
It failed in a similar fashion as OP described.
Then I patched-in the missing parts {Binding (0)} using the gist from @Andreas.

To test, I set all the color properties to black in my view, and 50% magenta in the newly created template.

test app

About this time I am ready to give up on System.Controls.Windows.Ribbon and try Fluent.Ribbon...

Template:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
                xmlns:mwt="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Classic" 
                xmlns:swcrp="clr-namespace:System.Windows.Controls.Ribbon.Primitives;assembly=System.Windows.Controls.Ribbon" 
                xmlns:s="clr-namespace:System;assembly=mscorlib">

<!-- Template Colors -->

<SolidColorBrush x:Key="GroupsInnerBorderBrush" Color="#60FFFFFF"/>
<SolidColorBrush x:Key="QatTopHostBorderBrush1" Color="#66CCCCCC"/>
<SolidColorBrush x:Key="QatTopHostBorderBrush2" Color="#77222222"/>
<SolidColorBrush x:Key="QatTopHostBorderBrush3" Color="#81444444"/>
<SolidColorBrush x:Key="QatTopHostBorderBrush4" Color="#69EEEEEE"/>

<!-- #71000000 -->
<s:Byte x:Key="r">#00</s:Byte>
<s:Byte x:Key="g">#00</s:Byte>
<s:Byte x:Key="b">#00</s:Byte>
<s:Byte x:Key="a">#71</s:Byte>
<Color x:Key="DropShadowColor" R="{StaticResource r}" G="{StaticResource g}" B="{StaticResource b}" A="{StaticResource a}"/>

<LinearGradientBrush x:Key="GroupsBorderBackgroundBrush" EndPoint="0.5,1" StartPoint="0.5,0">
    <GradientStop Color="#EEFFFFFF" Offset="0"/>
    <GradientStop Color="#BBFFFFFF" Offset="0.1"/>
    <GradientStop Color="#05FFFFFF" Offset="0.5"/>
    <GradientStop Color="#20FFFFFF" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="TitleBarBackgroundBrush" EndPoint="0.5,1" StartPoint="0.5,0">
    <GradientStop Color="#EEFFFFFF" Offset="0"/>
    <GradientStop Color="#BBFFFFFF" Offset="0.1"/>
    <GradientStop Color="#05FFFFFF" Offset="0.5"/>
    <GradientStop Color="#20FFFFFF" Offset="1"/>
</LinearGradientBrush>

<!-- Template -->

<ControlTemplate x:Key="RibbonTemplate" TargetType="{x:Type Ribbon}">
    <Grid SnapsToDevicePixels="True">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Border x:Name="BackgroundBorder" Grid.ColumnSpan="3" Grid.Row="1" Grid.RowSpan="3"
                        BorderBrush="{TemplateBinding BorderBrush}" 
                        Background="{TemplateBinding Background}"/>
        <Border Grid.ColumnSpan="3" Grid.Row="1">
            <Popup x:Name="PART_ITEMSPRESENTERPOPUP" AllowsTransparency="True" 
                           IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" 
                           PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}">
                <mwt:SystemDropShadowChrome x:Name="Shdw" Color="Transparent" RenderOptions.ClearTypeHint="Enabled" 
                                                    FocusVisualStyle="{x:Null}" Focusable="True" Margin="0,0,5,5">
                    <Border x:Name="CollapsedPopupBackgroundBorder" Background="{TemplateBinding Background}">
                        <ContentControl x:Name="popupItemsPresenterHost" KeyboardNavigation.DirectionalNavigation="Cycle" 
                                                Focusable="False" Margin="0,1,0,0" KeyboardNavigation.TabNavigation="Cycle"/>
                    </Border>
                </mwt:SystemDropShadowChrome>
            </Popup>
        </Border>
        <ContentControl x:Name="mainItemsPresenterHost" Grid.ColumnSpan="3" Focusable="False" Grid.Row="2">
            <Border x:Name="groupsBorder" BorderThickness="1,0,1,1" Height="91" SnapsToDevicePixels="True"
                            BorderBrush="{TemplateBinding BorderBrush}"  
                            Background="{StaticResource GroupsBorderBackgroundBrush}">
                <Border BorderThickness="0,0,0,1" Margin="0,0,0,1" SnapsToDevicePixels="True"
                                BorderBrush="{StaticResource GroupsInnerBorderBrush}">
                    <ItemsPresenter x:Name="ItemsPresenter"/>
                </Border>
            </Border>
        </ContentControl>
        <Border x:Name="QatBottomHost" Grid.ColumnSpan="3" Grid.Row="3" BorderBrush="{TemplateBinding BorderBrush}">
            <ContentPresenter x:Name="QatBottomHostContentPresenter" IsHitTestVisible="True"
                                      HorizontalAlignment="Left" VerticalAlignment="Center"/>
        </Border>
        <Border x:Name="titleBarBackground" BorderThickness="0,0,0,1" Grid.ColumnSpan="3" Visibility="Collapsed"
                        BorderBrush="{TemplateBinding BorderBrush}" 
                        Background="{StaticResource TitleBarBackgroundBrush}"/>
        <DockPanel Grid.ColumnSpan="3" Grid.Column="0" Height="22" LastChildFill="True">
            <ContentControl x:Name="windowButtonPlaceHolder" DockPanel.Dock="Right" Focusable="False" 
                                    IsHitTestVisible="False" Margin="3,0,0,0" Width="35">
                <ContentControl.Visibility>
                    <TemplateBinding Property="IsHostedInRibbonWindow">
                        <TemplateBindingExtension.Converter>
                            <BooleanToVisibilityConverter />
                        </TemplateBindingExtension.Converter>
                    </TemplateBinding>
                </ContentControl.Visibility>
            </ContentControl>
            <ContentControl x:Name="windowIconPadding" DockPanel.Dock="Left" Focusable="False" 
                                    IsHitTestVisible="False" Margin="0,0,3,0" Width="16"/>
            <swcrp:RibbonTitlePanel x:Name="PART_TitlePanel">
                <Grid x:Name="QatTopHost">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <Border x:Name="QatTopHostLeftBorder" BorderBrush="{StaticResource QatTopHostBorderBrush1}" 
                                    BorderThickness="1,0,1,0.9" Background="{StaticResource QatTopHostBorderBrush2}" Grid.Column="0" 
                                    CornerRadius="0,0,2,2" Margin="8,2,0,2" Width="3"/>

                    <ContentPresenter x:Name="QatTopHostContentPresenter" Grid.Column="1" IsHitTestVisible="True"
                                              Content="{TemplateBinding QuickAccessToolBar}"/>

                    <Border x:Name="QatTopHostRightBorder" BorderBrush="{StaticResource QatTopHostBorderBrush1}" 
                                    BorderThickness="1,0,1,0.9" Background="{StaticResource QatTopHostBorderBrush2}" Grid.Column="2" 
                                    CornerRadius="0,0,2,2" Margin="0,2,1,2" Width="3"/>
                </Grid>

                <ContentPresenter x:Name="PART_TitleHost" ContentTemplate="{TemplateBinding TitleTemplate}" 
                                          Content="{TemplateBinding Title}" ContentSource="Title" 
                                          TextElement.Foreground="{DynamicResource {x:Static SystemColors.ActiveCaptionTextBrushKey}}" 
                                          TextElement.FontWeight="{DynamicResource {x:Static SystemFonts.CaptionFontWeightKey}}" 
                                          TextElement.FontSize="{DynamicResource {x:Static SystemFonts.CaptionFontSizeKey}}" 
                                          TextElement.FontFamily="{DynamicResource {x:Static SystemFonts.CaptionFontFamilyKey}}" 
                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                          IsHitTestVisible="False" Margin="3,0" MinWidth="75" MinHeight="22">

                    <ContentPresenter.Resources>
                        <DataTemplate x:Key="{DataTemplateKey DataType={x:Type s:String}}" DataType="{x:Type s:String}">
                            <TextBlock x:Name="titleTextBlock" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" 
                                               Margin="0,-2,0,0" Text="{TemplateBinding Content}" TextTrimming="CharacterEllipsis"/>
                            <DataTemplate.Triggers>
                                <MultiDataTrigger>
                                    <MultiDataTrigger.Conditions>
                                        <Condition Binding="{Binding Path=(SystemParameters.IsGlassEnabled)}" Value="True"/>
                                        <Condition Binding="{Binding IsHostedInRibbonWindow, RelativeSource={RelativeSource FindAncestor, 
                                                    AncestorLevel=1, AncestorType={x:Type Ribbon}}}" Value="True"/>
                                    </MultiDataTrigger.Conditions>
                                    <Setter Property="Effect" TargetName="titleTextBlock">
                                        <Setter.Value>
                                            <DropShadowEffect BlurRadius="5" Color="White" ShadowDepth="0"/>
                                        </Setter.Value>
                                    </Setter>
                                </MultiDataTrigger>
                                <DataTrigger Binding="{Binding Path=(SystemParameters.IsGlassEnabled)}" Value="False">
                                    <Setter Property="Margin" TargetName="titleTextBlock" Value="0"/>
                                    <Setter Property="VerticalAlignment" TargetName="titleTextBlock" Value="Center"/>
                                </DataTrigger>
                                <DataTrigger Binding="{Binding Path=(SystemParameters.HighContrast)}" Value="True">
                                    <Setter Property="Margin" TargetName="titleTextBlock" Value="0,1,0,0"/>
                                </DataTrigger>
                                <MultiDataTrigger>
                                    <MultiDataTrigger.Conditions>
                                        <Condition Binding="{Binding Path=(SystemParameters.UxThemeName)}" Value="AeroLite"/>
                                        <Condition Binding="{Binding Path=(SystemParameters.IsGlassEnabled)}" Value="False"/>
                                        <Condition Binding="{Binding IsHostedInRibbonWindow, RelativeSource={RelativeSource FindAncestor, 
                                                    AncestorLevel=1, AncestorType={x:Type Ribbon}}}" Value="True"/>
                                        <Condition Binding="{Binding WindowState, RelativeSource={RelativeSource FindAncestor, 
                                                    AncestorLevel=1, AncestorType={x:Type RibbonWindow}}}" Value="Normal"/>
                                    </MultiDataTrigger.Conditions>
                                    <Setter Property="Margin" TargetName="titleTextBlock" Value="0,0,0,7"/>
                                </MultiDataTrigger>
                            </DataTemplate.Triggers>
                        </DataTemplate>
                    </ContentPresenter.Resources>
                </ContentPresenter>
                <RibbonContextualTabGroupItemsControl x:Name="PART_ContextualTabGroupItemsControl" 
                                                              HorizontalAlignment="Center" IsHitTestVisible="True" 
                                                              WindowChrome.IsHitTestVisibleInChrome="True"/>
            </swcrp:RibbonTitlePanel>
        </DockPanel>
        <ContentPresenter x:Name="applicationMenu" Content="{TemplateBinding ApplicationMenu}" Grid.Row="1" VerticalAlignment="Top"/>
        <RibbonTabHeaderItemsControl x:Name="TabHeaderItemsControl" Grid.Column="1" 
                                             HorizontalAlignment="Left" Margin="1,1,1,0" Grid.Row="1" VerticalAlignment="Top"/>
        <ContentPresenter x:Name="PART_HelpPane" ContentTemplate="{TemplateBinding HelpPaneContentTemplate}" 
                                  Content="{TemplateBinding HelpPaneContent}" Grid.Column="2" ContentSource="HelpPaneContent" 
                                  HorizontalAlignment="Right" Grid.Row="1" VerticalAlignment="Top"/>
    </Grid>
    <ControlTemplate.Triggers>
        <Trigger Property="IsCollapsed" Value="True">
            <Setter Property="Visibility" TargetName="applicationMenu" Value="Collapsed"/>
            <Setter Property="Visibility" TargetName="QatBottomHost" Value="Collapsed"/>
            <Setter Property="Visibility" TargetName="QatTopHost" Value="Collapsed"/>
            <Setter Property="Visibility" TargetName="mainItemsPresenterHost" Value="Collapsed"/>
            <Setter Property="Visibility" TargetName="TabHeaderItemsControl" Value="Collapsed"/>
            <Setter Property="Visibility" TargetName="PART_HelpPane" Value="Collapsed"/>
            <Setter Property="Visibility" TargetName="PART_ContextualTabGroupItemsControl" Value="Collapsed"/>
            <Setter Property="MinWidth" TargetName="PART_TitleHost" Value="0"/>
        </Trigger>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsCollapsed" Value="True"/>
                <Condition Property="IsHostedInRibbonWindow" Value="False"/>
            </MultiTrigger.Conditions>
            <Setter Property="Visibility" Value="Collapsed"/>
        </MultiTrigger>
        <Trigger Property="ShowQuickAccessToolBarOnTop" Value="False">
            <Setter Property="Content" TargetName="QatTopHostContentPresenter" Value="{x:Null}"/>
            <Setter Property="Visibility" TargetName="QatTopHost" Value="Collapsed"/>
            <Setter Property="Content" TargetName="QatBottomHostContentPresenter" 
                            Value="{Binding QuickAccessToolBar, RelativeSource={RelativeSource TemplatedParent}}"/>
            <Setter Property="BorderThickness" TargetName="BackgroundBorder" Value="0,0,0,1"/>
        </Trigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding QuickAccessToolBar.HasItems, RelativeSource={RelativeSource Self}}" Value="False"/>
                <Condition Binding="{Binding QuickAccessToolBar.CustomizeMenuButton, RelativeSource={RelativeSource Self}}" Value="{x:Null}"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Visibility" TargetName="QatTopHost" Value="Collapsed"/>
            <Setter Property="Visibility" TargetName="QatBottomHost" Value="Collapsed"/>
        </MultiDataTrigger>
        <Trigger Property="IsMinimized" Value="True">
            <Setter Property="Content" TargetName="mainItemsPresenterHost" Value="{x:Null}"/>
            <Setter Property="Visibility" TargetName="mainItemsPresenterHost" Value="Collapsed"/>
            <Setter Property="Content" TargetName="popupItemsPresenterHost" Value="{Binding ElementName=groupsBorder}"/>
            <Setter Property="BorderThickness" TargetName="BackgroundBorder" Value="0,0,0,1"/>
        </Trigger>
        <Trigger Property="WindowIconVisibility" Value="Collapsed">
            <Setter Property="Visibility" TargetName="windowIconPadding" Value="Collapsed"/>
            <Setter Property="Visibility" TargetName="QatTopHostLeftBorder" Value="Collapsed"/>
        </Trigger>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsMinimized" Value="True"/>
                <Condition Property="ShowQuickAccessToolBarOnTop" Value="False"/>
            </MultiTrigger.Conditions>
            <Setter Property="BorderThickness" TargetName="QatBottomHost" Value="0,1,0,0"/>
        </MultiTrigger>
        <Trigger Property="IsHostedInRibbonWindow" Value="False">
            <Setter Property="Grid.Row" TargetName="BackgroundBorder" Value="0"/>
            <Setter Property="Grid.RowSpan" TargetName="BackgroundBorder" Value="4"/>
            <Setter Property="Visibility" TargetName="titleBarBackground" Value="Visible"/>
            <Setter Property="Visibility" TargetName="windowIconPadding" Value="Collapsed"/>
            <Setter Property="Visibility" TargetName="QatTopHostLeftBorder" Value="Collapsed"/>
        </Trigger>
        <Trigger Property="IsDropDownOpen" Value="True">
            <Setter Property="BorderThickness" TargetName="BackgroundBorder" Value="0"/>
        </Trigger>
        <Trigger Property="HasDropShadow" SourceName="PART_ITEMSPRESENTERPOPUP" Value="True">
            <Setter Property="Color" TargetName="Shdw" Value="{StaticResource DropShadowColor}"/>
        </Trigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsActive, RelativeSource={RelativeSource FindAncestor, 
                            AncestorLevel=1, AncestorType={x:Type RibbonWindow}}}" Value="False"/>
                <Condition Binding="{Binding Path=(SystemParameters.IsGlassEnabled)}" Value="False"/>
                <Condition Binding="{Binding IsHostedInRibbonWindow, RelativeSource={RelativeSource Self}}" Value="True"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="TextElement.Foreground" TargetName="PART_TitleHost" 
                            Value="{DynamicResource {x:Static SystemColors.InactiveCaptionTextBrushKey}}"/>
        </MultiDataTrigger>
        <DataTrigger Binding="{Binding Path=(SystemParameters.UxThemeName)}" Value="Aero">
            <Setter Property="Margin" TargetName="QatTopHost" Value="0,-3,0,0"/>
            <Setter Property="Margin" TargetName="QatTopHostLeftBorder" Value="3,3,0,5"/>
            <Setter Property="Background" TargetName="QatTopHostLeftBorder" Value="{StaticResource QatTopHostBorderBrush3}"/>
            <Setter Property="BorderBrush" TargetName="QatTopHostLeftBorder" Value="{StaticResource QatTopHostBorderBrush4}"/>
            <Setter Property="Margin" TargetName="QatTopHostRightBorder" Value="0,3,1,5"/>
            <Setter Property="Background" TargetName="QatTopHostRightBorder" Value="{StaticResource QatTopHostBorderBrush3}"/>
            <Setter Property="BorderBrush" TargetName="QatTopHostRightBorder" Value="{StaticResource QatTopHostBorderBrush4}"/>
        </DataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding Path=(SystemParameters.UxThemeName)}" Value="Aero"/>
                <Condition Binding="{Binding WindowState, RelativeSource={RelativeSource FindAncestor, 
                            AncestorLevel=1, AncestorType={x:Type RibbonWindow}}}" Value="Maximized"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Margin" TargetName="QatTopHost" Value="0"/>
        </MultiDataTrigger>
    </ControlTemplate.Triggers>
</ControlTemplate>
like image 100
Scott Solmer Avatar answered Oct 07 '22 16:10

Scott Solmer