AIBMass
asked on
Can I stop DoubleClick from firing an event in another Window?
This is driving me crazy.
I have a number of labels in Window1. Clicking a specific label correctly causes Window2, which has some buttons on it, to be brought to the front.
If my user double-clicks on the label in Window1 and the ultimate position of one of the buttons in Window2 is in the same location as the label in Window1, the button fires. This is not desirable!
I can't just handle the double-click event in Window1, because that's not where the event shows up. I get the MouseClick event in Window1 which puts Window2 in place and then the event in Window2 fires.
Does anyone know how to control this?
I have a number of labels in Window1. Clicking a specific label correctly causes Window2, which has some buttons on it, to be brought to the front.
If my user double-clicks on the label in Window1 and the ultimate position of one of the buttons in Window2 is in the same location as the label in Window1, the button fires. This is not desirable!
I can't just handle the double-click event in Window1, because that's not where the event shows up. I get the MouseClick event in Window1 which puts Window2 in place and then the event in Window2 fires.
Does anyone know how to control this?
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
I realized that hence you need to reread the comment!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Below is an example of #3:
*If you need double clicks to be valid elsewhere in the application then you'll need to modify the filter so you can notify it when to ignore clicks; and also allow it to reset itself after the lockout period.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
Application.AddMessageFilter(New DoubleClickKiller)
End Sub
Private Sub Label1_Click(sender As System.Object, e As System.EventArgs) Handles Label1.Click
Dim f2 As New Form2
f2.StartPosition = FormStartPosition.Manual
f2.Location = Me.Location
f2.Show()
End Sub
End Class
Public Class DoubleClickKiller
Implements IMessageFilter
Private Const WM_LBUTTONDOWN = &H201
Private IgnoreWindowInMilliseconds As Integer = SystemInformation.DoubleClickTime ' <-- use the default, or specify your own time
Private Last_WM_LBUTTONDOWN As DateTime = DateTime.MinValue
Public Function PreFilterMessage(ByRef m As System.Windows.Forms.Message) As Boolean Implements System.Windows.Forms.IMessageFilter.PreFilterMessage
Select Case m.Msg
Case WM_LBUTTONDOWN
Dim CurrentDateTime = DateTime.Now
If Last_WM_LBUTTONDOWN <> DateTime.MinValue Then
If CurrentDateTime.Subtract(Last_WM_LBUTTONDOWN).TotalMilliseconds <= IgnoreWindowInMilliseconds Then
Return True ' Consume the click so it doesn't propagate to the application
End If
End If
Last_WM_LBUTTONDOWN = CurrentDateTime
End Select
Return False ' Allow valid messages to be processed normally
End Function
End Class
*If you need double clicks to be valid elsewhere in the application then you'll need to modify the filter so you can notify it when to ignore clicks; and also allow it to reset itself after the lockout period.
ASKER
Let me see. First, an apology to CodeCruiser. Indeed I was responding to some other message rather than the one that was written.
CodeCruiser's suggestion to locate Window2 away from the MouseClick would certainly work. I see the following problems: 1. Because any of the windows in the application can be moved around the placement logic is not simple and 2. We are permanently subjecting some components of the application (Window1) to know about the UI of other components (Window2) and this is highly undesirable. Still, it will have merit in some simple cases.
Idle_Mind has two excellent suggestions. The DoubleClickKiller class works perfectly as supplied. I am strongly considering this method as I don't think the application has any actual call for a DoubleClick. However, this is a bit esoteric for many and that's a disadvantage.
Finally, I am considering a variation of Idle_Mind's second suggestion. I set a variable to the current time when the form is loaded and then provider a function for the Click events to call to verify that the difference between the form load time and the click time exceeds the double click time. This code should be easily understandable even if the motivation for having it is not.
Thanks to both CodeCruiser and Idle_Mind.
CodeCruiser's suggestion to locate Window2 away from the MouseClick would certainly work. I see the following problems: 1. Because any of the windows in the application can be moved around the placement logic is not simple and 2. We are permanently subjecting some components of the application (Window1) to know about the UI of other components (Window2) and this is highly undesirable. Still, it will have merit in some simple cases.
Idle_Mind has two excellent suggestions. The DoubleClickKiller class works perfectly as supplied. I am strongly considering this method as I don't think the application has any actual call for a DoubleClick. However, this is a bit esoteric for many and that's a disadvantage.
Finally, I am considering a variation of Idle_Mind's second suggestion. I set a variable to the current time when the form is loaded and then provider a function for the Click events to call to verify that the difference between the form load time and the click time exceeds the double click time. This code should be easily understandable even if the motivation for having it is not.
Thanks to both CodeCruiser and Idle_Mind.
There's no good solution to this problem. =\
While definitely esoteric, the DoubleClickKiller() solution doesn't require changes to every button handler in the application. You just load it with the one line and you're done!
Application.AddMessageFilt er(New DoubleClickKiller)
The other route will require changes all over the place and increases the chances that you'll make a mistake, or forget to add that additional code down the line if the UI changes.
Good luck!
While definitely esoteric, the DoubleClickKiller() solution doesn't require changes to every button handler in the application. You just load it with the one line and you're done!
Application.AddMessageFilt
The other route will require changes all over the place and increases the chances that you'll make a mistake, or forget to add that additional code down the line if the UI changes.
Good luck!
ASKER
Post Mortem: Before implementing the DoubleClickKiller, I am anticipating a problem. Think of the label(s) on Form1 as being Order Numbers and that Form2 is the detail window for orders.
Depending on the size of the order and other issues, it may take anywhere from .25 second to 4 or 5 seconds for Form2 to appear. Thus I fear the second mousedown may be a few seconds, rather than some milliseconds, after the first and thus blow the whole scheme.
I guess I'll have to find out.
Depending on the size of the order and other issues, it may take anywhere from .25 second to 4 or 5 seconds for Form2 to appear. Thus I fear the second mousedown may be a few seconds, rather than some milliseconds, after the first and thus blow the whole scheme.
I guess I'll have to find out.
Keep us posted...I'm curious.
ASKER
Real life experience with DoubleClickKiller.
Setting the interval between the MouseButtonDown events to 1 second is too fast for Form2 to load. Setting it to 3 seconds works fine in this specific regard, but I am concerned that this is way too long for other parts of the application.
I will turn now to some variation of the timers.
Setting the interval between the MouseButtonDown events to 1 second is too fast for Form2 to load. Setting it to 3 seconds works fine in this specific regard, but I am concerned that this is way too long for other parts of the application.
I will turn now to some variation of the timers.
I would look at the loading code in Form2. Can that be threaded with the BackgroundWorker()?...
ASKER
I am going with setting a timestamp when the form has been loaded and filled with data and insisting that the button click be more than 250 milliseconds from that time.
This was way too difficult.
It seems like an underlying Windows flaw that a UI event from one Window can show up in another Window. It just shouldn't be so :(
This was way too difficult.
It seems like an underlying Windows flaw that a UI event from one Window can show up in another Window. It just shouldn't be so :(
Well...part of the problem is that all user interaction gets processed in the main UI thread. If you thread the length record loading work, then the main UI thread can be free to process that second pending click, and consequently discard it. If all the work remains in the main UI thread and takes longer than one second to load, then the pending messages also sit there for one second waiting to be processed. If the loading takes even longer then can end up with an un-responsive UI, or a "white out" where the main form being displayed doesn't repaint while the secondary form is still loading.
ASKER