Excel自定义RibbonUI + COM可见dll:我可以订阅dll中的功能区控件事件吗?

问题描述 投票:0回答:1

我正在用C#开发一个COM可见的DLL,并且这个DLL在Excel VBA项目中被引用。这个想法是将所有代码外包给 DLL,而不是使用 VBA。 VBA仅用于订阅我的Excel工作簿的不同事件:

Option Explicit

Private Sub Workbook_Open()
  With New ProjectXLib.EndPoint
    Call .Subscribe(Excel.ThisWorkbook)
  End With
End Sub

这是我的

IEndPoint
界面:

using System;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;

namespace ProjectXLib.Source
{
    [ComVisible(true)]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("6ca9d5e5-41fe-45f3-8ccb-8106288a447c")]
    public interface IEndPoint
    {
        void Subscribe(Excel.Workbook workbook);
    }
}

这是

IEndPoint
的实现:

using ExcelCoreLib.Source.Core;
using ProjectXLib.Source.Events;
using System;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;

namespace ProjectXLib.Source
{
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    [Guid("e8b3885e-8ea3-4bcb-baa2-b5b7b1e9f8f3")]
    [ProgId(nameof(EndPoint))]
    public class EndPoint : IEndPoint
    {
        public EndPoint() { }

        public void Subscribe(Excel.Workbook workbook)
        {
            using (Macro.GetInstance(workbook.Application))
            {
                WorkbookEvents.Subscribe(workbook);
            }
        }
    }
}

我在

WorkbookEvents
类中订阅我的工作簿事件和 ActiveX 控件以进行编码:

using ExcelCoreLib.Source.Core;
using System.Windows.Forms;
using Excel = Microsoft.Office.Interop.Excel;
using MSForms = Microsoft.Vbe.Interop.Forms;

namespace ProjectXLib.Source.Events
{
    internal static class WorkbookEvents
    {
        private static Excel.Workbook Workbook { get; set; }
        private static Excel.WorkbookEvents_Event Events { get; set; }
        private static MSForms.CommandButton BtnErrors { get; set; }

        public static void Subscribe(Excel.Workbook workbook)
        {
            Workbook = workbook;
            Events = workbook;

            // Buttons
            BtnErrors = Worksheet.GetCommandButton(workbook.Worksheets["Errors"], "btnErrors");
            BtnErrors.Click += BtnErrors_Click;

            // Events
            Events.BeforeClose += Workbook_BeforeClose;
            Events.SheetBeforeDoubleClick += Workbook_SheetBeforeDoubleClick;
            Events.SheetChange += Workbook_SheetChange;
            Events.AfterSave += Workbook_AfterSave;
        }

        private static void BtnErrors_Click()
        {
            MessageBox.Show("Hello world from dll!");
        }

        private static void Workbook_BeforeClose(ref bool Cancel)
        {
            Events.BeforeClose -= Workbook_BeforeClose;
            Events.SheetBeforeDoubleClick -= Workbook_SheetBeforeDoubleClick;
            Events.SheetChange -= Workbook_SheetChange;
            Events.AfterSave -= Workbook_AfterSave;
            BtnErrors.Click -= BtnErrors_Click;
        }

        private static void Workbook_SheetBeforeDoubleClick(object Sh, Excel.Range Target, ref bool Cancel)
        {
            if (Target.Count.Equals(1) && Target.Value2 is bool && !Target.HasFormula)
            {
                Cancel = true; Target.Value2 = !Target.Value2;
            }
        }

        private static void Workbook_SheetChange(object Sh, Excel.Range Target)
        {
            Worksheet.CastAs(Sh).CircleInvalid();
        }

        private static void Workbook_AfterSave(bool Success)
        {
            Excel.Worksheet worksheet = Workbook.ActiveSheet;
            worksheet.CircleInvalid();
        }
    }
}

所有这些都运行良好。我使用 Regasm 注册我的 DLL,在 Excel 工作簿中引用它,事件和按钮事件工作正常。我的问题是我无法从 CustomRibbonUI 订阅按钮:

<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">
  <ribbon startFromScratch="false">
    <tabs>
      <tab id="idMacros" label="Macros">
        <group id="idErrors" label="Errors">
          <button id="btnReset" label="Reset" imageMso="HappyFace" size="large"/>
          <button id="btnFindInvalidCells" label="Invalid cells" imageMso="HappyFace" size="large"/>
        </group>
      </tab>
    </tabs>
  </ribbon>
</customUI>

在给你写信之前我查了很多资料。理想情况下,我不想在 VBA 中进行任何额外的实现,除了加载功能区时的

RibbonOnLoad
方法之外,就像我在打开工作簿时使用
Workbook_Open
事件订阅工作簿事件一样。例如,我想将我的
btnReset
btnFindInvalidCells
按钮订阅与 Click 相关的事件,并在 DLL 中完成这些事件的实现。

除此之外,我尝试添加和实现 IRibbonExtensibility 接口但没有成功,也许我做错了。

感谢那些读到这里的人和那些帮助我的人。

excel vba dll com ribbon
1个回答
0
投票

为什么您甚至想订阅特定的按钮按下事件? (您选择这样做的原因是什么?)因为据我了解,这会将 DLL 中的实现与自定义功能区实现结合起来。

<button id="btnFindInvalidCells" [...] onAction="handleInvalidCells"/>

Sub handleInvlaidCells(control As IRibbonControl)
    'call DLL function here
End Sub

这样,功能区菜单和 DLL 中的代码就可以独立更改,而无需更改其他

© www.soinside.com 2019 - 2024. All rights reserved.