Change Management Template Based on Current Topic

Unfortunately, I had to redefine the control template of one of the TabControl in my application, because I needed to make some minor changes to the appearance and appearance that could not be done otherwise.

 <TabControl Name="specialTabControl" Template="{StaticResource SpecialTabControlTemplate} />". 

Everything looks fine until I switch the OS theme. Now my TabControl looks completely garbage, because it uses the wrong theme control template (the theme on which I based my control template is extracted using Blend).

Therefore, I need to find a way to provide 4 control templates (luna, aero, xp, classic) for this special TabControl , which must be selected in accordance with the current OS theme.

So, how can you provide and apply custom control templates different for specialTabControl based on the current theme, so when the user switches the OS theme, this specialTabControl switch to the control template that I provided for this theme?

Note that I have another TabControl in the application that does not have an override control template, and should always have a standard control template for this theme.

+4
source share
1 answer

I think you need to see the themes in the WPF application. An assembly may contain the following lines:

[assembly:. ThemeInfo (ResourceDictionaryLocation SourceAssembly , ResourceDictionaryLocation.SourceAssembly)]

This means that the system themes of the application are located in your assembly (in the folder / themes). The theme name should correspond to system topics ... for example:

 The Aero theme (Windows Vista and Windows 7): themes\Aero.NormalColor.xaml The default Windows XP theme: themes\Luna.NormalColor.xaml The olive green Windows XP theme: themes\Luna.Homestead.xaml The Windows Classic theme: themes\Classic.xaml 

When the user changes the skin of the system, the WPF application automatically downloads your themes. Accordingly, you can set a control template for each system theme. More information can be found in:

"Adam Nathan. WPF 4 Unleashed." Chapter 14.

WPF Themed Applications: http://blogs.infosupport.com/theming-wpf-applications/

Hope this helps.

* EDIT *

I found an interesting example that talks about the topic of topic change:

http://northhorizon.net/2010/how-to-actually-change-the-system-theme-in-wpf/

You can set an explicit style that will not respond to skin changes in the system:

 <Style x:Key="ExplicitGreenButtonStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}"> <Setter Property="Background" Value="Green" /> <Setter Property="Foreground" Value="White" /> </Style> 

Accordingly, an implicit style will respond to a change in the system skin:

 <Style x:Key="ImplicitGreenButtonStyle" TargetType="Button"> <Setter Property="Background" Value="Green" /> <Setter Property="Foreground" Value="White" /> </Style> 

In addition, the example contains useful code in ThemeHelper , in which some topics work.

* EDIT # 2 *

If I understand correctly, first you need to get the name of the system theme. This action can be performed in several ways.

First, use the Win32 functions from the UxTheme.dll library, for example GetCurrentThemeName () :

 [DllImport("uxtheme.dll", CharSet = CharSet.Auto)] public static extern int GetCurrentThemeName(StringBuilder pszThemeFileName, int dwMaxNameChars, StringBuilder pszColorBuff, int dwMaxColorChars, StringBuilder pszSizeBuff, int cchMaxSizeChars); StringBuilder stringThemeName = new StringBuilder(260); StringBuilder stringColorName = new StringBuilder(260); StringBuilder stringSizeName = new StringBuilder(260); Int32 s = GetCurrentThemeName(stringThemeName, 260, stringColorName, 260, stringSizeName, 260); 

But I got this function incorrectly received some names of system themes, such as "Classic". So I tried differently.

The second way is to get the topic name from the registry. In the path, "HKEY_CURRENT_USER \ Software \ Microsoft \ Windows \ CurrentVersion \ Themes \ LastTheme" contains the current system theme. So we need to intercept the "Change system theme event" with a window hook.

Below is an example with several buttons, the style of which depends on the system theme:

Add to window:

 SourceInitialized="Window_SourceInitialized" 

Styles

 <Style x:Key="DefaultStyle" BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}"> <Setter Property="Background" Value="CadetBlue" /> </Style> <Style x:Key="LunaStyle" TargetType="{x:Type Button}"> <Setter Property="Background" Value="Blue" /> <Setter Property="Foreground" Value="White" /> </Style> <Style x:Key="ClassicStyle" TargetType="{x:Type Button}"> <Setter Property="Background" Value="Gray" /> <Setter Property="Foreground" Value="Black" /> </Style> 

Main grid:

 <Grid> <Button Style="{StaticResource DefaultStyle}" Content="Default button" Width="100" Height="30" VerticalAlignment="Top" HorizontalAlignment="Left" /> <Button Name="ChangeButtonStyle" Content="Changes style" Width="100" Height="30" VerticalAlignment="Top" HorizontalAlignment="Right" /> <TextBlock Name="CurrentTheme" FontSize="16" Text="Null" Width="150" Height="30" HorizontalAlignment="Center" VerticalAlignment="Top" /> </Grid> 

In code:

Intercept the "Change system theme" event:

 private IntPtr hwnd; private HwndSource hsource; private void Window_SourceInitialized(object sender, EventArgs e) { if ((hwnd = new WindowInteropHelper(this).Handle) == IntPtr.Zero) { throw new InvalidOperationException("Could not get window handle."); } hsource = HwndSource.FromHwnd(hwnd); hsource.AddHook(WndProc); } private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { case 0x31A: // Define this as WM_DWMCOMPOSITIONCHANGED for Windows 7 case 0x31E: // Define this as WM_THEMECHANGED // Action on the change system theme GetThemeName(SubKey, Value); return IntPtr.Zero; default: return IntPtr.Zero; } } 

Get the name of the system theme and set the style:

 public string SubKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\LastTheme"; public string Value = "ThemeFile"; private void GetThemeName(string OpenKey, string Value) { RegistryKey pRegKey = Registry.CurrentUser; pRegKey = pRegKey.OpenSubKey(OpenKey); Object val = pRegKey.GetValue(Value); string NameThemeFile = val as string; if (NameThemeFile.IndexOf("Luna") != -1) { ChangeButtonStyle.Style = this.FindResource("LunaStyle") as Style; CurrentTheme.Text = "Luna"; } if (NameThemeFile.IndexOf("Classic") != -1) { ChangeButtonStyle.Style = this.FindResource("ClassicStyle") as Style; CurrentTheme.Text = "Classic"; } } 

This method is not the best, but it will begin.

0
source

All Articles