Visio二次开发的事件编程主要分为四个步骤:
首先,需要创建visio事件代理和visio事件处理类,并添加需要处理的事件;
其次,对需要处理的事件向对象进行注册,即添加到对象的EventList事件列表中,并同时指定visio事件处理类。这样,当对象触发了相应的事件后,能够向事件处理类发出通知;
再次,需要实现事件处理类的事件处理方法,以便当接到通知后,能够做出相应的处理;
最后,根据接收到的事件通知,判断其事件代码、事件源、作用对象、事件ID等参数,来触发相应的需要处理的事件。
下面结合源码给予说明:
1. 创建visio事件代理和visio事件处理类,并添加需要处理的事件
/// <summary>
/// 是一个用于处理visio事件的visio事件代理
/// </summary>
/// <param name="sender">引发事件的visio对象</param>
/// <param name="e">与事件相关的参数</param>
public delegate void VisioEventHandler(object sender, EventArgs e);
/// <summary>
/// 这是一个visio事件处理类,继承IVisEventProc。
/// 所有的注册了的visio事件发出通知后,都会调用VisEventProc()过程;
/// </summary>
public sealed class EventSink : IVisEventProc{…};
/// <summary>
/// 图形添加事件
/// </summary>
public event VisioEventHandler OnShapeAdd;
/// <summary>
/// 图形删除事件
/// </summary>
public event VisioEventHandler OnShapeDelete;
/// <summary>
/// 定义图形双击事件
/// </summary>
public event VisioEventHandler OnShapeDoubleClick;
2.向对象注册事件,可以接收注册事件的对象有:Application和Document。就是将事件分为处于应用层的事件(和应用相关的事件),还有文档层的事件(只和文档相关的事件)。那么哪一些事件和Application相关?哪一些事件和Document相关呢?可以参考前一篇文章“visio二次开发_事件篇_事件分类”。这里和Application相关的事件与和Document相关的事件有点区别,关于这方面的内容,在后续的文章会有介绍。
向对象注册事件,其实就是调用对象的EventList的AddAdvise()方法:
假设有Application对象visApplication和Document对象visDocument。
EventList applicationEvents = visApplication.EventList;
EventList documentEvents = visDocument.EventList;
Event newEvent = null;
// 向visDocument注册该文档的图形添加事件
newEvent = documentEvents.AddAdvise(
(unchecked((short)VisEventCodes.visEvtAdd) +
(short)VisEventCodes.visEvtShape),
(IVisEventProc)this, sink, targetArgs);
// 向visDocument注册该文档的图形删除事件
newEvent = documentEvents.AddAdvise(
(short)VisEventCodes.visEvtDel +
(short)VisEventCodes.visEvtShape,
(IVisEventProc)this, sink, targetArgs);
// 向visApplication注册该应用的标签事件
newEvent = applicationEvents.AddAdvise(
(short)VisEventCodes.visEvtApp +
(short)VisEventCodes.visEvtMarker,
(IVisEventProc)this, sink, targetArgs);
3.实现事件处理类的事件处理方法,根据 eventCode判断是什么样的事件,这里需要注意的是要将VisEventCodes强制转变为short类型。关于标签事件在后续的文章中会介绍:
object IVisEventProc.VisEventProc(short eventCode, object source,
int eventId,
int eventSequenceNumber,
object subject,
object moreInfo)
switch (eventCode)
{
// 根据 VisEventCodes判断是什么样的事件;
// 注意要将VisEventCodes强制转变为short类型
//判断是否为图形添加事件;
case (short)VisEventCodes.visEvtShape +
unchecked((short)VisEventCodes.visEvtAdd):
// 调用handleShapeAdd()去抛出图形添加事件
eventShape = (Shape)subject;
handleShapeAdd(eventShape);
break;
//判断是否为图形删除事件;
case (short)VisEventCodes.visEvtDel +
(short)VisEventCodes.visEvtShape:
// 调用handleShapeDelete()去抛出图形删除事件
eventShape = (Shape)subject;
handleShapeDelete(eventShape);
break;
//判断是否为应用的标记事件;
case (short)VisEventCodes.visEvtApp +
(short)VisEventCodes.visEvtMarker:
// 调用handleMarker()去抛出标签事件
handleMarker(eventApplication);
break;
}
4. 触发相应的需要处理的事件。由于篇幅原因,这里只给出图形添加的例子。需要注意的事情是,为了提高效率,往往会使用队列来处理这些图形添加事件,就是暂时将添加的图形放到队列中去,等到空闲的时候,再出队处理(即抛出事件):
private void handleShapeAdd(Shape addedShape)
{
if (OnShapeAdd != null)
OnShapeAdd(addedShape, new EventArgs());
}
当然要进行事件编程,到这里并没有结束。需要进行事件编程的组件还要向这个visio事件处理类的实例对象注册事件处理方法:
EventSink visioEventSink = new EventSink();
//注册图形添加处理事件;
visioEventSink. OnShapeAdd += new VisioEventHandler(visioEventSink_OnShapeDoubleClick);
//注册图形删除处理事件;
visioEventSink. OnShapeDelete +=
new VisioEventHandler(visioEventSink_OnSelectTheSameFloorShape);
其实本文主要介绍了如何注册事件,相应事件通知,再分别抛出事件等过程。抛砖引玉,希望大家提出自己的高见。
下面是完整的源码:
Code
using System;
using System.Diagnostics;
using Microsoft.Office.Interop.Visio;
namespace IndoorDistribut
{
/// <summary>
/// 是一个用于处理visio事件的visio事件代理
/// </summary>
/// <param name="sender">引发事件的visio对象</param>
/// <param name="e">与事件相关的参数</param>
public delegate void VisioEventHandler(object sender, EventArgs e);
/// <summary>
/// 这是一个visio事件处理类,继承IVisEventProc。
/// 所有的注册了的visio事件发出通知后,都会调用VisEventProc()过程;
///
/// </summary>
public sealed class EventSink : IVisEventProc
{
/// <summary>Visio.Application 对象.</summary>
private Microsoft.Office.Interop.Visio.Application
eventApplication = null;
/// <summary>Visio.Document 对象.</summary>
private Document eventDocument = null;
/// <summary>Visio Application.AlertResponse value.</summary>
private int alertResponse = 0;
/// <summary>Two FIFO queues are used to store added and deleted
/// shape information while Visio events are being processed.</summary>
private System.Collections.Queue shapeAddedQueue = null;
private System.Collections.Queue shapeDeletedQueue = null;
/// <summary>
/// 图形添加事件
/// </summary>
public event VisioEventHandler OnShapeAdd;
/// <summary>
/// 图形删除事件
/// </summary>
public event VisioEventHandler OnShapeDelete;
/// <summary>
/// 定义图形双击事件
/// </summary>
public event VisioEventHandler OnShapeDoubleClick;
public EventSink()
{
// 创建图形添加和删除的事件队列
shapeAddedQueue = new System.Collections.Queue();
shapeDeletedQueue = new System.Collections.Queue();
}
/// <summary>
/// 当然这首先要通过AddAdvise()添加需要侦测的事件。
/// 也就是需要用AddAdvise()向visio注册事件;
/// summary>
[CLSCompliant(false)]
public void AddAdvise(
Microsoft.Office.Interop.Visio.Application callingApplication,
Document callingDocument)
{
if (callingApplication == null)
{
throw new ArgumentNullException("callingApplication","");
}
if (callingDocument == null)
{
throw new ArgumentNullException("callingDocument","");
}
eventApplication = callingApplication;
alertResponse = callingApplication.AlertResponse;
eventDocument = callingDocument;
setAddAdvise();
return;
}
object IVisEventProc.VisEventProc(short eventCode,
object source,
int eventId,
int eventSequenceNumber,
object subject,
object moreInfo)
{
Microsoft.Office.Interop.Visio.Application eventApplication = null;
Document eventDocument = null;
Shape eventShape = null;
if (source is IVApplication)
{
eventApplication =
(Microsoft.Office.Interop.Visio.Application)source;
}
else if (source is IVDocument)
{
eventDocument = (Document)source;
}
switch (eventCode)
{
// 根据 VisEventCodes判断是什么样的事件;
// 注意要将VisEventCodes强制转变为short类型
//判断是否为图形添加事件;
case (short)VisEventCodes.visEvtShape +
unchecked((short)VisEventCodes.visEvtAdd):
// 调用handleShapeAdd()去抛出图形添加事件
eventShape = (Shape)subject;
handleShapeAdd(eventShape);
break;
//判断是否为图形删除事件;
case (short)VisEventCodes.visEvtDel +
(short)VisEventCodes.visEvtShape:
// 调用handleShapeDelete()去抛出图形删除事件
eventShape = (Shape)subject;
handleShapeDelete(eventShape);
break;
//判断是否为应用的标记事件;
case (short)VisEventCodes.visEvtApp +
(short)VisEventCodes.visEvtMarker:
// 调用handleMarker()去抛出标签事件
handleMarker(eventApplication);
break;
case (short)VisEventCodes.visEvtApp +
(short)VisEventCodes.visEvtNonePending:
handleNonePending(eventApplication);
break;
default:
break;
}
return null;
}
private void setAddAdvise()
{
const string sink = "";
const string targetArgs = "";
Event newEvent = null;
EventList applicationEvents = eventApplication.EventList;
EventList documentEvents = eventDocument.EventList;
try
{
// 向visDocument注册该文档的图形添加事件
newEvent = documentEvents.AddAdvise(
(unchecked((short)VisEventCodes.visEvtAdd) +
(short)VisEventCodes.visEvtShape),
(IVisEventProc)this, sink, targetArgs);
// 向visDocument注册该文档的图形删除事件
newEvent = documentEvents.AddAdvise(
(short)VisEventCodes.visEvtDel +
(short)VisEventCodes.visEvtShape,
(IVisEventProc)this, sink, targetArgs);
// 向visApplication注册该应用的标签事件
newEvent = applicationEvents.AddAdvise(
(short)VisEventCodes.visEvtApp +
(short)VisEventCodes.visEvtMarker,
(IVisEventProc)this, sink, targetArgs);
newEvent = applicationEvents.AddAdvise(
(short)VisEventCodes.visEvtApp +
(short)VisEventCodes.visEvtNonePending,
(IVisEventProc)this, sink, targetArgs);
}
catch (Exception e)
{
;
}
return;
}
/// visio空闲时,需做的处理
private void handleNonePending(
Microsoft.Office.Interop.Visio.Application idleApplication)
{
// 处理添加图形事件队列
if (OnShapeAdd != null)
{
while (shapeAddedQueue.Count > 0)
{
OnShapeAdd(shapeAddedQueue.Dequeue(), new EventArgs());
}
}
else
{
shapeAddedQueue.Clear();
}
// 处理添加图形事件队列
if (OnShapeDelete != null)
{
while (shapeDeletedQueue.Count > 0)
{
OnShapeDelete(shapeDeletedQueue.Dequeue(),
new EventArgs());
}
}
else
{
shapeDeletedQueue.Clear();
}
return;
}
private void handleShapeAdd(Shape addedShape)
{
shapeAddedQueue.Enqueue(addedShape);
return;
}
private void handleShapeDelete(Shape deletedShape)
{
shapeDeletedQueue.Enqueue(productId);
return;
}
}
}