Disabling shape and selection events while handle connections even

J

Josef Meile

Hi

I added the following events to my event sink class using the
AddAdvise method:

Shape added: visEvtShape + visEvtAdd
Query Selection delete: visEvtCodeQueryCancelSelDel
Connection added: visEvtConnect + visEvtAdd
Connection deleted: visEvtConnect + visEvtDel

The problem I'm having is that during connecting or disconnecting shapes
sometimes I need to paste or delete some shapes, so, the shape added
event or query selection delete event will be triggered as well. I would
like to disable the shape added and query selection delete events while
handling the connection events. I have tried several things, but I haven't
had any success:

Alternative 1:

1) Save the event codes and its corresponding events ids of the events added
to my event sink. ie:

to add an event I did the following inside a method from my sink class:

//Shape added event
short eventCode = (short)Visio.VisEventCodes.visEvtShape +
(short)Visio.VisEventCodes.visEvtMod;

Visio.Event addedEvent = eventList.AddAdvise(eventCode,this, "", "");
DocumentEvents[eventCode] = addedEvent.ID;

//Same for the query selection deleted
eventCode = (short)Visio.VisEventCodes.visEvtCodeQueryCancelSelDel;
addedEvent = eventList.AddAdvise(eventCode,this, "", "");
DocumentEvents[eventCode] = addedEvent.ID;

2) Whenever I handle a connection added or deleted event, disable the
shape added and query selection delete events, process the event, and
enable the events again:

//Shape added event
short eventCode = (short)Visio.VisEventCodes.visEvtShape +
(short)Visio.VisEventCodes.visEvtMod;
int eventId = (int) DocumentEvents[eventCode];
Visio.EventList eventList = vsoDocument.EventList;
Visio.Event shapeAddedEv = eventList.get_ItemFromID(eventId);
shapeAddedEv.Enabled = 0;

//Same for the query selection deleted comes here
eventCode =
selDeleteEv = ....

//Proccess event here

//At the end, enable events again
shapeAddedEv.Enabled = 1;
selDeleteEv.Enabled = 1;

3) After having handled the connection events I set the Enable property to
1. At this point, the program exists from the VisEventProc method, then
later it fires either the shape added or the query selection deleted event.
So, it means that somehow the event was deffered instead of being disabled.

Alternative 2:

1) Add the events to the sink class and to the DocumentEvents as done in
the first step of Alternative 1.

2) When handling the connection events, delete the event from the EventList
Collection, process the event and add the events again (ugly):

//Shape added event
eventCode = (short)Visio.VisEventCodes.visEvtShape +
(short)Visio.VisEventCodes.visEvtMod;
eventId = (int) DocumentEvents[eventCode];
Visio.EventList eventList = vsoDocument.EventList;
Visio.Event shapeAddedEv = eventList.get_ItemFromID(eventId);
//physically delete the shape added event
shapeAddedEv.Delete();

//Same for the query selection deleted comes here
selDeleteEv = ....

//Proccess event here

//At the end, add the events again
short eventCode = (short)Visio.VisEventCodes.visEvtShape +
(short)Visio.VisEventCodes.visEvtMod;

Visio.Event addedEvent = eventList.AddAdvise(eventCode,this, "", "");
DocumentEvents[eventCode] = addedEvent.ID;

//Same for the query selection deleted
eventCode = (short)Visio.VisEventCodes.visEvtCodeQueryCancelSelDel;
addedEvent = eventList.AddAdvise(eventCode,this, "", "");
DocumentEvents[eventCode] = addedEvent.ID;

This method worked similar to the alternative 1. Either the shape added or
query selection delete events were fired after returning from the VisEventProc
method. I have to admit that I really don't like this approach.

Alternative 3: Use several combination of the OnComponentEnterState method of
the application object:

1) This behaved the same as alternatives 1 and 2:

visioApp.OnComponentEnterState(
Visio.VisOnComponentEnterCodes.visComponentStateModal |
Visio.VisOnComponentEnterCodes.visModalDisableVisiosFrame |
Visio.VisOnComponentEnterCodes.visModalDontBlockMessages, true);

//Handle event here

visioApp.OnComponentEnterState(
Visio.VisOnComponentEnterCodes.visComponentStateModal |
Visio.VisOnComponentEnterCodes.visModalDisableVisiosFrame |
Visio.VisOnComponentEnterCodes.visModalDontBlockMessages, false);

I also tried without the visModalDisableVisiosFrame, but the effect was
the same.

Alternative 4 (in progress): whenever an event is caught, instead of handling
it, put the event type and the data it modifies into a queue (ArrayList
maybe),
then in the handler of the NoEventsPending event, process that queue and each
time that a connection event is going to be handled, set a flag, which will
avoid
adding other events to enter to the queue.

I think I will give a try to Alternative 4, which was suggested by Mark
Nelson in
a post from Jan 29 2004:

* preventing events to be fired
group: microsoft.public.visio.developer
http://tinyurl.com/cq54g


But the question is: when I disconnect a shape and connect it to another one
without releasing the mouse button, is there any chance that first the
connection
delete event occurs, then the NoEventsPending event and finally the connection
added event? If so, then I will have problems again because I need always to
handle both events.

Finally, if somebody else has another suggestion, you are welcome to post it.

Regards
Josef
 
J

JuneTheSecond

Too many lines make me unable to catch what you really say.
But if you stop the listner, i think you can edit your drawing freely.
 
J

Josef Meile

Too many lines make me unable to catch what you really say.
I'm handling the shape added, the connection added and deleted events. The
problem is that while handling the connection events, I also need to paste
some shapes for which I want to disable the shape added event.
But if you stop the listner, i think you can edit your drawing freely.
Yes, but the question is how I do this. I have tried several alternatives
without any success.

Thanks for your reply
Josef
 
J

JuneTheSecond

I've tested a code to delete events in the help document for AddAdvice method.
When i run DeleteEventObjects, then events stopped, and when i run
CreateEventObjects, then events started again.
 
H

Heidi Munson [MSFT]

Enabling/Disabling the event object often does not work well when you are
trying to disable events that fire as a result of actions you performed by
your application, especially when the events you want to disable are after
events. Shape Added, Connection Added and Connection deleted are all after
events. QueryCancelSelectionDelete is not. Visio fires after events from a
background queue. If you disable the event object for an after event,
perform the action and then enable the event object, you will enable your
event handler before Visio fires the event and as a result you will often
still be notified of the action.



An alternative approach is to use marker events to mark the beginning and
end of actions performed by your solution. The idea is to fire a marker
event before you perform your actions and another one after you perform your
actions. You need to be able identify both the before marker event and the
after maker event. All events that fire between them are events caused by
your actions and can be ignored. To use this technique your solution must
listen to marker events. There is more detail about this approach here.

http://groups.google.com/group/microsoft.public.visio.developer/msg/74c4eccb11d6af6d



Note: You should only change the enable state of the event objects you
create via AddAdvise. Each time you call AddAdvise an event object is
returned. If you ever want to enable/disable or stop event firing of that
event for your implementation of IVisEventProc then you need to hold onto
the event object returned from your call to AddAdvise and only call
enable/delete on that. Calling ItemFromID on the EventList will return an
event object for that event but it will often not be the one you created.





-Heidi
Microsoft Corp

This posting is provided "AS IS" with no warranties, and confers no rights


Josef Meile said:
Hi

I added the following events to my event sink class using the
AddAdvise method:

Shape added: visEvtShape + visEvtAdd
Query Selection delete: visEvtCodeQueryCancelSelDel
Connection added: visEvtConnect + visEvtAdd
Connection deleted: visEvtConnect + visEvtDel

The problem I'm having is that during connecting or disconnecting shapes
sometimes I need to paste or delete some shapes, so, the shape added
event or query selection delete event will be triggered as well. I would
like to disable the shape added and query selection delete events while
handling the connection events. I have tried several things, but I haven't
had any success:

Alternative 1:

1) Save the event codes and its corresponding events ids of the events added
to my event sink. ie:

to add an event I did the following inside a method from my sink class:

//Shape added event
short eventCode = (short)Visio.VisEventCodes.visEvtShape +
(short)Visio.VisEventCodes.visEvtMod;

Visio.Event addedEvent = eventList.AddAdvise(eventCode,this, "", "");
DocumentEvents[eventCode] = addedEvent.ID;

//Same for the query selection deleted
eventCode = (short)Visio.VisEventCodes.visEvtCodeQueryCancelSelDel;
addedEvent = eventList.AddAdvise(eventCode,this, "", "");
DocumentEvents[eventCode] = addedEvent.ID;

2) Whenever I handle a connection added or deleted event, disable the
shape added and query selection delete events, process the event, and
enable the events again:

//Shape added event
short eventCode = (short)Visio.VisEventCodes.visEvtShape +
(short)Visio.VisEventCodes.visEvtMod;
int eventId = (int) DocumentEvents[eventCode];
Visio.EventList eventList = vsoDocument.EventList;
Visio.Event shapeAddedEv = eventList.get_ItemFromID(eventId);
shapeAddedEv.Enabled = 0;

//Same for the query selection deleted comes here
eventCode =
selDeleteEv = ....

//Proccess event here

//At the end, enable events again
shapeAddedEv.Enabled = 1;
selDeleteEv.Enabled = 1;

3) After having handled the connection events I set the Enable property to
1. At this point, the program exists from the VisEventProc method, then
later it fires either the shape added or the query selection deleted event.
So, it means that somehow the event was deffered instead of being disabled.

Alternative 2:

1) Add the events to the sink class and to the DocumentEvents as done in
the first step of Alternative 1.

2) When handling the connection events, delete the event from the EventList
Collection, process the event and add the events again (ugly):

//Shape added event
eventCode = (short)Visio.VisEventCodes.visEvtShape +
(short)Visio.VisEventCodes.visEvtMod;
eventId = (int) DocumentEvents[eventCode];
Visio.EventList eventList = vsoDocument.EventList;
Visio.Event shapeAddedEv = eventList.get_ItemFromID(eventId);
//physically delete the shape added event
shapeAddedEv.Delete();

//Same for the query selection deleted comes here
selDeleteEv = ....

//Proccess event here

//At the end, add the events again
short eventCode = (short)Visio.VisEventCodes.visEvtShape +
(short)Visio.VisEventCodes.visEvtMod;

Visio.Event addedEvent = eventList.AddAdvise(eventCode,this, "", "");
DocumentEvents[eventCode] = addedEvent.ID;

//Same for the query selection deleted
eventCode = (short)Visio.VisEventCodes.visEvtCodeQueryCancelSelDel;
addedEvent = eventList.AddAdvise(eventCode,this, "", "");
DocumentEvents[eventCode] = addedEvent.ID;

This method worked similar to the alternative 1. Either the shape added or
query selection delete events were fired after returning from the VisEventProc
method. I have to admit that I really don't like this approach.

Alternative 3: Use several combination of the OnComponentEnterState method of
the application object:

1) This behaved the same as alternatives 1 and 2:

visioApp.OnComponentEnterState(
Visio.VisOnComponentEnterCodes.visComponentStateModal |
Visio.VisOnComponentEnterCodes.visModalDisableVisiosFrame |
Visio.VisOnComponentEnterCodes.visModalDontBlockMessages, true);

//Handle event here

visioApp.OnComponentEnterState(
Visio.VisOnComponentEnterCodes.visComponentStateModal |
Visio.VisOnComponentEnterCodes.visModalDisableVisiosFrame |
Visio.VisOnComponentEnterCodes.visModalDontBlockMessages, false);

I also tried without the visModalDisableVisiosFrame, but the effect was
the same.

Alternative 4 (in progress): whenever an event is caught, instead of handling
it, put the event type and the data it modifies into a queue (ArrayList
maybe),
then in the handler of the NoEventsPending event, process that queue and each
time that a connection event is going to be handled, set a flag, which will
avoid
adding other events to enter to the queue.

I think I will give a try to Alternative 4, which was suggested by Mark
Nelson in
a post from Jan 29 2004:

* preventing events to be fired
group: microsoft.public.visio.developer
http://tinyurl.com/cq54g


But the question is: when I disconnect a shape and connect it to another one
without releasing the mouse button, is there any chance that first the
connection
delete event occurs, then the NoEventsPending event and finally the connection
added event? If so, then I will have problems again because I need always to
handle both events.

Finally, if somebody else has another suggestion, you are welcome to post it.

Regards
Josef
 
J

Josef Meile

I've tested a code to delete events in the help document for AddAdvice
method.
When i run DeleteEventObjects, then events stopped, and when i run
CreateEventObjects, then events started again.
Yes, it looks a little bit similar to what I did in my first alternative
(see my orignal
post). However, the diference is that I'm storing the event code and the id
of the event object returned by AddAdvice. Then later I retreived the Event
with the
get_ItemFromID of the EventList object.

Anyway, Heidi Munson pointed that get_ItemFromID not always gives me the
event I created, so, I will try storing the object itself as in the example
you mentioned.

Thanks
Josef
 
J

Josef Meile

Enabling/Disabling the event object often does not work well when you are
trying to disable events that fire as a result of actions you performed by
your application, especially when the events you want to disable are after
events. Shape Added, Connection Added and Connection deleted are all after
events. QueryCancelSelectionDelete is not. Visio fires after events from a
background queue. If you disable the event object for an after event,
perform the action and then enable the event object, you will enable your
event handler before Visio fires the event and as a result you will often
still be notified of the action.
So, it explains the behaviour of my solution. Now it is clearer.
An alternative approach is to use marker events to mark the beginning and
end of actions performed by your solution. The idea is to fire a marker
event before you perform your actions and another one after you perform your
actions. You need to be able identify both the before marker event and the
after maker event. All events that fire between them are events caused by
your actions and can be ignored. To use this technique your solution must
listen to marker events. There is more detail about this approach here.

http://groups.google.com/group/microsoft.public.visio.developer/msg/74c4eccb11d6af6d
Thanks for your advice. It looks like what I'm looking for. I will give it a
try.
Note: You should only change the enable state of the event objects you
create via AddAdvise. Each time you call AddAdvise an event object is
returned. If you ever want to enable/disable or stop event firing of that
event for your implementation of IVisEventProc then you need to hold onto
the event object returned from your call to AddAdvise and only call
enable/delete on that.
Ok, I guess it wouldn't work anyway if I store the event object instead of
the id.
According to your first paragraph, even if I enable/disable an after event
inside
the handler method, the events that were fired after will be still be still
fired. So,
I guess my best alternative are the marker events.
Calling ItemFromID on the EventList will return an event object for that event but it will
often not be the one you created.
So, then I'm just wondering what is the purpose of this method.

Thanks
Josef
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top