在Visio中,根据用户选择的形状自动应用颜色似乎是一个简单的任务,但实际上它涉及到几个关键的技术点。本文将介绍如何使用Visual Studio 2017创建一个Visio插件,实现这个功能。主要的技术挑战包括:
首先,需要在Visual Studio 2017中安装“Office/SharePoint开发”工作负载。从Visual Studio 2017开始,安装程序允许模块化安装,所以只需要添加这个工作负载到安装中。
启动Visual Studio Installer(开始 -> 输入“Visual Studio Installer”)。在安装程序窗口中,选择“更多 > 修改”:
稍等片刻后,将进入工作负载选择屏幕。选择Office/SharePoint开发,然后点击“修改”。
当再次启动Visual Studio时,会发现有一组新的项目模板。
在VS中,创建一个新项目(文件 > 新建 > 项目...),如下所示:
如所见,有新的项目模板用于“Office/SharePoint”。选择了Visio插件项目,并给它一个合适的名称“ActOnShapeSelection”。
结果是一个包含一个C#文件的项目(ThisAddIn.cs)。这是将初始化事件的地方。作为一个测试,在启动插件时显示一个消息框,关闭它时再显示一个:
public partial class ThisAddIn
{
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
MessageBox.Show("启动ActOnShapeSelection");
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
MessageBox.Show("关闭ActOnShapeSelection");
}
}
注意:默认情况下,System.Windows.Forms命名空间不包含在using列表中,所以需要添加它。一个简单的方法是点击下划线的消息框,然后输入ctrl+;(控制+分号)。现在可以选择如何解决“using问题”。
启动应用程序(F5)现在将启动Visio,第一个消息框确实显示出来了。关闭Visio会显示第二个消息框。到目前为止,没有什么复杂的,但这证明了插件已正确加载到Visio中。
说服Visio在形状被选中时做一些事情只是稍微困难一些。
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事件必须在启动事件中连接。稍后,将为ShapeAdded事件做同样的事情。一旦知道了这个“技巧”,事情就变得容易了。
运行这段代码时,每次在Visio中选择一些东西,就会看到消息框。所以事件连接工作。现在希望能够只在形状被选中时执行代码。让调查一下能否在“Window”参数中找到关于选定对象的一些信息:
正如预期的那样,这是一个动态对象。Visio通过COM访问。幸运的是,调试器允许展开动态视图成员。查看这个对象的成员,发现一个属性“Selection”。这看起来很有希望!再进一步,“Selection”是IVSelection接口的实现。这个接口继承自IEnumerable。
所以Selection实际上是一个可枚举的集合,包含了所有选定的项目,因此可以使用标准的foreach()来处理。让试试这个:
private void Application_SelectionChanged(Visio.Window Window)
{
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)。
将这个Ribbon命名为“ActionsRibbon”。
打开Ribbon,现在可以使用视觉设计器。确保工具箱窗口是可见的(视图 > 工具箱)。
现在在设计表面上添加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-fu来设置颜色。把它看作是一个食谱。当这样做时,会得到预期的结果。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;
}