如何解决C#WPF从其他类更改窗口的属性会导致异常
我试图创建一个自定义窗口,该窗口根据Windows 10主题(浅色或深色)更改其主题。我能够在运行时收听Windows 10主题更改。但是当我设置自定义依赖项属性值(WindowTheme)时,应用程序将引发异常:
引发的异常:“ system.invalidOperationException” WindowsBase.dll引发的异常: mscorlib.dll中的'System.Reflection.TargetInvocationException'
这是我的代码:
Window.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media;
using UWPHost.Enums;
using UWPHost.Utilities;
using static UWPHost.Utilities.NativeMethods;
namespace UWPHost
{
public class Window:System.Windows.Window
{
public Window()
{
}
private void SetTheme()
{
ResourceDictionary resourceDict = Application.LoadComponent(new Uri("UWPHost;component//Themes/res/Window.xaml",System.UriKind.RelativeOrAbsolute)) as ResourceDictionary;
Application.Current.Resources.MergedDictionaries.Clear();
Application.Current.Resources.MergedDictionaries.Add(resourceDict);
this.Style = (Style)Application.Current.Resources["GenericWindow"];
new ThemeUtility().Init(this);
}
public void SwitchTheme(Theme theme)
{
WindowTheme = theme;
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
var hWndSource = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
hWndSource.CompositionTarget.BackgroundColor = (Color)ColorConverter.ConvertFromString(CompositionTargetColor.ToString());
var nonClientArea = new Margins
{
left = ResizeframeWidth,top = (int)CaptionHeight,bottom = ResizeframeWidth,right = ResizeframeWidth
};
DwmExtendFrameIntoClientArea(hWndSource.Handle,ref nonClientArea);
hWndSource.AddHook(new WndProc(this).GetWndProc);
SetwindowPos(hWndSource.Handle,new IntPtr(),0x0020 | 0x0002 | 0x0001);
SetwindowLong(hWndSource.Handle,GWL_STYLE,getwindowlong(hWndSource.Handle,GWL_STYLE) & ~WS_SYSMENU);
SetTheme();
}
#region Dependency Properties
public double CaptionHeight
{
get { return (double)GetValue(CaptionHeightProperty); }
set { SetValue(CaptionHeightProperty,value); }
}
public static readonly DependencyProperty CaptionHeightProperty = DependencyProperty.Register("CaptionHeight",typeof(double),typeof(Window),new PropertyMetadata(33.0));
public int ResizeframeWidth
{
get { return (int)GetValue(ResizeframeWidthProperty); }
set { SetValue(ResizeframeWidthProperty,value); }
}
public static readonly DependencyProperty ResizeframeWidthProperty = DependencyProperty.Register("ResizeframeWidth",typeof(int),new PropertyMetadata(10));
public String CompositionTargetColor
{
get { return (String)GetValue(CompositionTargetColorProperty); }
set { SetValue(CompositionTargetColorProperty,value); }
}
public static readonly DependencyProperty CompositionTargetColorProperty = DependencyProperty.Register("CompositionTargetColor",typeof(String),new PropertyMetadata("#FFFFFF"));
public Theme WindowTheme
{
get { return (Theme)GetValue(WindowThemeProperty); }
set { SetValue(WindowThemeProperty,value); }
}
public static readonly DependencyProperty WindowThemeProperty = DependencyProperty.Register("WindowTheme",typeof(Theme),new PropertyMetadata(Theme.Default));
#endregion
}
}
ThemeUtility.cs
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Management;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using UWPHost.Enums;
namespace UWPHost.Utilities
{
public class ThemeUtility
{
private const string ThemeRegistry= @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
private const string RegistryValue= "AppsUseLightTheme";
private readonly string query;
private readonly WindowsIdentity CurrentUser;
ManagementEventWatcher ThemeWatcher;
Window window;
public ThemeUtility()
{
CurrentUser = WindowsIdentity.GetCurrent();
query= string.Format(CultureInfo.InvariantCulture,@"SELECT * FROM RegistryValueChangeEvent WHERE Hive = 'HKEY_USERS' AND KeyPath = '{0}\\{1}' AND ValueName = '{2}'",CurrentUser.User.Value,ThemeRegistry.Replace(@"\",@"\\"),RegistryValue);
}
public void Init(Window window)
{
this.window = window;
InitSystemThemeWatcher();
}
private void InitSystemThemeWatcher()
{
try
{
ThemeWatcher = new ManagementEventWatcher(query);
ThemeWatcher.EventArrived += (sender,args) =>
{
//This code is executed when windows 10 theme changes
if(GetSystemTheme()==Theme.Dark)
{
//Here i'm setting the property of window
window.SwitchTheme(Theme.Dark);
}
else
{
window.SwitchTheme(Theme.Light);
}
};
ThemeWatcher.Start();
}
catch(Exception)
{
throw new Exception("Error Unable to add theme listener.");
}
Theme initialTheme = GetSystemTheme();
}
private static Theme GetSystemTheme()
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(ThemeRegistry))
{
object registryValueObject = key?.GetValue(RegistryValue);
if (registryValueObject == null)
{
return Theme.Light;
}
int registryValue = (int)registryValueObject;
return registryValue > 0 ? Theme.Light : Theme.Dark;
}
}
}
}
Exception thrown: 'System.InvalidOperationException' in WindowsBase.dll
从本文中,我知道可以使用INotifyPropertyChanged完成此操作,但是我不知道如何在我的情况下实现它。
注意:WindowTheme属性的类型为enum,其值为Light,Dark,Default
解决方法
您的应用程序的UI线程中显然未调用ManagementEventWatcher.EventArrived
处理程序。
依赖性属性只能在创建拥有对象的线程中访问。
使用Window的Dispatcher将执行编组到创建Window的线程,即UI线程:
public void SwitchTheme(Theme theme)
{
Dispatcher.Invoke(() => WindowTheme = theme);
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。