C# Visual Studio Excel 插件:如何检测 Excel Office 主题变化?

5

我编写了一个类,可以检测当前Excel主题。

获取Excel当前Office主题:

//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;

我的问题:

  • 在Excel运行期间,如何检测用户是否从 Excel选项更改了Office主题?
  • 换句话说,当用户从Excel选项编辑任何内容时,是否有任何Excel事件会被触发?
  • 请问如何检测/捕获该事件?

enter image description here

我已经使用过进程监视器(Process Monitor)并获取了存储主题的注册表键的位置。但是我不能不断地检查注册表,我希望能够检测到用户点击更多命令\Excel选项的事件(如果该事件可检测)。

欢迎回答和建议。提前致谢!


2
假设我们无法检测到主题更改事件...我猜想您想要更改已创建的插件的外观。是否可以在您的插件中添加另一个选项,让用户手动选择更改其“主题”,而不是自动检测它? - Automate This
3
你可能会觉得这种主题监视器方法很有趣。此链接提供了更多信息。 - Automate This
@PortlandRunner,你的建议很棒!这个想法我没有想到过。实际上,在重新启动后,我可以将我的Addin主题与Office主题相适应,这就是为什么我想知道是否存在一个事件。但这也可能是一个很好的解决方案。点赞! - Tsiry Rakotonirina
@PortlandRunner,我也在测试这个theme_watcher,并且一旦我让它工作起来,就会向您报告。事实上,我已经更新了它,以便检测当前的Office版本,因为示例仅适用于硬编码的Office 15.0。我将尝试使其动态化,如果成功,我一定会在这里分享。 - Tsiry Rakotonirina
1
请在可用时分享。我越想越觉得奇怪,为什么微软不为插件开发人员内置此功能。也许这只是一个疏忽,但我相信你不是唯一想要这个功能的人! - Automate This
1个回答

1

非常感谢@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 主题并看到我的插件主题也随之改变时,我感到非常兴奋。也很想听听你的想法!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接