Current filter:
                                You should refresh the page.
                                  • Hi,

                                    I am looking to customise the standard ControlTemplate for controlling the theme of toolbar buttons (BarButtonItem, BarCheckItem, etc.). Here is the default found in DevExpress.Xpf.Themes.Office2019Colorful\Core\Core\Bars\Themes\Office2019Colorful\BarItems\BarItems.xaml:

                                    [XAML]
                                    <ControlTemplate x:Key="{dxbt:BarItemBorderThemeKey ResourceKey=Normal}" TargetType="{x:Type dxb:ItemBorderControl}"> <Grid x:Name="Root"> <Border x:Name="IsDefault" Background="Transparent" BorderBrush="Transparent" BorderThickness="1" cs:id="Border_0000"/> <Border x:Name="IsCustomization" BorderBrush="$Focused" BorderThickness="1" Opacity="0" cs:id="Border_0001"/> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="HideBorderSide"> <VisualState x:Name="None"/> <VisualState x:Name="Top"> <Storyboard> <ObjectAnimationUsingKeyFrames dxi:ValueSetter.Thickness="0,0,0,1" Storyboard.TargetName="Root" Storyboard.TargetProperty="Margin"/> </Storyboard> </VisualState> <VisualState x:Name="Right"> <Storyboard> <ObjectAnimationUsingKeyFrames dxi:ValueSetter.Thickness="0,0,1,0" Storyboard.TargetName="Root" Storyboard.TargetProperty="Margin"/> </Storyboard> </VisualState> <VisualState x:Name="Left"> <Storyboard> <ObjectAnimationUsingKeyFrames dxi:ValueSetter.Thickness="0" Storyboard.TargetName="Root" Storyboard.TargetProperty="Margin"/> </Storyboard> </VisualState> <VisualState x:Name="Bottom"> <Storyboard> <ObjectAnimationUsingKeyFrames dxi:ValueSetter.Thickness="0" Storyboard.TargetName="Root" Storyboard.TargetProperty="Margin"/> </Storyboard> </VisualState> <VisualState x:Name="All"/> </VisualStateGroup> <VisualStateGroup x:Name="ActiveState"> <VisualState x:Name="Active"> <Storyboard> <DoubleAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="Opacity" To="1"/> </Storyboard> </VisualState> <VisualState x:Name="Inactive"> <Storyboard> <DoubleAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="Opacity" To="0.62"/> </Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="State"> <VisualState x:Name="Normal"> <Storyboard> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="Transparent" cs:id="ColorAnimation_0000"/> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="Transparent" cs:id="ColorAnimation_0007"/> </Storyboard> </VisualState> <VisualState x:Name="Hover"> <Storyboard> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="$HoverAltBackground" cs:id="ColorAnimation_0001"/> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="$HoverAltBorder" cs:id="ColorAnimation_0008"/> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="$SelectionAltBackground" cs:id="ColorAnimation_0002"/> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="$SelectionAltBorder" cs:id="ColorAnimation_0009"/> </Storyboard> </VisualState> <VisualState x:Name="Disabled"/> <VisualState x:Name="Checked"> <Storyboard> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="$SelectionAltBackground" cs:id="ColorAnimation_0003"/> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="$SelectionAltBorder" cs:id="ColorAnimation_0010"/> </Storyboard> </VisualState> <VisualState x:Name="HoverChecked"> <Storyboard> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="$SelectionAltBackground" cs:id="ColorAnimation_0004"/> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="$SelectionAltBorder" cs:id="ColorAnimation_0011"/> </Storyboard> </VisualState> <VisualState x:Name="Indeterminate"> <Storyboard> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="$HoverAltBackground" cs:id="ColorAnimation_0005"/> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="$HoverAltBorder" cs:id="ColorAnimation_0012"/> </Storyboard> </VisualState> <VisualState x:Name="Focused"> <Storyboard> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="$HoverAltBackground" cs:id="ColorAnimation_0006"/> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="$Focused" cs:id="ColorAnimation_0013"/> </Storyboard> </VisualState> <VisualState x:Name="Customization"> <Storyboard> <DoubleAnimation Duration="0" Storyboard.TargetName="IsCustomization" Storyboard.TargetProperty="Opacity" To="1"/> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> </Grid> </ControlTemplate>

                                    Modifying the content of this is straightforward enough - what I need to know is how to pick up the appropriate colours from the currently active theme in place of the "$Focused", "$HoverAltBackground", "$HoverAltBorder", "$SelectionAltBackground" and "$SelectionAltBorder" placeholders.

                                    I have reviewed the following article but going down the route of implementing a custom control just to change the background and border for various visual states of a toolbar button seems massive overkill:
                                    https://www.devexpress.com/Support/Center/Question/Details/K18542/how-to-implement-the-thememananger-theme-support-in-custom-controls

                                    Essentially, I want this one ControlTemplate to pick up the current theme's colours regardless of what theme is currently active. Is there some kind of binding that I can put in place of "$Focused" etc. that will pick up the current theme's specified colour, e.g. "{Binding dx:ThemeManager.Palette.FocusedColor}"?

                                    Let me know, thanks,
                                    Gareth

                                • Ivan (DevExpress Support) 09.20.2019

                                  Hi again,

                                  Theme Designer replaces "$HoverAltBackground", "$HoverAltBorder", and other values with colors from the palette when you publish a theme. For our built-in themes, you can find these colors in these themes' source code. For example:

                                  <VisualState x:Name="Normal">
                                    <Storyboard>
                                      <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="Transparent" cs:id="ColorAnimation_0000" />
                                      <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="Transparent" cs:id="ColorAnimation_0007" />
                                    </Storyboard>
                                  </VisualState>
                                  <VisualState x:Name="Hover">
                                    <Storyboard>
                                      <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="#FFEFF6FC" cs:id="ColorAnimation_0001" x:Uid="@To=HoverBackground" />
                                      <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="#FFEFF6FC" cs:id="ColorAnimation_0008" x:Uid="@To=HoverBorder" />
                                    </Storyboard>
                                  </VisualState>
                                  

                                  There is no way to dynamically pick up these colors for objects like ColorAnimation. Taking this and your T816281 ticket into account, could you please clarify what kind of customization you're planning to implement? Perhaps, we will be able to suggest a better alternative.

                                • Gareth Thom 09.20.2019

                                  Hi Ivan,

                                  In the app we are writing we want to have two styles of toolbar menu - one at the very top of the application with one theme and all others a different theme. I suppose it would be similar to a website design with main menu navigation then sub menu options in a different style. These toolbars will also look slightly different to help keep them as distinct UI elements with different functions, we therefore cannot use the one theme to cover both toolbar types.

                                  The main toolbar at the top of the application essentially has some standard menu button options aligned to the left and right, with a series of grouped check buttons representing modules (or pages in website terms) with a highlight to indicate the currently active option. All content below this in the rest of the app will be related to the selected module, including a sub-menu with specific toolbar options/actions.

                                  We essentially want the active module to be underlined with a light background, as opposed to fully highlighted like a standard menu check button. Here is the XAML we have come up with to do this based on your standard template:

                                  [XAML]
                                  <ControlTemplate x:Key="{dxbt:BarItemBorderThemeKey ResourceKey=Normal, IsThemeIndependent=True}" TargetType="{x:Type dxb:ItemBorderControl}"> <Grid x:Name="Root" > <Border x:Name="IsDefault" Background="Transparent" BorderBrush="Transparent" BorderThickness="1"/> <!--BorderBrush="$Focused"--> <Border x:Name="IsCustomization" BorderBrush="#FFD70A31" BorderThickness="1" Opacity="0"/> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="HideBorderSide"> <VisualState x:Name="None"/> <VisualState x:Name="Top"> <Storyboard> <ObjectAnimationUsingKeyFrames dxi:ValueSetter.Thickness="0,0,0,1" Storyboard.TargetName="Root" Storyboard.TargetProperty="Margin"/> </Storyboard> </VisualState> <VisualState x:Name="Right"> <Storyboard> <ObjectAnimationUsingKeyFrames dxi:ValueSetter.Thickness="0,0,1,0" Storyboard.TargetName="Root" Storyboard.TargetProperty="Margin"/> </Storyboard> </VisualState> <VisualState x:Name="Left"> <Storyboard> <ObjectAnimationUsingKeyFrames dxi:ValueSetter.Thickness="0" Storyboard.TargetName="Root" Storyboard.TargetProperty="Margin"/> </Storyboard> </VisualState> <VisualState x:Name="Bottom"> <Storyboard> <ObjectAnimationUsingKeyFrames dxi:ValueSetter.Thickness="0" Storyboard.TargetName="Root" Storyboard.TargetProperty="Margin"/> </Storyboard> </VisualState> <VisualState x:Name="All"/> </VisualStateGroup> <VisualStateGroup x:Name="ActiveState"> <VisualState x:Name="Active"> <Storyboard> <DoubleAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="Opacity" To="1"/> </Storyboard> </VisualState> <VisualState x:Name="Inactive"> <Storyboard> <DoubleAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="Opacity" To="0.62"/> </Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="State"> <VisualState x:Name="Normal"> <Storyboard> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="Transparent"/> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="Transparent"/> </Storyboard> </VisualState> <VisualState x:Name="Hover"> <Storyboard> <!--To="$HoverAltBackground"/>--> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="#FFF3B6C1"/> <!--To="$HoverAltBorder"/>--> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="#FFF3B6C1"/> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <!--To="$SelectionAltBackground"/>--> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="#FFD70A31"/> <!--To="$SelectionAltBorder"/>--> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="#FFD70A31"/> </Storyboard> </VisualState> <VisualState x:Name="Disabled"/> <VisualState x:Name="Checked"> <Storyboard> <!--To="$SelectionAltBackground"/>--> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="#FFF7D3DA"/> <!--To="$SelectionAltBorder"/>--> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="#FFD70A31"/> <ThicknessAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="BorderThickness" To="0,0,0,3"/> </Storyboard> </VisualState> <VisualState x:Name="HoverChecked"> <Storyboard> <!--To="$SelectionAltBackground"/>--> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="#FFF3B6C1"/> <!--To="$SelectionAltBorder"/>--> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="#FFD70A31"/> <ThicknessAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="BorderThickness" To="0,0,0,3"/> </Storyboard> </VisualState> <VisualState x:Name="Indeterminate"> <Storyboard> <!--To="$HoverAltBackground"/>--> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="#FFF3B6C1"/> <!--To="$HoverAltBorder"/>--> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="#FFF3B6C1"/> </Storyboard> </VisualState> <VisualState x:Name="Focused"> <Storyboard> <!--To="$HoverAltBackground"/>--> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="#FFF3B6C1"/> <!--To="$Focused"/>--> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="#FFD70A31"/> </Storyboard> </VisualState> <VisualState x:Name="Customization"> <Storyboard> <DoubleAnimation Duration="0" Storyboard.TargetName="IsCustomization" Storyboard.TargetProperty="Opacity" To="1"/> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> </Grid> </ControlTemplate>

                                  However, instead of hard coding colours like in this example, we just want to override the template and use the standard colours of whatever theme is selected. We would then allow the user to select one of your own standard templates (e.g. Office 2019 White/Black/etc.) or our own "Red" themed one (which the colours in the template above are approximating for now).

                                  I have attached a screenshot of what we have so far (which is very much a work in progress with nothing set in stone - mostly just trying out ideas) - this shows the top toolbar line (which is actually split into 3 toolbar controls in order to get the spacing and alignment, etc. working we way we want it) with a white background and red underline on checked items; and it shows the second toolbar on the right hand side of the next section down with the bright red background.

                                  Do you have any other suggestions on how to handle this? We really want to be able to offer users the choice of standard theme but without us having to create a ControlTemplate for every possible theme we might include!

                                  Let me know, thanks,
                                  Gareth

                                • Gareth Thom 09.23.2019

                                  Hi Ivan,

                                  I've been looking into this all weekend and think I'm now getting somewhere.

                                  Searching through the Theme Designers generated code I came across the Core\Core\Themes\Office2019Colorful\Palettes_Base.xaml class which contains *almost* all of the colours and corresponding brushes defined using your official theme keys:

                                  [XAML]
                                  <ResourceDictionary mc:Ignorable="cs" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:cs="colorscheme_ignorable_uri" xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" xmlns:dxt="http://schemas.devexpress.com/winfx/2008/xaml/core/themekeys" xmlns:input="clr-namespace:System.Windows.Input;assembly=PresentationCore" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Backstage.Button.Background}">$Backstage.Button.Background</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Backstage.Delimiter}">$Backstage.Delimiter</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Backstage.Editor.Background}">$Backstage.Editor.Background</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Backstage.Focused}">$Backstage.Focused</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Backstage.Foreground}">$Backstage.Foreground</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Backstage.HoverBackground}">$Backstage.HoverBackground</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Backstage.SelectionBackground}">$Backstage.SelectionBackground</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Backstage.Window.Background}">$Backstage.Window.Background</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Border}">$Border</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Button.Background}">$Button.Background</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Control.Background}">$Control.Background</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Custom.Blue}">$Custom.Blue</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Custom.Green}">$Custom.Green</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Custom.Red}">$Custom.Red</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Delimiter}">$Delimiter</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Editor.Background}">$Editor.Background</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Focused}">$Focused</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Foreground}">$Foreground</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=HoverBackground}">$HoverBackground</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=HoverBorder}">$HoverBorder</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=HoverForeground}">$HoverForeground</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=SelectionBackground}">$SelectionBackground</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=SelectionBorder}">$SelectionBorder</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=SelectionForeground}">$SelectionForeground</Color> <Color x:Key="{dxt:PaletteColorThemeKey ResourceKey=Window.Background}">$Window.Background</Color> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Backstage.Button.Background}">$Backstage.Button.Background</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Backstage.Delimiter}">$Backstage.Delimiter</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Backstage.Editor.Background}">$Backstage.Editor.Background</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Backstage.Focused}">$Backstage.Focused</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Backstage.Foreground}">$Backstage.Foreground</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Backstage.HoverBackground}">$Backstage.HoverBackground</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Backstage.SelectionBackground}">$Backstage.SelectionBackground</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Backstage.Window.Background}">$Backstage.Window.Background</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Border}">$Border</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Button.Background}">$Button.Background</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Control.Background}">$Control.Background</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Custom.Blue}">$Custom.Blue</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Custom.Green}">$Custom.Green</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Custom.Red}">$Custom.Red</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Delimiter}">$Delimiter</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Editor.Background}">$Editor.Background</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Focused}">$Focused</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Foreground}">$Foreground</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=HoverBackground}">$HoverBackground</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=HoverBorder}">$HoverBorder</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=HoverForeground}">$HoverForeground</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=SelectionBackground}">$SelectionBackground</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=SelectionBorder}">$SelectionBorder</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=SelectionForeground}">$SelectionForeground</SolidColorBrush> <SolidColorBrush x:Key="{dxt:PaletteBrushThemeKey ResourceKey=Window.Background}">$Window.Background</SolidColorBrush> </ResourceDictionary>

                                  It turns out that the new 'Alt' palette colour names have not yet been added. Can you please get theses added for a forthcoming release? Thanks!

                                  I know these are only defined for the more modern themes, but that's all we would be aiming to use so I'm happy enough with that (although I'm sure it would be better if all of these palette colours were defined for each style in the same way!).

                                  Further searching lead me to this article:
                                  https://www.devexpress.com/Support/Center/Question/Details/Q576869/how-to-set-themename-parameter-dynamically

                                  Which in turn led me to your official ThemeResource MarkupExtension class:
                                  https://www.devexpress.com/Support/Center/Example/Details/T207471/how-to-use-the-themeresource-extension-to-load-resources-from-devexpress-themes

                                  On the surface, this seemed exactly like what I was looking for. When combined with the palette colours and brushes defined using official theme keys it would be perfect, and it is for customising colours directly on controls like the following it is:

                                  [XAML]
                                  <Border x:Name="ThisBorder" Margin="20" Padding="20" BorderThickness="10" Background="{dxi:ThemeResource ThemeKey={dxt:PaletteBrushThemeKey ResourceKey=Focused}}" BorderBrush="{dxi:ThemeResource ThemeKey={dxt:PaletteBrushThemeKey ResourceKey=SelectionBackground}}" Grid.ColumnSpan="2">

                                  However, it turns out that because ColorAnimation does not inherit from FrameworkElement it cannot be used in this scenario. I therefore set about trying to figure out how to resolve this.

                                  Investigating the example in Q576869, the problem is that provideValueTarget.TargetObject cannot be cast to FrameworkElement so it fails. The problem is that in order to get the actual theme resource you need to be able to call FrameworkElement.FindResource(themeKey) which is not available on Freezable objects (that ColorAnimation is derived from). However, IServiceProvider also exposes IRootObjectProvider, which gives access to the Window the control is on and this can be used instead!

                                  I have therefore modified this example to the following:

                                  [C#]
                                  public class ThemeResourceEx : MarkupExtension { //static ReflectionHelper reflectionHelper = new ReflectionHelper(); FrameworkElement targetElement; FrameworkElement targetObject_FrameworkElement; Freezable targetObject_Freezable; DependencyProperty targetProperty; PropertyInfo ResourceKeyInfo; ThemeKeyExtensionGeneric themeKey; FrameworkElement rootElement; public ThemeResourceEx() { } public ThemeResourceEx(ThemeKeyExtensionGeneric themeKey) { if (themeKey != null) ThemeKey = themeKey; } public ThemeKeyExtensionGeneric ThemeKey { get { return themeKey; } set { if (themeKey == value) return; themeKey = value; ResourceKeyInfo = ThemeKey.GetType().GetProperty("ResourceKey"); OnThemeKeyChanged(); } } public override object ProvideValue(IServiceProvider serviceProvider) { if (serviceProvider.GetService(typeof(IRootObjectProvider)) is IRootObjectProvider rootProvider) { object rootObject = rootProvider.RootObject; if (rootObject != null) rootElement = rootObject as FrameworkElement; } if (!(serviceProvider is IProvideValueTarget provideValueTarget)) return null; targetObject_Freezable = provideValueTarget.TargetObject as Freezable; targetObject_FrameworkElement = provideValueTarget.TargetObject as FrameworkElement; targetElement = targetObject_FrameworkElement ?? rootElement; targetProperty = provideValueTarget.TargetProperty as DependencyProperty; if (targetElement == null || (targetObject_FrameworkElement == null && targetObject_Freezable == null) || targetProperty == null) return null; var descriptor = DependencyPropertyDescriptor.FromProperty(ThemeManager.TreeWalkerProperty, provideValueTarget.TargetObject.GetType()); descriptor.AddValueChanged(provideValueTarget.TargetObject, OnTreeWalkerChanged); return GetThemeResource(); } private void OnTreeWalkerChanged(object sender, EventArgs e) { UpdateTargetProperty(); } private void OnThemeKeyChanged() { UpdateTargetProperty(); } void UpdateTargetProperty() { if (targetObject_FrameworkElement != null) { targetObject_FrameworkElement.SetValue(targetProperty, GetThemeResource()); } else if (targetObject_Freezable != null) { targetObject_Freezable.SetValue(targetProperty, GetThemeResource()); } } object GetThemeResource() { ThemeKeyExtensionGeneric themeKey = Activator.CreateInstance(ThemeKey.GetType()) as ThemeKeyExtensionGeneric; themeKey.ThemeName = GetThemeName(); //reflectionHelper.SetPropertyValue(themeKey, "ResourceKey", reflectionHelper.GetPropertyValue(ThemeKey, "ResourceKey")); var value = ResourceKeyInfo.GetValue(ThemeKey, null); ResourceKeyInfo.SetValue(themeKey, value, null); return targetElement.TryFindResource(themeKey); } string GetThemeName() { var treeWalker = targetElement.GetValue(ThemeManager.TreeWalkerProperty) as ThemeTreeWalker; if (treeWalker == null) return null; return treeWalker.ThemeName; } }

                                  This now allows me to modify my ControlTemplate as follows and everything works perfectly:

                                  [XAML]
                                  <ControlTemplate x:Key="{dxbt:BarItemBorderThemeKey ResourceKey=Normal, IsThemeIndependent=True}" TargetType="{x:Type dxb:ItemBorderControl}"> <Grid x:Name="Root" > <Border x:Name="IsDefault" Background="Transparent" BorderBrush="Transparent" BorderThickness="1"/> <Border x:Name="IsCustomization" BorderBrush="{local:ThemeResourceEx ThemeKey={dxt:PaletteBrushThemeKey ResourceKey=Focused}}" BorderThickness="1" Opacity="0"/> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="HideBorderSide"> <VisualState x:Name="None"/> <VisualState x:Name="Top"> <Storyboard> <ObjectAnimationUsingKeyFrames dxi:ValueSetter.Thickness="0,0,0,1" Storyboard.TargetName="Root" Storyboard.TargetProperty="Margin"/> </Storyboard> </VisualState> <VisualState x:Name="Right"> <Storyboard> <ObjectAnimationUsingKeyFrames dxi:ValueSetter.Thickness="0,0,1,0" Storyboard.TargetName="Root" Storyboard.TargetProperty="Margin"/> </Storyboard> </VisualState> <VisualState x:Name="Left"> <Storyboard> <ObjectAnimationUsingKeyFrames dxi:ValueSetter.Thickness="0" Storyboard.TargetName="Root" Storyboard.TargetProperty="Margin"/> </Storyboard> </VisualState> <VisualState x:Name="Bottom"> <Storyboard> <ObjectAnimationUsingKeyFrames dxi:ValueSetter.Thickness="0" Storyboard.TargetName="Root" Storyboard.TargetProperty="Margin"/> </Storyboard> </VisualState> <VisualState x:Name="All"/> </VisualStateGroup> <VisualStateGroup x:Name="ActiveState"> <VisualState x:Name="Active"> <Storyboard> <DoubleAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="Opacity" To="1"/> </Storyboard> </VisualState> <VisualState x:Name="Inactive"> <Storyboard> <DoubleAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="Opacity" To="0.62"/> </Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="State"> <VisualState x:Name="Normal"> <Storyboard> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="Transparent"/> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="Transparent"/> </Storyboard> </VisualState> <VisualState x:Name="Hover"> <Storyboard> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="{local:ThemeResourceEx ThemeKey={dxt:PaletteColorThemeKey ResourceKey=HoverBackground}}"/> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="{local:ThemeResourceEx ThemeKey={dxt:PaletteColorThemeKey ResourceKey=HoverBorder}}"/> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="{local:ThemeResourceEx ThemeKey={dxt:PaletteColorThemeKey ResourceKey=SelectionBackground}}"/> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="{local:ThemeResourceEx ThemeKey={dxt:PaletteColorThemeKey ResourceKey=Backstage.SelectionBackground}}"/> <ThicknessAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="BorderThickness" To="0,0,0,3"/> </Storyboard> </VisualState> <VisualState x:Name="Disabled"/> <VisualState x:Name="Checked"> <Storyboard> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="{local:ThemeResourceEx ThemeKey={dxt:PaletteColorThemeKey ResourceKey=SelectionBackground}}"/> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="{local:ThemeResourceEx ThemeKey={dxt:PaletteColorThemeKey ResourceKey=Focused}}"/> <ThicknessAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="BorderThickness" To="0,0,0,3"/> </Storyboard> </VisualState> <VisualState x:Name="HoverChecked"> <Storyboard> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="{local:ThemeResourceEx ThemeKey={dxt:PaletteColorThemeKey ResourceKey=SelectionBackground}}"/> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="{local:ThemeResourceEx ThemeKey={dxt:PaletteColorThemeKey ResourceKey=Backstage.HoverBackground}}"/> <ThicknessAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="BorderThickness" To="0,0,0,3"/> </Storyboard> </VisualState> <VisualState x:Name="Indeterminate"> <Storyboard> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="{local:ThemeResourceEx ThemeKey={dxt:PaletteColorThemeKey ResourceKey=HoverBackground}}"/> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="{local:ThemeResourceEx ThemeKey={dxt:PaletteColorThemeKey ResourceKey=HoverBorder}}"/> </Storyboard> </VisualState> <VisualState x:Name="Focused"> <Storyboard> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="{local:ThemeResourceEx ThemeKey={dxt:PaletteColorThemeKey ResourceKey=HoverBackground}}"/> <ColorAnimation Duration="0" Storyboard.TargetName="IsDefault" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="{local:ThemeResourceEx ThemeKey={dxt:PaletteColorThemeKey ResourceKey=Focused}}"/> </Storyboard> </VisualState> <VisualState x:Name="Customization"> <Storyboard> <DoubleAnimation Duration="0" Storyboard.TargetName="IsCustomization" Storyboard.TargetProperty="Opacity" To="1"/> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> </Grid> </ControlTemplate>

                                  The only problem that I have found is that themes are not applied at design time, due to IRootObjectProvider not exposing the window whilst in Visual Studio.

                                  ...

                                • Gareth Thom 09.23.2019

                                  I did notice that your standard DevExpress.Xpf.Core\DevExpress.Xpf.Core\Themes\ThemeManager\ThemeResource.cs class does appear to be able to show the correct theme at design time, so I investigated it too and have found that, although it works in a completely different way by picking up bindings and using a converter, it can also be modified to work with Freezable classes.

                                  I'm sure there will be a better way than what I have come up with, but I've spent to long on this already! Other than the same problem with the Freezable object not exposing a FrameworkElement, the other issue was that the ThemeTreeWalker passed into values[0] was null.

                                  The changes I made to resolves these issues are:
                                   - Added a RootProvider property to DXMarkupExtensionBase to get the IRootObjectProvider from IServiceProvider
                                   - Added a RootElement property to ThemeResourceConverter
                                   - Updated ThemeResourceExExtension.CreateBinding to pass the RootElement to the Converter
                                   - Updated ThemeResourceConverter.Convert to pick up the RootElement if the element returned from values[2] is not a framework element
                                   - Updated  ThemeResourceConverter.Convert to get the ThemeTreeWalker from the available framework element

                                  [C#]
                                  using System; using System.Linq; using System.Windows; using System.Windows.Data; using DevExpress.Mvvm.Native; using DevExpress.Mvvm.UI.Interactivity; using DevExpress.Xpf.Core; using DevExpress.Xpf.Core.Internal; using DevExpress.Xpf.Utils.Themes; namespace WpfApplication1 { public abstract class DXMarkupExtensionBaseEx : MarkupExtension { internal static bool? IsInDesingModeCore = null; protected static bool IsInDesignMode() { if (IsInDesingModeCore != null) return IsInDesingModeCore.Value; DependencyPropertyDescriptor property = DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty, typeof(FrameworkElement)); return (bool)property.Metadata.DefaultValue; } protected static string GetTargetPropertyName(object targetProperty) { return (targetProperty as DependencyProperty).With(x => x.Name) ?? (targetProperty as PropertyInfo).With(x => x.Name) ?? (targetProperty as MethodBase).With(x => x.Name) ?? (targetProperty as EventInfo).With(x => x.Name); } protected static Type GetTargetPropertyType(object targetProperty) { return (targetProperty as DependencyProperty).With(x => x.PropertyType) ?? (targetProperty as PropertyInfo).With(x => x.PropertyType) ?? (targetProperty as EventInfo).With(x => x.EventHandlerType); } protected static bool IsInSetter(IProvideValueTarget targetProvider) { if (targetProvider == null) return false; return targetProvider.TargetObject is Setter; } protected static bool IsInTemplate(IProvideValueTarget targetProvider) { if (targetProvider == null) return false; return targetProvider.TargetObject.GetType().FullName == "System.Windows.SharedDp"; } protected static bool IsInBinding(IProvideValueTarget targetProvider) { if (targetProvider == null) return false; return targetProvider.TargetObject is BindingBase; } IServiceProvider serviceProvider; IProvideValueTarget targetProvider; IXamlTypeResolver xamlTypeResolver; IXamlSchemaContextProvider xamlSchemaContextProvider; protected IServiceProvider ServiceProvider { get { return serviceProvider; } } protected IProvideValueTarget TargetProvider { get { if (targetProvider != null) return targetProvider; if (serviceProvider == null) return null; return targetProvider = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget)); } } IRootObjectProvider rootProvider; protected IRootObjectProvider RootProvider { get { if (rootProvider != null) return rootProvider; if (serviceProvider == null) return null; return rootProvider = (IRootObjectProvider)serviceProvider.GetService(typeof(IRootObjectProvider)); } } protected IXamlTypeResolver XamlTypeResolver { get { if (xamlTypeResolver != null) return xamlTypeResolver; if (serviceProvider == null) return null; return xamlTypeResolver = (IXamlTypeResolver)serviceProvider.GetService(typeof(IXamlTypeResolver)); } } protected IXamlSchemaContextProvider XamlSchemaContextProvider { get { if (xamlSchemaContextProvider != null) return xamlSchemaContextProvider; if (serviceProvider == null) return null; return xamlSchemaContextProvider = (IXamlSchemaContextProvider)serviceProvider.GetService(typeof(IXamlSchemaContextProvider)); } } public sealed override object ProvideValue(IServiceProvider serviceProvider) { try { this.serviceProvider = serviceProvider; return ProvideValueCore(); } finally { this.serviceProvider = null; this.targetProvider = null; this.xamlTypeResolver = null; } } protected abstract object ProvideValueCore(); } public sealed class ThemeResourceExExtension : DXMarkupExtensionBaseEx { public ThemeResourceExExtension() { } public ThemeResourceExExtension(ThemeKeyExtensionGeneric themeKey) { if (themeKey != null) ThemeKey = themeKey; } [ThreadStatic] static ThemeResourceConverterEx resourceConverter = new ThemeResourceConverterEx(); static ThemeResourceConverterEx ResourceConverter { get { return resourceConverter ?? (resourceConverter = new ThemeResourceConverterEx()); } } MultiBinding resourceBinding; MultiBinding ResourceBinding { get { return resourceBinding ?? (resourceBinding = CreateBinding()); } } public ThemeKeyExtensionGeneric ThemeKey { get; set; } MultiBinding CreateBinding() { var attachingLevel = LinqExtensions.Unfold(TargetProvider.With(x => x.TargetObject) as IAttachableObject, x => x.AssociatedObject as IAttachableObject, x => x == null).Count(); var basePath = string.Concat(Enumerable.Range(0, attachingLevel).Select(_ => "AssociatedObject.")); var binding = new MultiBinding() { Mode = BindingMode.OneWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }; binding.Bindings.Add(new Binding { Path = new PropertyPath(basePath + "(0)", ThemeManager.TreeWalkerProperty), RelativeSource = new RelativeSource(RelativeSourceMode.Self), Mode = BindingMode.OneWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); binding.Bindings.Add(new Binding { Source = ThemeKey, Mode = BindingMode.OneWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); binding.Bindings.Add(new Binding(basePath) { RelativeSource = new RelativeSource(RelativeSourceMode.Self), Mode = BindingMode.OneWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); if (RootProvider != null) ResourceConverter.RootElement = RootProvider.RootObject as FrameworkElement; binding.Converter = ResourceConverter; return binding; } protected override object ProvideValueCore() { if (IsInSetter(TargetProvider)) return ResourceBinding; return ResourceBinding.ProvideValue(ServiceProvider); } } public sealed class ThemeResourceConverterEx : IMultiValueConverter { [ThreadStatic] static ReflectionHelper reflectionHelper = new ReflectionHelper(); static ReflectionHelper ReflectionHelper { get { return reflectionHelper ?? (reflectionHelper = new ReflectionHelper()); } } public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { object element = values[2]; if (element == null || !IsFrameworkElement(element)) element = RootElement; if (values.Any(val => val == DependencyProperty.UnsetValue) || !IsFrameworkElement(element)) return DependencyProperty.UnsetValue; var treeWalker = GetThemeTreeWalker(element); var themeName = treeWalker != null ? treeWalker.ThemeName : null; var themeKey = values[1] as ThemeKeyExtensionGeneric; var newThemeKey = Activator.CreateInstance(themeKey.GetType()) as ThemeKeyExtensionGeneric; newThemeKey.ThemeName = themeName == Theme.DeepBlueName ? null : themeName; ReflectionHelper.SetPropertyValue(newThemeKey, "ResourceKey", ReflectionHelper.GetPropertyValue(themeKey, "ResourceKey")); return TryFindResource(element, newThemeKey) ?? DependencyProperty.UnsetValue; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } bool IsFrameworkElement(object obj) { return obj is FrameworkElement || obj is FrameworkContentElement; } object TryFindResource(object obj, object resourceKey) { if (obj is FrameworkElement) return ((FrameworkElement)obj).TryFindResource(resourceKey); if (obj is FrameworkContentElement) return ((FrameworkContentElement)obj).TryFindResource(resourceKey); return null; } ThemeTreeWalker GetThemeTreeWalker(object obj) { if (obj is FrameworkElement) return ((FrameworkElement)obj).GetValue(ThemeManager.TreeWalkerProperty) as ThemeTreeWalker; if (obj is FrameworkContentElement) return ((FrameworkContentElement)obj).GetValue(ThemeManager.TreeWalkerProperty) as ThemeTreeWalker; return null; } public FrameworkElement RootElement { get; set; } } }

                                  Hopefully you or someone else will find this useful.

                                  Can you please review these solutions to see what you think and look to implementing a solution to handle Freezable objects in a future release?

                                  I look forward to hearing from you, thanks!

                                  Kind Regards,
                                  Gareth

                                1 Solution

                                Creation Date Importance Sort by

                                Hello,

                                If you don't want to create different templates for every theme, you can use triggers in the BarItemBorderThemeKey ResourceKey=Normal template instead of visual states, for example:

                                [XAML]
                                <ControlTemplate x:Key="{dxbt:BarItemBorderThemeKey ResourceKey=Normal, IsThemeIndependent=True}" TargetType="{x:Type dxb:ItemBorderControl}"> <Grid x:Name="Root" > <Border x:Name="IsDefault" Background="Transparent" BorderBrush="Transparent" BorderThickness="1"/> <Border x:Name="IsCustomization" BorderBrush="#FFD70A31" BorderThickness="1" Opacity="0"/> </Grid> <ControlTemplate.Triggers> <Trigger Property="State" Value="Checked"> <Setter TargetName="IsDefault" Property="Background" Value="{dxi:ThemeResource {dxt:PaletteBrushThemeKey ResourceKey=SelectionBackground}}"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate>

                                Note that I used the PaletteBrushThemeKey extension to retrieve a palette color. You can use this approach only with our Palette Themes. To check available PaletteBrushThemeKeys, view the DevExpress.Xpf.Themes\Office2019Colorful\Core\Core\Themes\Office2019Colorful\PalettesBase.xaml file.

                                I attached a sample project demonstrating this approach. Let me know if you have additional questions.

                                • Gareth Thom 09.23.2019

                                  Hi André,

                                  Looks like you sent your reply whilst I was composing a big one to Ivan! Can you have a look at that and let me know what you think?

                                  Using triggers instead of animations certainly resolves the issue in the exact case of replicating your standard Office2019 ControlTemplate, but is no good if I wanted to actually use any animations with a From/To and Duration. I therefore think handling Freezable objects would be a useful addition to dxi:ThemeResource.

                                  However, in the short term, as it's unlikely we will end up doing any proper animations, it is of more interest to us to have the new 'Alt' colour palette colours added into Palettes_Base.xaml so we have access to the full range of possible colours. Would it be possible for you action this for the next minor release please?

                                  Let me know, thanks,
                                  Gareth

                                • Dima (DevExpress Support) 09.24.2019

                                  Hello Gareth,

                                  Thank you for sharing your solution with us. I reviewed it and discussed it with our developers. Although it looks promising, we are not very optimistic about it. It may be dangerous to manipulate Freezable elements in such a manner. This case requires deep research to conclude if it is safe or not. At the same time, we do not have plans to implement the same capabilities for our ThemeResource extension.

                                  As an alternative, you can try using a new theme with a custom palette every time you change your application's theme. For example:

                                  [C#]
                                  public MainWindow() { InitializeComponent(); Loaded += MainWindow_Loaded; }   private void MainWindow_Loaded(object sender, RoutedEventArgs e) { AddHandler(ThemeManager.ThemeChangedEvent, new ThemeChangedRoutedEventHandler(ThemeManager_ThemeChanged)); }   private void ThemeManager_ThemeChanged(DependencyObject sender, ThemeChangedRoutedEventArgs e) { var palette = new ThemePalette("Custom"); palette.SetColor("HoverBackground", (Color)this.TryFindResource(new PaletteColorThemeKeyExtension() { ThemeName = ThemeHelper.GetEditorThemeName(this), ResourceKey = "HoverBackground" })); //... var theme = Theme.CreateTheme(palette, MyTheme, MyTheme.Name + e.GetHashCode().ToString()); Theme.RegisterTheme(theme); ThemeManager.SetTheme(targetElement, theme); }

                                  The main idea here is to manually transfer palette colors between themes. Keep in mind that not all of these colors correspond to each other - one theme may not actually use the HoverBackground color as the background color of an item's hover border.

                                  As for alternative palette colors, it looks like they are currently missing and should already be defined in Palettes_Base. I created a separate ticket to address this issue (Alternative palette colors are not present in Palettes_Base.xaml) and passed it to our developers for further research.

                                  Let me know if you have any further questions.