C# Visual Studio Excel 加载项:如何检测 Excel Office 主题更改?

C# Visual Studio Excel Add-in: How can I detect Excel Office Theme Change?

我写了一个 class 来检测当前的 Excel 主题。

获取Excel当前办公主题:

//Declaration
string officeVersion;
int themeCode;

// Get Office Version first
officeVersion = "16.0";

// Goto the Registry Current Version
RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Office\" + officeVersion + @"\Common");

// Get Stored Theme
themeCode = (int)rk.GetValue("UI Theme", GlobalVar.COLORFUL);

然后根据themeCode的值,判断当前Excel的主题是什么:

// Theme Constants
public const int COLORFUL = 0;
public const int DARKGREY = 3;
public const int BLACK = 4;
public const int WHITE = 5;

我的问题:

  • How can I detect when the user, during Excel Running, change the Office Theme from the Excel Options?
  • In Another way, is there any Excel Event triggered when the User has edited anything from the Excel Options?
  • How can I detect/trap that event please?

I used already Process Monitor and got the location of the Registry key where the theme is stored. But I cannot constantly check the Registry, I prefer to detect when the user clicked on More Commmand\Excel Options if that event is detectable.

非常欢迎您的回答和建议。提前致谢!

非常感谢@PortlandRunner 在评论中给我的方法。我想出了以下代码:

using Microsoft.Win32;
using System;
using System.Drawing;
using System.Management;
using System.Security.Principal;

namespace YourProject
{
    /*
     #####################################
     # GLOBAL CONSTANTS FOR OFFICE THEME #
     # By Tsiriniaina Rakotonirina       #
     #####################################
     */
    public class GlobalVar
    {
        //Theme Constants
        public const int COLORFUL = 0;
        public const int DARKGREY = 3;
        public const int BLACK = 4;
        public const int WHITE = 5;
    }

    /*
     ########################################
     # OFFICE CLASS TO RETURN TO THE ADDINS #
     # By Tsiriniaina Rakotonirina          #
     ########################################
     */
    public class ExcelTheme
    {
        private int code;             //Theme Code               
        private Color backgroundColor;//Addins Backcolor based on Theme
        private Color textForeColor;  //Addins Text Color based on Theme

        public Color BackgroundColor { get => backgroundColor; set => backgroundColor = value; }
        public Color TextForeColor { get => textForeColor; set => textForeColor = value; }
        public int Code { get => code; set => code = value; }
    }

    /*
     ###############################
     # OFFICE THEME CHANGE WATCHER #
     # By Tsiriniaina Rakotonirina #
     ###############################
     */
    class ExcelThemeWatcher
    {
        /*
         *****************************************
         * CLASS CONSTRUCTOR                     *
         * ---> The Watch start right away after *
         *      the class is created             *
         *****************************************
         */
        public ExcelThemeWatcher()
        {
            //Start Watching Office Theme Change
            //By calling the following method
            StartThemeWatcher();
        }

        /*
         *****************************************
         * GET OFFICE VERSION                    *
         * ---> Read the Registry and            *
         *      get the Current Office Version   *
         *****************************************
         */
        public int GetOfficeVersion()
        {
            //Get Current Excel Version
            try
            {
                //Get Office Version
                //Goto the Registry Current Version
                RegistryKey rk = Registry.ClassesRoot.OpenSubKey(@"Excel.Application\CurVer");

                //Read Current Version
                string officeVersion = rk.GetValue("").ToString();

                //Office Version
                string officeNumberVersion = officeVersion.Split('.')[officeVersion.Split('.').GetUpperBound(0)];

                //Return Office Version
                return Int32.Parse(officeNumberVersion);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return 0;
            }
        }

        /*
         *****************************************
         * GET OFFICE THEME                      *
         * ---> Read the Registry and            *
         *      get the Current Office Theme     *
         *****************************************
         */
        private int GetRegistryOfficeTheme()
        {
            //Get Office Version first
            string officeVersion = GetOfficeVersion().ToString("F1");

            //Goto the Registry Current Version
            RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Office\" + officeVersion + @"\Common");

            return Convert.ToInt32(rk.GetValue("UI Theme", GlobalVar.COLORFUL));
        }

        /*
         *****************************************
         * GET ADDINS THEME                      *
         * ---> Based on the Office Theme        *
         *      Return the Addins Theme          *
         *****************************************
         */
        public ExcelTheme GetAddinsTheme()
        {
            ExcelTheme theme = new ExcelTheme();

            //Default Theme Code
            theme.Code = GetRegistryOfficeTheme();

            //Get Background Colors
            theme.BackgroundColor = ColorTranslator.FromHtml("#EFE9D7");
            theme.TextForeColor = ColorTranslator.FromHtml("#004B8D");

            try
            {
                switch (theme.Code)
                {
                    case GlobalVar.COLORFUL:
                        theme.BackgroundColor = ColorTranslator.FromHtml("#E6E6E6");
                        theme.TextForeColor = ColorTranslator.FromHtml("#004B8D");

                        break;

                    case GlobalVar.DARKGREY:
                        theme.BackgroundColor = ColorTranslator.FromHtml("#666666");
                        theme.TextForeColor = ColorTranslator.FromHtml("White");
                        break;

                    case GlobalVar.BLACK:
                        theme.BackgroundColor = ColorTranslator.FromHtml("#323130");
                        theme.TextForeColor = ColorTranslator.FromHtml("#CCA03B");
                        break;

                    case GlobalVar.WHITE:
                        theme.BackgroundColor = ColorTranslator.FromHtml("#FFFFFF");
                        theme.TextForeColor = ColorTranslator.FromHtml("#004B8D");

                        break;

                    default:
                        break;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            return theme;
        }

        /*
         ******************************************
         * START OFFICE THEME CHANGE WATCH        *
         * ---> Using WMI, read and watch         *
         *      Registry Section for Office Theme *
         ******************************************
         */
        private void StartThemeWatcher()
        {
            string keyPath;   //Office Theme Path
            string valueName; //Office Theme Value name

            //Get Office Version first
            string officeVersion = GetOfficeVersion().ToString("F1");

            //Set the KeyPath based on the Office Version
            keyPath = @"Software\Microsoft\Office\" + officeVersion + "\Common";
            valueName = "UI Theme";

            //Get the Current User ID
            //---> HKEY_CURRENT_USER doesn't contain Value as it is a shortcut of HKEY_USERS + User ID
            //     That is why we get that currentUser ID and use it to read the wanted location

            //Get the User ID
            var currentUser = WindowsIdentity.GetCurrent();

            //Build the Query based on 3 parameters
            //Param #1: User ID
            //Param #2: Location or Path of the Registry Key
            //Param #3: Registry Value to watch
            var query = new WqlEventQuery(string.Format(
                    "SELECT * FROM RegistryValueChangeEvent WHERE Hive='HKEY_USERS' AND KeyPath='{0}\\{1}' AND ValueName='{2}'",
                    currentUser.User.Value, keyPath.Replace("\", "\\"), valueName));

            //Create a Watcher based on the "query" we just built
            ManagementEventWatcher watcher = new ManagementEventWatcher(query);

            //Create the Event using the "Function" to fire up, here called "KeyValueChanged"
            watcher.EventArrived += (sender, args) => KeyValueChanged();

            //Start the Watcher
            watcher.Start();

        }

        /*
         ******************************************
         * EVENT FIRED UP WHEN CHANGE OCCURS      *
         * ---> Here the event is instructed      *
         *      to update the Addins Theme        *
         ******************************************
         */
        private void KeyValueChanged()
        {
            // Here, whenever the user change the Office theme,
            // this function will automatically Update the Addins Theme
            Globals.ThisAddIn.SetAddinsInterfaceTheme();
        }
    }

}

我觉得没有必要停止观察者,但如果你想出了这个主意,请告诉我把它放在哪里;)

更新:

也很高兴告诉您,当我测试更改 Office 主题并看到我的 Addins 主题也发生变化时,我是如此的存在。也很想听听您的意见!