Preventing mouse events on a form

Posted by Admin on 05-Mar-2009 11:22

I'm attempting to disable all mouse events for an MDI form and it's child tabs without having to figure out all the events to unsubscribe to.

I've been looking at implementing IMessageFilter to selectively filter the mouse events but have not been able to figure out how to use it or whether it can even be used in 10.2.

What I attempted was to first create a class that implements IMessageFilter (System.Windows.Forms). The class contains one method named PreFilterMessage. In that method I would test m:Msg to see if it matched one of the mouse event message constants and return true if it does.

In my app, I perform a NEW on the class:

MyFilterVar = NEW Filters.NoFormClick().

System.Windows.Forms.Application:AddMessageFilter

(MyFilterVar).

The application throws the following error:

System.NullReferenceException: Object reference not set to an instance of an object.

My goal is to prevent events from firing if users click on the form if I have a long running process. I have tried disabling the main form, but the event fires anyway once the form is re-enabled. I also cannot use a modal dialog in these cases.

Any help or suggestions would be greatly appreciated.

Thanks,

JL

All Replies

Posted by Håvard Danielsen on 05-Mar-2009 13:37

I have never tried to use this, but all Infragistics Controls has an EventManager that you can grab and then use to disable/enable certain events. There are different types of event managers. The more advanced ones, like the one for the grid, have methods to disable all before- or after events- in one call, while others support fewer operations. So this might still require that you need to figure out which events you need to disable.

See Infragistics Online Documentation.

Posted by Admin on 09-Apr-2009 13:07

Havard,

Thanks for the reply.

I've been trying a number of different approaches including setting the EventManager for select controls. For example, I tried to disable events in the UltraExplorer bar by using:

- FrameworkExplorer:EventManager:AllEventsEnabled = FALSE.

Unfortunately, this doesn't seem to work or I'm doing something incorrectly. I've tried setting the MDI parent Enabled property to false, but if I click on something, it still fires after resetting the MDI parent back to true.

I've been lookup at examples of System.Windows.Forms.IMessageFilter to see if I could basically throw away select messages such as mouse clicks. I've had no luck with this either; it doesn't seem to fire. I believe I've implemented this correctly...it no longer throws an error in SP1.

USING Progress.Lang.*.
USING System.Windows.Forms.IMessageFilter.
USING Api.*.  /* this contains api constants and methods */


CLASS Filters.NoFormClick IMPLEMENTS IMessageFilter  :
   
    METHOD PUBLIC LOGICAL PreFilterMessage
        ( INPUT-OUTPUT m AS System.Windows.Forms.Message ):
               
        CASE m:Msg:
            WHEN Win32:WM_LEFTMOUSEDOWN   OR
            WHEN Win32:WM_LEFTMOUSEUP     OR
            WHEN Win32:WM_RIGHTMOUSEDOWN  OR
            WHEN Win32:WM_RIGHTMOUSEUP    OR
            WHEN Win32:WM_MIDDLEMOUSEDOWN OR
            WHEN Win32:WM_MIDDLEMOUSEUP THEN
                RETURN TRUE.
        END CASE.
       
        RETURN FALSE.
       
    END METHOD.
   
END CLASS.

In my code...

MyNoFormClick  = NEW Filters.NoFormClick().

Then, when I want to prevent the user from performing any actions using the mouse...


System.Windows.Forms.Application:AddMessageFilter(MyNoFormClick).

and when done with the long running process...

System.Windows.Forms.Application:RemoveMessageFilter(MyNoFormClick).

Please let me know if I am totally off base here. Essentially I would like the MDI parent to behave as if there's a modal dialog, but without the modal dialog.

Thanks,

Jim

Posted by Thomas Mercer-Hursh on 09-Apr-2009 13:36

If one had a multithreaded client ... hint, hint ... then it would be reasonable to try to trap such events during the long running process and respond with "Be patient" or whatever.  It is possible someone will come along and answer your question as you have phrased it, i.e., actually disabling such events during the long running process, but that could be dangerous since you would have to be absolutely sure that you got them re-enabled again after the process was complete, even in the event of an error.  As an alternative, have you considered the possibility of setting it up so that rather than preventing them, you go in to a mode where they are discarded when the process completes ... flush the queue as it were ... possibly with a message telling the user you have done so.  Then, when the queue is empty, put things back to normal.

Mind you, I don't personally know how to do that either, but I thought it might be a different way to think about the problem.

Posted by Admin on 09-Apr-2009 14:22

Yes...multithreading could possibly solve a couple of issues here. The first would be allowing the long running process to be sent to another thread.

I have thought about what you suggest, but I'm think it could get difficult to manage. Almost any event we subscribed to would need to contain code in its event that checks to see if there's a long running process active (maybe by way of a central static property). I'll have to run this by the others in my group to get their opinion. It would need to be set up as a coding standard that everyone would adhere to. It's not out of the question, but low on the list.

I'm still not convinced that will correct the problem though. What I believe I'm seeing here is that, due to being single threaded, the running process is delaying the event (mouse click) from firing until the process finishes. For example, the process could be a 'for each' that is looping through a large number of records. If I disable the form, and then, while the process is running, click on an object that normally fires an event, the event fires after the form is re-enabled. A PROCESS EVENTS statement in the loop might solve this, but it is not allowed inside a method. This may also be preventing the MessageFilter I created from doing what it's supposed to.

We have discussed moving long running processes into their own background Progress sessions, but that poses other problems such as transaction scope and integrity.

Posted by Thomas Mercer-Hursh on 09-Apr-2009 14:28

Suitable use of user controls and inheritance might simplify the implementation ... but, I think you are right that the events are only going to get queued while the long running process is active.  This, of course, makes it more complicated.  I am thinking of setting a flag at the start of the process, returning from the process and allowing all events to fire, and only then turning off the flag and going back to normal processing.  This requires either having a way to tell that there are pending events or perhaps a timer.  I.e., one might start a timer on return from the LRP and then reset it in each event.  If one then reached some specified interval with no events firing, then the flag would get switched.

Posted by jquerijero on 18-Jun-2009 14:44

Try overlaying a panel on top of your form.

Posted by Admin on 18-Jun-2009 15:06

Thanks Joseph,

I did try that but could never get it to look right. Plus I still had the issue with the actual click event being queued so that after I hid the panel, the click actually fired.

Jim

Posted by jquerijero on 18-Jun-2009 16:17

By the way, are you already calling PROCESS EVENTS after the long process is done but before reenabling the Form?

Posted by Admin on 18-Jun-2009 16:20

No.

I've had a lot of problems trying to use Process Events. See http://communities.progress.com/pcom/thread/17176?tstart=0 from a coworker.

Posted by Thomas Mercer-Hursh on 18-Jun-2009 16:31

Sounds like what you need is

PROCESS-EVENTS( False).

to discard the event queue. 

Seriously, though, I have seen such things in other languages and it seems to make sense.

Posted by jquerijero on 18-Jun-2009 16:32

Since PROCESS EVENTS' usage in the case is not for UI update, hopefully, it won't cause you much trouble. What you are dealing with are queued events. Even if you can catch those events, it will still happen after the long running process.

Posted by Thomas Mercer-Hursh on 18-Jun-2009 16:45

Yes but wouldn't it be nice to be able to:

1) Simply discard the event queue and let the user know that one is paying attention again; and/or

2) Suspend normal processing of the event queue and loop through it inspecting the nature of the events, deleting those which are inappropriate, and then resume processing the event queue again?

Of course, it they would give us a multi-threaded client, we could do better than that.

This thread is closed