微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C#WPF从其他类更改窗口的属性会导致异常

如何解决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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?