visio二次开发——事件编程
- 首先,创建一个Visio事件侦听类
“`
///
/// Visio事件侦听类
///
[ComVisible(true)]
public sealed class EventSink : IVisEventProc
{
private Application eventApplication; //Visio应用程序对象
private Document eventDocument; //Visio文档对象
private int alertResponse;
public event VisioEventHandler OnShapeAdd; //形状添加事件
public event VisioEventHandler OnShapeClick; //形状点击事件
public event VisioEventHandler OnShapeDelete; //形状删除事件
public event VisioEventHandler OnMarkerEvent; //右键菜单事件阀门开关
public event VisioEventHandler OnCellChanged; //属性值修改事件
public event VisioEventHandler OnTextEdit; //文本编辑事件
public event QueryCancelEventHandler OnQueryCancelSelectionDelete; //选区选择删除事件
/// <summary>
/// 默认构造函数
/// </summary>
public EventSink()
{
}
/// <summary>
/// 对文档的相关处理事件进行侦听处理
/// </summary>
/// <param name="callingApplication">应用对象</param>
/// <param name="callingDocument">文档对象</param>
[CLSCompliant(false)]
public void AddAdvise(Application callingApplication, Document callingDocument)
{
// ArgumentValidation.CheckForNullReference(callingApplication, "callingApplication");
//ArgumentValidation.CheckForNullReference(callingDocument, "callingDocument");
// 保存应用程序对象,方便设置事件处理
eventApplication = callingApplication;
// 缓存AlertResponse 对象的值
alertResponse = callingApplication.AlertResponse;
// 保存文档对象,方便设置事件处理
eventDocument = callingDocument;
// 增加感兴趣的事件侦听处理
setAddAdvise();
return;
}
/// <summary>
/// 当事件被增加到事件列表后,且该事件被触发处理,那么IVisEventProc.VisEventProc 函数会被Visio进行调用
/// 事件增加通过SetAddAdvise函数进行处理。
/// </summary>
/// <param name="eventCode">触发的事件代码</param>
/// <param name="source">触发事件的源对象,该对象可能是一个Visio应用程序对象(application),也可以是文档对象(document)。</param>
/// <param name="eventId">触发的事件唯一性标识</param>
/// <param name="eventSequenceNumber">触发事件的相对顺序</param>
/// <param name="subject">发生该事件的对象应用,如对形状删除和增加的事件来说,对象就是形状本身。</param>
/// <param name="moreInfo">关于该事件的附加信息</param>
/// <returns>返回值会被忽略,除非事件是一个查询事件。如没有任何的查询事件,返回值对象是一个空值。</returns>
object IVisEventProc.VisEventProc(short eventCode, object source, int eventId,
int eventSequenceNumber, object subject, object moreInfo)
{
Application eventProcApplication = null;
Document eventProcDocument = null;
Shape eventShape = null;
Selection subjectSelection = null;
object result = null;
// 获得传递过来的应用程序对象或者文档对象
if (source is IVApplication)
{
eventProcApplication = (Visio.Application)source;
}
else if (source is IVDocument)
{
eventProcDocument = (Document)source;
}
// 检查每个事件代码是否被处理了。事件代码是对象和事件动作的联合对象。
// 仅当事件在SetAddAdvise方法里面增加后,事件会被发送到这里进行处理。
switch (eventCode)
{
// 形状新增事件
// VisEventCodes.visEvtAdd的值不能自动转换到一个short类型,通过unchecked函数,可以实现short类型的转换。
case (short)VisEventCodes.visEvtShape + unchecked((short)VisEventCodes.visEvtAdd):
eventShape = (Shape)subject;
handleShapeAdd(eventShape);
break;
//形状删除事件
case (short)VisEventCodes.visEvtDel + (short)VisEventCodes.visEvtShape:
eventShape = (Shape)subject;
handleShapeDelete(eventShape);
break;
//右键菜单事件
case (short)VisEventCodes.visEvtApp + (short)VisEventCodes.visEvtMarker:
handleMarker(eventProcApplication);
break;
//常规处理
case (short)VisEventCodes.visEvtApp + (short)VisEventCodes.visEvtNonePending:
handleNonePending(eventProcApplication);
break;
//单元属性值修改事件
case (short)VisEventCodes.visEvtCell + (short)VisEventCodes.visEvtMod:
Visio.Cell cell = (Cell)subject;
handleCellModify(cell);
break;
//形状文本编辑处理事件
case (short)VisEventCodes.visEvtCodeShapeExitTextEdit:
eventShape = (Shape)subject;
handleShapeExitTextEdit(eventShape);
break;
//选区对象删除的事件处理
case (short)VisEventCodes.visEvtCodeQueryCancelSelDel:
subjectSelection = (Visio.Selection)subject;
result = handleQueryCancelSelectionDelete(subjectSelection);
break;
case (short)VisEventCodes.visEvtCodeMouseDown:
subjectSelection = (Visio.Selection)subject;
result = handleQueryCancelSelectionDelete(subjectSelection);
break;
default:
break;
}
return result;
}
/// <summary>
/// 该方法增加相应的事件,用来响应对应Visio的行为处理。
/// 例如,增加或删除形状的事件为了和Visio控件表格数据保持一致,需要进行相应处理。
/// Marker事件(右键事件)用来响应形状的双击操作。
/// none-pending事件则是用在空闲时间对Visio进行的相应处理。
/// </summary>
/// <remarks>如果失败,则抛出异常信息</remarks>
private void setAddAdvise()
{
const string sink = "";
Event newEvent = null;
EventList applicationEvents = eventApplication.EventList;
EventList documentEvents = eventDocument.EventList;
// 增加shape-added形状添加事件到文档,新形状对象在该处理过程中可以使用。
// VisEventCodes.visEvtAdd的值不能自动转换为short类型,可以通过unchecked方法进行转换为short类型。
newEvent = documentEvents.AddAdvise(
(unchecked((short)VisEventCodes.visEvtAdd) + (short)VisEventCodes.visEvtShape),
(IVisEventProc)this, sink, "ShapeAdd");
//增加对文档的before-shape-deleted(形状删除前)事件处理。
//该事件在文档的形状删除后触发产生,删除的形状对象在处理过程中依旧是可用的
newEvent = documentEvents.AddAdvise(
(short)VisEventCodes.visEvtDel + (short)VisEventCodes.visEvtShape,
(IVisEventProc)this, sink, "ShapeDelete");
// 增加none-pending 事件处理,该事件在Visio空闲的时候触发。
newEvent = applicationEvents.AddAdvise(
(short)VisEventCodes.visEvtApp + (short)VisEventCodes.visEvtNonePending,
(IVisEventProc)this, sink, "NonePending");
//由于MarkertEvent只需执行一次事件绑定,因此先判断是否已经绑定
//如果多次绑定,会出现多次响应的情况
if (!IsContainEvent(applicationEvents, "MarkerEvent"))
{
newEvent = applicationEvents.AddAdvise(
(short)VisEventCodes.visEvtApp + (short)VisEventCodes.visEvtMarker,
(IVisEventProc)this, sink, "MarkerEvent");
}
//形状属性单元发生修改的事件
newEvent = documentEvents.AddAdvise(
(short)VisEventCodes.visEvtMod + (short)VisEventCodes.visEvtCell,
(IVisEventProc)this, sink, "CellChanged");
//形状文本退出修改的事件
newEvent = documentEvents.AddAdvise(
(short)VisEventCodes.visEvtCodeShapeExitTextEdit,
(IVisEventProc)this, sink, "ShapeExitedTextEdit");
//选区对象删除的事件
newEvent = documentEvents.AddAdvise(
(short)VisEventCodes.visEvtCodeQueryCancelSelDel,
(IVisEventProc)this, sink, "QueryCancelSelectionDelete");
return;
}
/// <summary>
/// 查看是否包含指定的事件
/// </summary>
private bool IsContainEvent(EventList eventList, string eventTargetArgs)
{
foreach (Event oneEvent in eventList)
{
if (oneEvent.TargetArgs == eventTargetArgs)
{
return true;
}
}
return false;
}
/// <summary>
/// 该方法在Visio事件全部被处理后被调用。
/// </summary>
/// <param name="idleApplication">空闲的应用程序对象</param>
private void handleNonePending(Application idleApplication)
{
}
/// <summary>
/// 该方法在形状添加后触发调用。
/// 形状对象已经存在,因此可以在后续使用进行引用处理。
/// 形状添加的实际处理过程,是在所有Visio事件处理完毕后进行。
/// </summary>
/// <param name="addedShape">待添加的形状对象</param>
private void handleShapeAdd(Shape addedShape)
{
//在绘图过程中如果用户组存在该形状,那么添加事件将会忽略这个添加的形状对象
//这样可以阻止OnShapeAdd事件触发,导致添加的对象被重复计算超过一次
if (!eventApplication.get_IsInScope((short)VisUICmds.visCmdObjectGroup))
{
OnShapeAdd(addedShape, new EventArgs());
}
}
private void handleShapeClick(Shape addedShape)
{
//在绘图过程中如果用户组存在该形状,那么添加事件将会忽略这个添加的形状对象
//这样可以阻止OnShapeAdd事件触发,导致添加的对象被重复计算超过一次
if (!eventApplication.get_IsInScope((short)VisUICmds.visCmdObjectGroup))
{
OnShapeClick(addedShape, new EventArgs());
}
}
///
/// 当形状被删除时,该方法会被调用。
/// 该形状对象在此过程依旧可用,因此形状的信息可以在下面继续被读取。
/// 形状添加的实际处理过程,是在所有Visio事件处理完毕后进行。
///
/// 待删除的形状对象
private void handleShapeDelete(Shape deletedShape)
{
if (!eventApplication.get_IsInScope((short)VisUICmds.visCmdObjectGroup))
{
OnShapeDelete(deletedShape, new EventArgs());
}
}
/// <summary>
/// 该方法当Visio触发marker事件的时候进行处理。
/// 当用户在形状上双击,在形状的EventDblClick单元上将会运行QueueMarkerEvent方法,触发marker事件。
/// </summary>
/// <param name="visioApplication">触发该事件的Visio应用程序</param>
private void handleMarker(Application visioApplication)
{
if (OnMarkerEvent != null)
{
string arguments = visioApplication.get_EventInfo((short)VisEventCodes.visEvtIdMostRecent);
// 获得形状的引用
Shape targetShape = VisioUtility.GetShapeFromArguments(visioApplication, arguments);
OnMarkerEvent(targetShape, new MarketEventArgs(arguments));
}
return;
}
/// <summary>
/// 形状属性单元发生修改的事件处理
/// </summary>
/// <param name="cell">单元对象</param>
private void handleCellModify(Cell cell)
{
if (OnCellChanged != null)
{
OnCellChanged(cell, new EventArgs());
}
}
/// <summary>
/// 形状文本退出修改的事件处理
/// </summary>
/// <param name="shape">形状对象</param>
private void handleShapeExitTextEdit(Shape shape)
{
if (OnTextEdit != null)
{
OnTextEdit(shape, new EventArgs());
}
}
/// <summary>
/// 选区对象删除的事件处理
/// </summary>
/// <param name="selection">选区对象</param>
/// <returns></returns>
private bool handleQueryCancelSelectionDelete(Visio.Selection selection)
{
bool result = false;
if (OnQueryCancelSelectionDelete != null)
{
result = OnQueryCancelSelectionDelete(selection, new EventArgs());
}
return result;
}
}
///
/// Market事件的参数
///
public class MarketEventArgs : EventArgs
{
private string argument = string.Empty;
/// <summary>
/// 参数表达式
/// </summary>
public string Argument
{
get { return argument; }
set { argument = value; }
}
public MarketEventArgs() { }
public MarketEventArgs(string argument)
{
this.argument = argument;
}
}
2. 初始化文档的事件处理类
partial class FrmConstruct
{
/// <summary>
/// 初始化文档的事件处理
/// </summary>
private void InitEventSink(Visio.Application targetApplication, Document targetDocument)
{
try
{
visioEventSink = null; // 释放上一次对应的事件处理
//创建一个事件接收器,连接事件到Visio的应用程序和文档。
visioEventSink = new EventSink();
visioEventSink.AddAdvise(targetApplication, targetDocument);
//侦听添加形状的事件
visioEventSink.OnShapeAdd += new VisioEventHandler(visioEventSink_OnShapeAdd);
//侦听形状删除的事件
visioEventSink.OnShapeDelete += new VisioEventHandler(visioEventSink_OnShapeDelete);
//侦听右键菜单的marker事件,当用户双击形状的时候触发
//visioEventSink.OnMarkerEvent += new VisioEventHandler(visioEventSink_OnMarkerEvent);
//侦听形状单元属性修改事件
//visioEventSink.OnCellChanged += new VisioEventHandler(visioEventSink_OnCellChanged);
//侦听形状文本内容修改事件
visioEventSink.OnTextEdit += new VisioEventHandler(visioEventSink_OnTextEdit);
//侦听选区删除处理事件
//visioEventSink.OnQueryCancelSelectionDelete += new QueryCancelEventHandler(visioEventSink_OnQueryCancelSelectionDelete);
}
catch (COMException error)
{
MessageUtil.ShowError("An unknown COM error occurred:" + error.Message);
throw;
}
}
private void visioEventSink_OnTextEdit(object sender, EventArgs e)
{
MessageBox.Show("文本修改");
}
/// <summary>
/// 处理形状删除的事件,它将移除指定形状表格上的信息。
/// </summary>
/// <param name="sender">事件的触发形状对象</param>
/// <param name="e">事件关联参数,在此被忽略使用。</param>
private void visioEventSink_OnShapeDelete(object sender, EventArgs e)
{
MessageBox.Show("删除");
}
/// <summary>
/// 在用户添加设备后,我们为特定的设备增加对应的右键菜单事件。
/// 当用户双击形状的时候,触发对应的右键菜单事件(marker event)
/// </summary>
/// <param name="sender">用户双击的Visio形状对象 </param>
/// <param name="e">事件关联参数,在此被忽略使用。</param>
private void visioEventSink_OnShapeAdd(object sender, EventArgs e)
{
MessageBox.Show("添加");
}
}
“`
注意:上面两个类要在同一命名空间下