Введение

Это продолжение статьи о создании надстройки для Excel с помощью библиотеки Excel-DNA о сборке простой надстройки с пользовательской формулой. Здесь рассмотрим как сделать свою панель с кнопками, взаимодействовать с рабочей книгой, выводить уведомления, а также получить доступ к элементам интерфейса Excel.

Создание панели

Панели Ribbon описываются в XML. Простейшая выглядит так:

<customUI xmlns='http://schemas.microsoft.com/office/2006/01/customui'>
    <ribbon>
        <tabs>
            <tab id='MyAddinTab' label='My Addin Tab'>
                <group id='MyAddinGroup' label='My Addin Group'>
                    <button id='Button1' label='Button 1' size='large' imageMso='HappyFace' />
                    <button id='Button2' label='Button 2' size='large' imageMso='SadFace' />
                    <button id='Button3' label='Button 3' size='large' imageMso='Piggy' />
                </group>
            </tab>
        </tabs>
    </ribbon>
</customUI>

Тег tab описывает вкладки на панели инструментов, group - группы элементов, которые визуально отделяются друг от друга вертикальной чертой, button - элементы кнопок.

Для того чтобы отобразить такую панель в Excel нужно наследовать классу ExcelRibbon и переопределить метод GetCustomUI в котором возвращаем XML панели.

using ExcelDna.Integration.CustomUI;  

namespace ExcelAddIn.Controllers;  

public class RibbonController : ExcelRibbon
{
    public override string GetCustomUI(string ribbonID)
    {
        return @"<customUI xmlns='http://schemas.microsoft.com/office/2006/01/customui'>
      <ribbon>
        <tabs>
          <tab id='MyAddinTab' label='My Addin Tab'>
            <group id='MyAddinGroup' label='My Addin Group'>
                <button id='Button1' label='Button 1' size='large' imageMso='HappyFace' />
                <button id='Button2' label='Button 2' size='large' imageMso='SadFace' />
                <button id='Button3' label='Button 3' size='large' imageMso='Piggy' />
            </group>
          </tab>
        </tabs>
      </ribbon>
    </customUI>";
    }
}
Результат
Результат

Фабрика инструментов

Определим абстрактный класс инструмента, который будет вызываться кнопкой:

namespace ExcelAddIn.Tools;  

public abstract class Tool : IDisposable
{
    public abstract void Execute();  

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected abstract void Dispose(bool disposing);
}

И фабрику этих инструментов:

using ExcelDna.Integration.CustomUI;  

namespace ExcelAddIn.Tools;  

public static class ToolFactory
{
    public static Tool GetTool(IRibbonControl control)
    {
        return control.Id switch
        {
            "Button1" => new Button1Tool(),
            "Button2" => new Button2Tool(),
            "Button3" => new Button3Tool(),
            _ => throw new NotImplementedException(control.Id)
        };
    }
}

Чтобы кнопка заработала, нужно добавить в её описание атрибут onAction с именем метода который будем выполнять.

using ExcelDna.Integration.CustomUI;
using ExcelAddIn.Tools;
 
namespace ExcelAddIn.Controllers;  

public class RibbonController : ExcelRibbon
{
    public override string GetCustomUI(string ribbonID)
    {
        return @"<customUI xmlns='http://schemas.microsoft.com/office/2006/01/customui'>
      <ribbon>
        <tabs>
          <tab id='MyAddinTab' label='My Addin Tab'>
            <group id='MyAddinGroup' label='My Addin Group'>
                <button id='Button1' label='Button 1' size='large' imageMso='HappyFace' onAction='OnToolPressed'/>
                <button id='Button2' label='Button 2' size='large' imageMso='SadFace' onAction='OnToolPressed'/>
                <button id='Button3' label='Button 3' size='large' imageMso='Piggy' onAction='OnToolPressed'/>
            </group>
          </tab>
        </tabs>
      </ribbon>
    </customUI>";
    }
    
    public void OnToolPressed(IRibbonControl control)
    {
        using var tool = ToolFactory.GetTool(control);
        tool.Execute();
    }
}

Первый инструмент

Пусть первая кнопка просто покажет нам сообщение в MessageBox.

Чтобы надстройка смогла работать с Windows Forms нужно добавить в .csproj строку:

  <PropertyGroup>
	...
    <UseWindowsForms>true</UseWindowsForms>
  </PropertyGroup>

Теперь сделаем класс-наследник абстрактного класса Tool:

namespace ExcelAddIn.Tools; 

public class Button1Tool : Tool
{
    public override void Execute()
    {
        MessageBox.Show($"Message from {nameof(Button1Tool)}");
    } 

    protected override void Dispose(bool disposing)
    {
    }
}
Проверяем работу
Проверяем работу

Получаем доступ к рабочей книге

Взаимодействие с Excel - его рабочими книгами, листами, интерфейсом - осуществляется через интерфейс Application.

Чтобы получить к нему доступ нужно установить пакет ExcelDna.Interop:

dotnet add package ExcelDna.Interop

Объект Application является свойством класса ExcelDnaUtil.

Пусть вторая кнопка инкрементирует текущую ячейку:

using Application = Microsoft.Office.Interop.Excel.Application;  

namespace ExcelAddIn.Tools;  

public class Button2Tool : Tool
{
    private readonly Application app;

    public Button2Tool()
    {
        app = (Application)ExcelDnaUtil.Application;
    }
    
    public override void Execute()
    {
        if (app.ActiveCell == null)
        {
            return;
        }
        double? cellValue = app.ActiveCell.Cells.Value2;
        if (cellValue != null)
        {
            app.ActiveCell.Cells.Value2 = ++cellValue;
        }
    }  

    protected override void Dispose(bool disposing)
    {

    }
}
Работа второй кнопки
Работа второй кнопки

Строка состояния

В нижней части окна Excel есть строка состояния, куда можно выводить сервисную информацию.

Это бывает полезно для отображения процесса какой-либо ресурсоемкой задачи.

После окончания работы необходимо сбросить строку, передав ей значение false. Это вернет контроль над ней приложению Excel, иначе в ней зависнет последнее переданное нами сообщение.

using Application = Microsoft.Office.Interop.Excel.Application;  

namespace ExcelAddIn.Tools;  

public class Button3Tool : Tool
{
    private readonly Application app;
    
    public Button3Tool()
    {
        app = (Application)ExcelDnaUtil.Application;
    }

    public override void Execute()
    {
        for (int i = 0; i < 10;)
        {
            Thread.Sleep(400);
            app.StatusBar = $"Выполнено {++i * 10}%...";
        }
    }

    protected override void Dispose(bool disposing)
    {
        app.StatusBar = false;
    }
}
Работа строки состояния
Работа строки состояния

Заключение

В этой статье описываются основы создания собственной панели инструментов надстройки и её взаимодействие с Excel.

Код к этой и предыдущей статье лежит в репозитории https://gitea.cebotari.ru/chebser/ExcelAddIn

Комментарии (1)


  1. Surrogate
    17.06.2023 06:49

    Спасибо, хорошая статья!

    Немного не хватает: картинки со структурой проекта

    Фабрика инструментов

    И упоминания, о каком файле идёт речь (./Tools/ToolFactory.cs).

    Начинающим вроде меня это было бы полезно.

    После второго прочтения и просмотра репозитория, даже я понял.