在 VS2017 中创建 Visio 插件





5.00/5 (3投票s)
如何在 VS2017 中创建 Visio 插件
问题陈述
一位好朋友问了我一个问题:
如何在 Visio 中,通过简单地选择一个形状,就将其颜色更改为之前选择的颜色?
听起来很简单,但有一些注意事项,所以这是我尝试解决这个问题的方法。主要的注意事项包括:
- 连接 `SelectionChanged` 事件
- 在功能区(Ribbon)中保持和访问状态(用于默认颜色)
- 设置所选形状的颜色
该项目的代码可以在 此处找到。
Visio 插件 – 准备工作
我决定使用 Visual Studio 2017 来创建 Visio 插件。为此,我们需要安装“Office/SharePoint 开发”工作负载。自 Visual Studio 2017 起,安装程序支持模块化安装,所以我们只需要将此项添加到我们的安装中。
启动 **Visual Studio Installer**(开始 -> 输入“Visual Studio Installer”)。在安装程序窗口中,选择“更多 > 修改”
稍后,这将带我们进入工作负载选择屏幕。选择 Office/SharePoint 开发,然后单击“修改”。
当您再次启动 Visual Studio 时,您会发现一堆新的项目模板。
创建 Visio 插件
在 VS 中,创建一个新项目(文件 > 新建 > 项目…),如下所示:
正如您所看到的,“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
”参数中找到有关所选对象的信息。
正如预期的那样,这是一个动态对象。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)。
将此功能区命名为“ActionsRibbon
”。
打开功能区,我们现在可以使用可视化设计器。确保工具箱窗口可见(视图 > 工具箱)。
现在我们在设计表面添加 3 个 ToggleButton
,分别命名为 btnRed
、btnGreen
,您猜对了:btnBlue
。对于每个按钮,我们通过双击按钮添加一个 Click
事件。使用 **GroupView Tasks**,我们还添加了一个 DialogBoxLauncher
。这将打开一个 ColorDialog
用于选择自定义颜色。
双击组以实现“DialogLauncherClick
”事件,该事件将处理此功能。
ActionsRibbon
将包含自己的数据,即颜色的 3 个分量(Red
、Green
、Blue
)。
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);
}
**注意**:当没有自定义颜色选项时,此代码可以正常工作。选择自定义颜色时,值将变为非 0
或 255
,并且不再与 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
。其余的只是直接实现。