Silverlight click event registered a second time before first event completed - silverlight

I have a button which launches a "modal dialog" - it just creates a transparent grid covering everything, with the "dialog" created on top of that.
However I have a strange issue - if I double/triple click the button really fast (or add some delay in the event code), the button click event is executed multiple times, creating multiple overlapping modal dialogs. If the first action in my event is to disable the button (IsEnabled=false) it seems to prevent this.
My guess is that Silverlight is being multithreaded with input - it is not only recording the second click in another thread (while the button's click event is running), but it is jumping the gun by evaluating which control should be the target before the previous event has finished executing. Even though that event alters what control is at those mouse coordinates, it doesn't matter.
Does anyone know anything about this behavoir, or a way around it? If I have something like a save window, where the user clicks a save button, a blocking grid ("Saving...") is placed up while it saves, and then the whole "window" is closed, I'd like to avoid the user being able to queue up multiple save event clicks (this could lead to unpredictable program behavoir).

If you've ever worked with WinForms or WPF, this is expected behavior. Your button is broadcasting its Click event until your modal dialog covers it up. Unfortunately, there is some amount of time between your first click and when the modal dialog covers the button which allows multiple clicks to the original button.
You have two solution choices:
Disable the button after the first click and then re-enable after the modal dialog returns. You've already mentioned that this works.
Write code in the Event Handler of the button to determine if a modal dialog is already being displayed. This way, you're putting the responsibility in one location rather than splitting it up (disabling and re-enabling the button). This would be my preferred solution.

I think what you're seeing is the behaviour of Silverlight's routed events.
You can set the Handled property of the event arguments to true to prevent the event from bubbling.

Related

Drag finger from one button to another - want to un-trigger old button and trigger new button - Windows Store

I am working on a windows store application and I want to be able to drag between buttons so that the originally pressed button becomes deactivated and the newly "dragged onto" button becomes activated but I can't seem to get this to work.
I have 2 Buttons inside a StackPanel and the events I have on them are:
PointerPressed
PointerEntered
PointerReleased
PointerExited
PointerCanceled
PointerCaptureLost
PointerPressed and PointerEntered share the same event handler and the rest (the "deactivation" events) share the same event handler.
If I press one button my "activated" event handler is triggered and if I drag off it my "deactivated" event handler is triggered but if I then drag onto the second button the "activated" event handler isn't triggered again.
Strangely, if I start by dragging from off the StackPanel onto one of the buttons the "activated" event handler is triggered. I assume that it is something to do with the internal pointer management stuff but can't seem to find a workaround.
Does anyone know why this is happening and how I can get it to work how I want?
Thanks for your time.
Edit
Okay I've been researching some stuff and I've come across CapturePointer() and ReleasePointerCapture() but this seems to be broken - If I capture the pointer, when I take my finger off the screen, PointerReleased doesn't even get hit.
I've also realized why the "dragging from off the SP onto one of the buttons causes it to 'activate'" - this is because when a button is pressed it doesn't route its event but fires a Click event - meaning the same pointer cannot fire a PointerEntered event of another button, but if it starts outside a Button it will trigger PointerEntered.
This doesn't get me much further but it is a little extra info :)
The concept of Button is a bit unique in regard to mouse capture and how dragging away from it happens. In your scenario I'm not sure if the event model around Button will work correctly for you. On Button, when a pointer is depressed (mouse) it has capture until it is released. This is not the same for touch where a press and drag away is different because in touch there isn't any explicit capture unless you create it.
So what you are hitting is going to be a slight conflict between mouse/touch interactions anyway using Button -- using some other UI element (not sure if you have a styled button) should get you what you want.

WPF menu and multitouch

I have a menu that is implemented in a way that when a menu item is pressed, a popup containing it's sub-items is open.
When running with touch screen, occasionally user touches 2 menu items at the same time with his fingers - and this leads to one of the menuitems have a touch capture which is not released until another window gets focus, making the app seem stuck.
How can I prevent such a case?
thanks
You could use a queue that contains delegates:
When triggering a command, add the delegate to the queue.
Then grab the first delegate of the queue and flush it afterwards.
Now you only have 1 "command".
I found the cause for the problem: the popup used to display submenu items had StaysOpen set to false.
This causes the Popup to capture input so it can know when to close itself once a click was made outside its boundaries.
Setting its StaysOpen property to True fixed the issue.

Name of closing button on Windows Forms

What's the name of the default red button with an X in the middle at the top right?
EDIT: I want to get the event associated with clicking that button.
You cannot disable the close box on its own using in properties window like you can with the minimize and maximize boxes. You can however disable the control box which contains them all.
Setting ControlBox to false will remove the minimize, maximize and close buttons.
You might want to consider why you are doing this though, as it's generally a good idea to let users quit out of windows using the close button (think of it as a cancel button).
EDIT:
You can handle when the user clicks on that close button using either the Closing or the Closed events of the Form. The difference between the two is that the Closing event fires before the form has closed (meaning that you can veto the closure by setting the Cancel property of the FormClosingEventArgs to true), whereas the Closed event fires after the form has actually closed.
it is possible to hook all messages goes to a form by implementing ImessageFilter interface
this link can be use full Using IMessageFilter to create a generic filter for operating system events
You can disable it by setting the ControlBox to false in the form properties, or in code like the following:
this.ControlBox = false;
Setting this will also hide the minimize and maximize buttons if that is OK. If not, the solution is a bit more elaborate.

WPF toplevel MenuItem enable/disable based on task

I have a top-level menu item which is responsible for refreshing a datagrid in the same window. My current control flow is:
User clicks on refresh
In the click event handler, I:
Disable the menuitem, by setting oMenuItem.IsEnabled = false.
Dispatch an action to refresh the grid and in that action, I re-enable the menuitem, by setting IsEnabled = true
The problem is that the user can click refresh even when it's disabled and it's as if the clicks get queued up. When the action returns it goes on to process the remaining, "queued-up" clicks. What I expect is: all clicks while the menuitem is disabled are ignored and only when it's enabled, the clicks are acknowledged.
The weird thing is that if I just disable it and never enable it it stays that way, i.e., it is disabled.wpf,
"Dispatch an action" you mean by calling Dispatcher.BeginInvoke() or some other kind of async opetation?
Anyway, in both cases you can get a "handle" to the operation (DispatcherOperation or IAsyncResult) and store it as a field when you dispatch your operation. When it completes - set this field to null.
In the click event handler of the menu-item check this field. If it's null it means it is safe to start the operation. If it is not null - return immediately and do nothing.
And something not related to your question but important - why not use Commands? That way you don't need to play with event handling and enabling/disabling. And of course commands can be invoked by multiple means (for example - the user selected the command from the menu using the keyboard and pressed Enter. No mouse clicks involved, but should do the same as clicking the menu item).
Alex.

How can I make a 'Partially' modal dialog?

Is there a way to start off showing a dialog modally, but then instead of hiding it, to keep it visible while changing it to a non-modal dialog?
I want to show a dialog, blocking the method that shows the dialog. Then when the user clicks the 'Finish' button on the dialog I want:
The dialog to remain visible.
Control to return to the method that showed the dialog.
I've achieved this result by running the dialog on a separate STA thread, and using an event to block the main UI thread until 'Finish' is pressed, but there's a catch to this method: you can click on the close button of the 'main' window while the dialog is visible, and the main window closes when the dialog is hidden.
Update
Thanks for the responses so far. Sorry - it looks like I got the balance wrong between too much background and not enough.
The form is effectively a modal 'wizard' dialog - it appears, sits in front of the main app modally, and then is hidden. So as far as the user's concerned there's no non-standard weirdness going on. The only difference is that the dialog is driven from a series of callbacks from the UI thread, so I don't think making it truly modal (via a call to ShowDialog) for its lifetime would work. The first callback must show the dialog, and then block while the user sets their preferences via the dialog UI. After that, the dialog stays visible and displays a progress bar page while various other callbacks are made from the UI thread. Eventually the form is hidden. The user isn't interacting with the main window while the form is up. As far as they're concerned, it should appear to be 100% modal wrt the main UI thread.
(The form is a dialog for a Visual Studio wizard - these are driven from a series of callbacks on the UI thread). An alternative would be to show the dialog, hide it, immediately show a topmost 'progress' form instead and then hide that, but I think showing a single dialog is more seamless an experience for the user.
Again - sorry for the confusion!
Perhaps you want to rethink your interaction model? How are you going to explain this to your users? They have an internalized model of how computer programs work, and you better have a very good reason to break that. They know about modal dialogs, they know about non-modal dialogs, they know about inspectors. Choose one, and apply it.
Modal dialogs are made for short-time interaction. They should not block exiting the application. The user is in control of the interaction, the program only provides the minimum of restrictions needed.
[after the explanation, replaced]
What's wrong with showing the progress bar in the modal dialog? Start processing once ok
is clicked, disabling all buttons, only keeping the cancel button active? If it takes a long time, the user might want to abort the action. Only close the dialog when you're finished processing.
You could use a modeless dialog then have your main UI check if the user has clicked the Finished button. If the modeless dialog is open but Finished hasn't been clicked then don't respond to any users actions in the main form...
This is just a terrible idea - it's completely non-standard behavior and you're going to jump through all kinds of hoops to get something working that is just going to horribly confuse your users.
Like most of the other answers here stated, you're implement non-standard UI elements that will be confusing to most users.
If the dialog remains visible just to provide read-only access to the data, then why not have dialog window close normally and open a side-bar window in your application with the data from the dialog window?
If the dialog remains visible to allow the users to continue making updates in it, then perhaps, it shouldn't be modal to begin with.
Point is, there's a couple different ways you can accomplish your task without breaking standard UI metaphors.
I'd make it a flyout from the side or bottom of your app that shoves other things out of the way. If it's on top of other stuff that the user might need to see or interact with then it's just gonna annoy them.
I found that showing an an invisible modal dialog on the main UI thread during the blocking stage of the interaction works great.
Hidden modal dialog settings (so it's not visible): ShowInTaskBar=false, FormBorderStyle=None, size={0,0}, Opacity=0%, StartupPosition=CenterParent.
The hidden dialog is shown on the UI thread using ShowDialog. The visible dialog is shown on a separate STA thread. The thread is kicked off before calling hiddenDialog.ShowDialog on the main UI thread.
The visible dialog hides hiddenDialog when it wants the initial blocking state to complete. This stops the main UI thread from blocking.
The important bits of code:
void LaunchWizardForm(s)
{
// Show the wizard on its own thread.
ThreadStart t = () =>
{
_wizard = new WizardForm(s);
Application.Run(new ApplicationContext(_wizard));
};
var thread = new Thread(t);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
// Block this (main UI) thread
_hiddenForm.ShowDialog();
}
void EndModalEpisode()
{
_hiddenForm.Invoke((Action) (() => _hiddenForm.Hide()));
}

Resources