Пишем надстройку Excel на Excel-DNA. Часть 2

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Введение

Это продолжение статьи о создании надстройки для 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

Источник: https://habr.com/ru/articles/741732/


Интересные статьи

Интересные статьи

Несколько недель назад в блоге «.NET Blog» появилась статья «Что такое .NET, и почему вы должны выбрать его?». В нем был представлен высокоуровневый обзор платформы, кратко описаны различные компоне...
Функционал раций покрывает все нужды в своей нише, но, учитывая, что мобильный телефон всегда под рукой, хотелось бы попробовать сочетать утилитарность раций и удобство смартфона. Даже возможность пер...
Привет, друзья! Представляю вашему вниманию третью (заключительную) часть перевода этой замечательной книги по WebRTC. Первая часть. Вторая часть. Если вам это интересно, прошу под кат. ...
Я решил составить краткую шуточную инструкцию для начинающих некромантов, которые захотят поднимать из мертвых лазеры на парах меди. Виктор Франкенштейн «вдыхал жизнь» в мертвецов, а мы проделаем...
История об исследовании и разработке в 3-х частях. Часть 1 — исследовательская. Буков много — пользы еще больше. Постановка задачи В ходе проведения пентестов и RedTeam кампаний не всегда уд...