Closed ClarkRSD closed 1 year ago
I was able to fix this. I still cannot get accent colors to work without recompiling, but this satisfies my needs. You're able to change it by utilizing the [ModernWpf.ThemeManager]::SetRequestedTheme()
method. Looking at the source code it just sets the value of ui:ThemeManager.RequestedTheme
to either Light
or Dark
, which is good enough to be able to change in PowerShell without recompiling. I know that class is intended for changing themes on elements but that's the only solution. There isn't a public one for setting the accent color and every property I found to change the accent color requires that recompile to happen. I also tried changing the ResourceDictionary after it's been parsed already and it requires a recompile there as well.
Just make sure you specify the following ResourceDictionary with a color in-place as well as ui:ThemeManager.HasThemeResources="True"
, ui:ThemeManager.RequestedTheme="Light"
, and ui:ThemeManager.IsThemeAware="True"
.
<Window.Resources>
<ResourceDictionary x:Key="ThemeResourceDictionary">
<ResourceDictionary.MergedDictionaries>
<ui:ColorPaletteResources Accent="Blue" />
<ui:ThemeResources/>
<ui:XamlControlsResources />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.modernwpf.com/2019"
Height="450"
Width="800"
ui:TitleBar.ExtendViewIntoTitleBar="True"
ui:WindowHelper.UseModernWindowStyle="True"
ui:ThemeManager.IsThemeAware="True"
ui:ThemeManager.RequestedTheme="Light"
ui:ThemeManager.HasThemeResources="True">
<Window.Resources>
<ResourceDictionary x:Key="ThemeRD">
<ResourceDictionary.MergedDictionaries>
<ui:ColorPaletteResources Accent="Blue" />
<ui:ThemeResources/>
<ui:XamlControlsResources />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<ui:NavigationView
IsBackButtonVisible="Visible"
IsTitleBarAutoPaddingEnabled="False"
PaneTitle="PowerShell"
IsBackEnabled="True"
PaneDisplayMode="LeftCompact"
Name="Navigation"
IsSettingsVisible="False"
IsPaneOpen="False">
<ui:NavigationView.MenuItems>
<ui:NavigationViewItem Icon="Home" Content="Sample Item 1" Tag="Page1" IsSelected="True" />
<ui:NavigationViewItem Tag="Page2" Content="Sample Item 2">
<ui:NavigationViewItem.Icon>
<ui:FontIcon Glyph=""/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
</ui:NavigationView.MenuItems>
<ui:Frame Name="ContentFrame"/>
</ui:NavigationView>
</Window>
Here is the exact code that I ran to change the value in code-behind. Note that the $WindowObject
variable is the variable that you use to run your .ShowDialog()
method in your script.
$btnLight.Add_Click({
[ModernWpf.ThemeManager]::SetRequestedTheme($WindowObject,[ModernWpf.ElementTheme]::Light)
})
$btnDark.Add_Click({
[ModernWpf.ThemeManager]::SetRequestedTheme($WindowObject,[ModernWpf.ElementTheme]::Dark)
})
If you specify a key for your ResourceDictionary you can also dynamically change it using this helper function that I created. Make sure that you run this function BEFORE you parse the xml file, otherwise the changes won't get reflected. See script block at the bottom for where exactly it needs to go.
Function Set-AccentColor {
param(
[string]$AccentColor,
[System.Xml.XmlNode]$Element
)
if ($AccentColor){
$Color = $AccentColor
}
else {
# Get decimal value for system accent color
[Int64]$ColorDec = (Get-ItemProperty "HKCU:\Software\Microsoft\Windows\DWM\" -Name 'AccentColor').AccentColor
# Convert to hex and turn to array because it's in ABGR and we need it in RGB
$Hex = ([System.Convert]::ToString($ColorDec,16)).ToCharArray()
# Grab each value and convert to RGB
$R = ($Hex)[6,7] -join ''
$G = ($Hex)[4,5] -join ''
$B = ($Hex)[2,3] -join ''
# Turn into a single string
$Color = $R + $G + $B
}
# Create a Namespace object and add the x: namespace
[System.Xml.XmlNamespaceManager]$NamespaceManager = $Element.NameTable
$NamespaceManager.AddNamespace("x", "http://schemas.microsoft.com/winfx/2006/xaml")
# Create a variable for the ResourceDictionary and modify the ResourceDictionary before it's parsed
$Key = $Element.SelectNodes("//*[@x:Key]",$NamespaceManager)
New-Variable -Name "AccentColorData" -Value $Key.'ResourceDictionary.MergedDictionaries'
if ($Color -like "#*"){
$AccentColorData.ColorPaletteResources.Accent = $Color
}
else {
$AccentColorData.ColorPaletteResources.Accent = "#$($Color)"
}
}
[xml]$Content = Get-Content -Path C:\Path\To\xaml\file.xaml
Set-AccentColor -Element $Content
$reader = (New-Object System.Xml.XmlNodeReader $Content)
$parser = [Windows.Markup.XamlReader]::Load($reader)
Is it possible to toggle the theme using PowerShell? I can't seem to get it to work.
My understanding is I just add the resource dictionaries to the window and pages, then use the class to change it within PowerShell, but calling the
Current
method shows that it's supposed to be dark but it's still light. Does it have something to do with PowerShell being single threaded? I'm sure I'm doing something wrong but can't seem to figure out what it is.Window XAML:
Page 1 XAML:
Page 2 XAML:
Script: