Open billhenn opened 3 years ago
@llongley @codendone as FYI
This is currently by design. It is a little hidden down in the Remarks section of the documentation:
The theme can only be set when the app is started, not while it's running. Attempting to set RequestedTheme while the app is running throws an exception (NotSupportedException for Microsoft .NET code). ...
You can change specific theme values at run-time after Application.RequestedTheme is applied, if you use the FrameworkElement.RequestedTheme property and sets values on specific elements in the UI.
The error message could certainly be better -- a problem we have for all errors right now. This error will be much easier to understand when the code is finally open source, since you'd then be able to see this code comment at the source of the exception:
// RequestedTheme cannot be set after app.xaml has been loaded.
@codendone Thanks, I apologize I didn't see that remark before. The more descriptive error message would certainly help prevent confusion on this, and as you said, error messages really need to be more detailed across the board.
I would really ask that you improve this to support app-wide theme changes without having to restart the app. All popular modern apps support instant live theme changes between variations of light and dark themes without having to restart, and it's kind of an expected app capability at this point. Not having support for that in a "modern" UI platform is very disappointing. Thanks for listening!
I believe this restriction exists simply because way back in Windows 8 when the RequestedTheme support was implemented there weren't available resources to also support dynamic changes. Adding that support could be done in the future, so I'm marking this as a future feature proposal.
Thank you @codendone, much appreciated.
Guys, can you please please please add just a tad of description in the exception, when you throw it? I wanted to bang my head against the wall on this one (Until i figured out i should set that in the constructor). The (insanely generic) exception is beyond annoying.
A potentially dumb question: if runtime switching isn't supported, how does task manager do it? Or notepad? Both support runtime switching, and they're both using WinUI 3.
The proposal: 💯
This is a sort of workaround for the missing feature. One can call SetTheme("Light", window.Content)
to enforce theme changes for all ComboBoxes (simplification). However, it modifies only visible ComboBoxes as VisualTreeHelper
(doc) is used.
Not sure how to change all ComboBoxes in the window (being visible in the UI tree or not).
public static void SetTheme(string appTheme, Microsoft.UI.Xaml.DependencyObject obj)
{
Microsoft.UI.Xaml.ElementTheme elementTheme = appTheme switch
{
"Light" => Microsoft.UI.Xaml.ElementTheme.Light,
"Dark" => Microsoft.UI.Xaml.ElementTheme.Dark,
"System" => Microsoft.UI.Xaml.ElementTheme.Default,
_ => throw new NotSupportedException($"Invalid application theme value '{appTheme}'."),
};
foreach (Microsoft.UI.Xaml.Controls.ComboBox comboBox in FindDescendants<Microsoft.UI.Xaml.Controls.ComboBox>(obj))
{
comboBox.RequestedTheme = elementTheme;
}
}
public static IEnumerable<T> FindDescendants<T>(Microsoft.UI.Xaml.DependencyObject dobj)
where T : Microsoft.UI.Xaml.DependencyObject
{
int count = Microsoft.UI.Xaml.Media.VisualTreeHelper.GetChildrenCount(dobj);
for (int i = 0; i < count; i++)
{
Microsoft.UI.Xaml.DependencyObject element = Microsoft.UI.Xaml.Media.VisualTreeHelper.GetChild(dobj, i);
if (element is T t)
yield return t;
foreach (T descendant in FindDescendants<T>(element))
yield return descendant;
}
}
This is a more complete code one can use: https://github.com/dotnet/maui/issues/21042#issuecomment-2325140606
place this line of code inside your App's OnLaunched method to set m_isRequestedThemeSettable
to true
*(bool*)(((IWinRTObject)this).NativeObject.As<IUnknownVftbl>(IApplicationIID).ThisPtr + 0x118U) = true;
IApplicationIID is defined like below.
private static ref readonly Guid IApplicationIID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref MemoryMarshal.AsRef<Guid>([231, 244, 168, 6, 70, 17, 175, 85, 130, 13, 235, 213, 86, 67, 176, 33]);
}
(Tested and works in WASDK 1.6.3)
Additional Context: https://github.com/microsoft/WindowsAppSDK/discussions/4710#discussioncomment-10741712
place this line of code inside your App's OnLaunched method to set
m_isRequestedThemeSettable
to true(bool)(((IWinRTObject)this).NativeObject.As
(IApplicationIID).ThisPtr + 0x118U) = true; (Tested and works in WASDK 1.6.3) Additional Context: microsoft/WindowsAppSDK#4710 (comment)
what is IApplicationIID ?
what is IApplicationIID ?
@ghost1372 My bad, you can find through looking the code decompiled by VS.
There is a Make___objRef_global__Microsoft_UI_Xaml_IApplication
method in Application
And finally get this
what is IApplicationIID ?
@ghost1372 My bad, you can find through looking the code decompiled by VS.
There is a
Make___objRef_global__Microsoft_UI_Xaml_IApplication
method inApplication
And finally get this
thank you now its working fine
complete code:
unsafe
{
*(bool*)(((IWinRTObject)this).NativeObject.As<IUnknownVftbl>(IID).ThisPtr + 0x118U) = true;
}
public static ref readonly Guid IID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference((ReadOnlySpan<byte>)new byte[16]
{
231, 244, 168, 6, 70, 17, 175, 85, 130, 13,
235, 213, 86, 67, 176, 33
}));
}
}
Describe the bug Setting
Application.Current.RequestedTheme
at run-time to alter the app's light/dark theme throws this exception:Setting the
RequestedTheme
property on the rootGrid
in myWindow
succeeds. But I want to change it app-wide, not only on this window.Steps to reproduce the bug
Use this code to reproduce:
Expected behavior
No exception and the app theme should toggle to the selected theme.
Version Info
NuGet package version: [Microsoft.WinUI 3.0.0-preview4.210210.4]