如何自定义 WPF Ribbon 4.5(样式、模板等)

Posted

技术标签:

【中文标题】如何自定义 WPF Ribbon 4.5(样式、模板等)【英文标题】:How to customize the WPF Ribbon 4.5 (styles, templates, etc.) 【发布时间】:2013-07-03 12:13:10 【问题描述】:

我尝试从 .Net Framework 4.5 中自定义 System.Windows.Controls.Ribbon,以便它可以与 Expression Dark 主题(如 Blend 的默认主题中的深色)一起使用。 我尝试了以下想法,但到目前为止没有任何进展:

更改功能区的背景:将仅更改主 颜色,但保留所有其他光泽颜色、突出颜色等。 更改样式和模板:我找不到任何默认模板 功能区 4.5。我试图通过 ShowMeTheTemplate 等工具获取它们, 但似乎他们使用了一些内部类。 使用 Blend for VS2012 自定义模板:我总是收到错误消息“复制模板失败。” 使用 RibbonControlLibrary 中的 .net 4 功能区:RibbonWindow 在 Windows 8 中看起来很难看(请参阅 WPF RibbonWindow + Windows 8 - control box looks bad),我无法解决

任何帮助将不胜感激,欢迎所有建议。

【问题讨论】:

【参考方案1】:

您可以通过在功能区上设置属性来更改几种颜色:

<ribbon:Ribbon x:Name="Ribbon"
                  Background="Khaki"
                  BorderBrush="Brown"
                  MouseOverBackground="LightCoral"
                  MouseOverBorderBrush="Coral"
                  PressedBackground="LightGreen"
                  PressedBorderBrush="Green"
                  CheckedBackground="LightBlue"
                  CheckedBorderBrush="Blue"
                  FocusedBackground="LightSlateGray"
                  FocusedBorderBrush="SlateBlue">

不完全是一个好看的例子,但展示了如何做到这一点。

也有兴趣如何进行完整的重新造型...

【讨论】:

比没有好;-)【参考方案2】:

我能够使用Show me the templates 提取一个完全正常工作的模板。为此,我对其进行了修改以从“System.Windows.Controls.Ribbon”(而不是主框架程序集)中提取模板。

它给了我以下信息:

https://gist.github.com/drayde/75526b570a266f5f8f38(此处粘贴太长)

只需将其添加到您的资源中并像这样使用它:

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

通过修改模板,您应该可以完全控制功能区的显示方式。

【讨论】:

在功能区设置为最小化的情况下使用此模板,单击菜单项不会展开功能区...【参考方案3】:

我关注this answer 从 VS 获取模板。 它以与 OP 描述的方式相似的方式失败。 然后我使用@Andreas 的要点修补了缺失的部分Binding (0)

为了进行测试,我将视图中的所有颜色属性设置为黑色,并在新创建的模板中设置为 50% 的洋红色。

大约这一次我准备放弃System.Controls.Windows.Ribbon 并尝试Fluent.Ribbon...

模板:

<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>

【讨论】:

以上是关于如何自定义 WPF Ribbon 4.5(样式、模板等)的主要内容,如果未能解决你的问题,请参考以下文章

如何在不覆盖现有样式的情况下向 WPF 自定义控件添加触发器?

WPF中自定义标题栏时窗体最大化处理之WindowChrome

WPF自定义控件与样式(15)-终结篇 & 系列文章索引 & 源码共享

WPF自定义控件与样式-ScrollViewer与ListBox自定义样式

请教wpf中的用户控件,如何模拟出它的close事件

WPF自定义控件与样式-列表控件DataGrid与ListView自定义样式