65.9K
CodeProject 正在变化。 阅读更多。
Home

在 VS2017 中创建 Visio 插件

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2018年2月4日

CPOL

5分钟阅读

viewsIcon

11981

如何在 VS2017 中创建 Visio 插件

问题陈述

一位好朋友问了我一个问题:

如何在 Visio 中,通过简单地选择一个形状,就将其颜色更改为之前选择的颜色?

听起来很简单,但有一些注意事项,所以这是我尝试解决这个问题的方法。主要的注意事项包括:

  • 连接 `SelectionChanged` 事件
  • 在功能区(Ribbon)中保持和访问状态(用于默认颜色)
  • 设置所选形状的颜色

该项目的代码可以在 此处找到。

Visio 插件 – 准备工作

我决定使用 Visual Studio 2017 来创建 Visio 插件。为此,我们需要安装“Office/SharePoint 开发”工作负载。自 Visual Studio 2017 起,安装程序支持模块化安装,所以我们只需要将此项添加到我们的安装中。

启动 **Visual Studio Installer**(开始 -> 输入“Visual Studio Installer”)。在安装程序窗口中,选择“更多 > 修改”

image

稍后,这将带我们进入工作负载选择屏幕。选择 Office/SharePoint 开发,然后单击“修改”。

image

当您再次启动 Visual Studio 时,您会发现一堆新的项目模板。

创建 Visio 插件

在 VS 中,创建一个新项目(文件 > 新建 > 项目…),如下所示:

image

正如您所看到的,“Office/SharePoint”有新的项目模板。我选择了 Visio Add-in 项目,并给它起了一个恰当的名字“ActOnShapeSelection”。

结果是一个包含一个 C# 文件(ThisAddIn.cs)的项目。我们将在那里初始化我们的事件。作为测试,我们在启动插件时显示一个消息框,在关闭插件时显示另一个消息框。

public partial class ThisAddIn
{
    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        MessageBox.Show("Startup ActOnShapeSelection");
    }

    private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
    {
        MessageBox.Show("Shutdown ActOnShapeSelection");
    }

    // …
}

**注意**:默认情况下,namespace System.Windows.Forms 不包含在 using 列表中,因此我们需要添加它。一个简单的方法是点击带有红色下划线的 MessageBox 并键入 ctrl+;(即 control + 分号)。现在我们可以选择如何解决“using 问题”。

现在启动应用程序(**F5**)将启动 Visio,并显示我们的第一个消息框。关闭 Visio 会显示第二个消息框。到目前为止,没有什么高深的,但这证明了我们的插件已正确加载到 Visio 中。

让 Visio 在形状被选中时执行操作稍微困难一些。

连接 Selected 事件

public partial class ThisAddIn
{
    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        Application.SelectionChanged += Application_SelectionChanged;
    }

    private void Application_SelectionChanged(Visio.Window Window)
    {
        MessageBox.Show("SelectionChanged ActOnShapeSelection");
    }
// …
}

SelectionChanged 事件必须在 `startup` 事件中连接。稍后,我们将对 `ShapeAdded` 事件执行相同的操作。一旦您了解了这个“技巧”,事情就会变得容易。

运行此代码时,每次我们在 Visio 中选择内容时,都会看到我们漂亮的弹出消息框。因此,事件连接是有效的。现在我们希望只在选择形状时执行代码。让我们研究一下是否可以从“Window”参数中找到有关所选对象的信息。

image

正如预期的那样,这是一个动态对象。Visio 是通过 COM 访问的。幸运的是,调试器允许展开动态视图成员。浏览该对象的成员,我们找到了一个名为“Selection”的属性。这看起来很有希望!再看下去,“Selection”是 `IVSelection` 接口的实现。并且该接口继承自 `IEnumerable`。

所以 Selection 实际上是所有选中项的可枚举集合,因此可以使用标准的 foreach() 来处理。让我们试试这个:

private void Application_SelectionChanged(Visio.Window Window)
{
    //MessageBox.Show("SelectionChanged ActOnShapeSelection");
    Visio.Selection selection = Window.Selection;
    foreach (dynamic item in selection)
    {
        Visio.Shape shp = item as Visio.Shape;
        if (shp != null)
        {
            shp.Characters.Text = "selected";
        }
    }
}

我们再次运行插件(F5),并在页面上添加 2 个形状。当我们选中形状时,它们将显示文本“selected”。现在我们能够知道哪些形状被选中并对它们执行有用的操作。让我们添加一个新的功能区(Ribbon)来对我们的形状执行操作。毕竟,这就是本次练习的目的。

添加功能区

可以通过右键单击项目,选择“新建项”来轻松完成。然后选择 Office/SharePoint > Ribbon (Visual Designer)。

image

将此功能区命名为“ActionsRibbon”。

打开功能区,我们现在可以使用可视化设计器。确保工具箱窗口可见(视图 > 工具箱)。

现在我们在设计表面添加 3 个 ToggleButton,分别命名为 btnRedbtnGreen,您猜对了:btnBlue。对于每个按钮,我们通过双击按钮添加一个 Click 事件。使用 **GroupView Tasks**,我们还添加了一个 DialogBoxLauncher。这将打开一个 ColorDialog 用于选择自定义颜色。

image

双击组以实现“DialogLauncherClick”事件,该事件将处理此功能。

ActionsRibbon 将包含自己的数据,即颜色的 3 个分量(RedGreenBlue)。

public byte Red { get; private set; }
public byte Green { get; private set; }
public byte Blue { get; private set; }

每个切换按钮将切换其自己的颜色分量。

private void btnRed_Click(object sender, RibbonControlEventArgs e)
{
    Red = (byte)(255 - Red);
}

private void btnGreen_Click(object sender, RibbonControlEventArgs e)
{
    Green = (byte)(255 - Green);
}

private void btnBlue_Click(object sender, RibbonControlEventArgs e)
{
    Blue = (byte)(255 - Blue);
}

**注意**:当没有自定义颜色选项时,此代码可以正常工作。选择自定义颜色时,值将变为非 0255,并且不再与 UI 对应。我将使其成为读者练习,以实现更好的实现。

选择自定义颜色

private void group1_DialogLauncherClick(object sender, RibbonControlEventArgs e)
{
    ColorDialog dlg = new ColorDialog { Color = Color.FromArgb(Red, Green, Blue) };

    if (dlg.ShowDialog() == DialogResult.OK)
    {
        Red = dlg.Color.R;
        Green = dlg.Color.G;
        Blue = dlg.Color.B;
    }
}

在我们的 AddIn 类的 SelectionChanged 事件中,我们现在需要引用来自 Ribbon 的 RGB 值。以下是事件处理程序的完整代码:

private void Application_SelectionChanged(Visio.Window Window)
{
    ActionsRibbon rib = Globals.Ribbons.ActionsRibbon;
    Visio.Selection selection = Window.Selection;
    foreach (dynamic item in selection)
    {
        Visio.Shape shp = item as Visio.Shape;
        if (shp != null)
        {
            shp.Characters.Text = "selected";
            shp.CellsSRC[(short)Visio.VisSectionIndices.visSectionObject,3, 0].FormulaU = 
                                           $"THEMEGUARD(RGB({rib.Red}, {rib.Green}, {rib.Blue}))";
        }
    }
}

有一些 **Visio 的技巧** 来设置颜色。请将其视为食谱。当您这样做时,您将获得期望的结果。可以说,Visio 并不总是直观的。

现在我们有了一个工作的 Visio 插件,它完成了被要求的功能。但是,当我们添加一个新形状时,它会自动接收所选颜色。为了解决这个问题,我们添加另一个事件处理程序:

Application.ShapeAdded += Application_ShapeAdded;

我们还添加一个布尔值,指示我们是否正在添加形状。

bool _isAddingAShape = false;

ShapeAdded 事件中,我们将其值设置为 true

private void Application_ShapeAdded(Visio.Shape Shape)
{
    _isAddingAShape = true;
}

我们修改 SelectionChanged 事件,使其在添加形状时不做任何事情。当选择形状时,以及当添加形状时(实际上会选中它),都会调用此事件。代码如下:

private void Application_SelectionChanged(Visio.Window Window)
{
    if (! _isAddingAShape)
    {
        ActionsRibbon rib = Globals.Ribbons.ActionsRibbon;
        Visio.Selection selection = Window.Selection;
        foreach (dynamic item in selection)
        {
            Visio.Shape shp = item as Visio.Shape;
            if (shp != null)
            {
                shp.Characters.Text = "selected";
                shp.CellsSRC[(short)Visio.VisSectionIndices.visSectionObject, 3, 0].FormulaU = 
                                    $"THEMEGUARD(RGB({rib.Red}, {rib.Green}, {rib.Blue}))";
            }
        }
    }
    _isAddingAShape = false;
}

结论

使用 Visual Studio,我们花费了大约 100 行代码来实现所需行为。添加更多功能区操作并不难。但那样的话,最好将执行操作的代码移到 ActionRibbon 类中,而不是在 AddIn 类中使用该类的值。

最困难的部分是找到如何在 AddIn 类中获取新创建的 Ribbon。其余的只是直接实现。

© . All rights reserved.