C# Preventing clicks on a form without using Enabled=false - c#

I have a form that requires a long operation (expansion of a treeview node searches the network for additional items to create more tree nodes) - so I plan on using a BackgroundWorker for this task. During the long operation I want the cursor to be the wait cursor and I want the entire form to be unclickable except for the Cancel button. I know I could use Enabled=false but this turns the treeview grey which looks pretty lame imo.
I could just NOT use a BW but that means I have to use DoEvents to get the cursor to change and that possibly "Not Responding" would show up, which I hate.
I thought of handling all the mouse click events and keyboard events so that they are cancelled if the BW is busy... so that is my current plan. I just wondered if I am missing something, if there is another way.
Thanks.

There is no easy way to do that. It is better to fix your treeview and use Enabled property. You can also show your progressbar in Modal dialog - that will block UI

You could use a Panel as an overlay over the form, wholly or partly transparent, which only propagates clicks when over the cancel button - similar to the way browsers simulate modal windows by 'graying' the background with an overlay.
When you are in processing mode, set the Z-Order of the mask to be in front of all other controls, and when that finishes set it behind them.

You could use Background worker and pop up another dialog with progressbar and that shows current progress and a cancel button. Where you can user
popup = new ProgressWindow();
popup.Owner=this;
popup.show();
And the cancel button will cancel the background worker. In this way your back form will not be clickable and popup will remain on top with cancel button.

Related

How to detect when the visual tree is destroyed?

In a WPF application I have, I have a control that is central to the application. This control, called ArtView, is visible for the entire lifetime of the main window. It performs hardware accelerated rendering, and in order to avoid bogging down the UI thread, I set up an event loop in the OnLoaded handler for this control. Events such as mouse clicks, keyboard input, and scrolling are added to a queue that is then consumed by the event loop, but the problem I have is that I do not know how to end the event loop when the window is closed. When I close the window that contains the control, OnUnloaded does not fire, so what is the best way to disable the event loop when the control is no longer visible?
I am aware that I can do something like Window.GetWindow(this).Closing += OnWindowClosing; but that feels like a hack.
dymanoid's solution of subscribing to IsVisibleChanged works flawlessly, and provides a more satisfying solution than depending on the Window for the cleanup of my control.

Disabling all controls during a callback

I have a DevExpress Callback panel with a group of buttons and a text box inside of it. When the user clicks a button, it adds the message to the textbox and performs a callback. Users can also type into the text box, and when the textbox loses focus, it also performs a callback. When the callback is occurring, a modal loading panel appears to stop users from spamming buttons to fast and jumbling the words up in the text box (I'm sure I could handle this better with my jQuery code, but I am pretty new to that, so I am doing the best I can). My main issue is that while a callback is being performed, the User can keep typing the text box, and the new text gets deleted when the callback finishes. My conclusion is that I just wanted to stop all input during the callback, so I was hoping there would be a way to disable all the controls inside of the panel during the callback, and then re-enable them when its done. I know it is possible to hide them, but that is quite the eyesore IMHO.
any ideas?

disable "Close" button when another dialog is on top

I currently have a problem with forms here.
Whenever some process is ongoing, I have a progress dialog that should popup, but when I click the "X" button of the window/form behind my progress dialog, it will be dismissed and the ongoing operation is cancelled.
How can I prevent that from happening? Should I have to disable my whole form behind my progress bar? and how can I do it?
p.s.
I have tried this and this and this but NONE of them seems to work in my application. T__T
Start the form using Form.ShowDialog() instead of Form.Show(). That will disable the background form (actually any other form in the process) until the form you are showing closes. As an added benefit you can have the form return a value (e.g. Cancel, OK, Yes, No, etc.) in case any action needs to be taken as a result.
Not actually the answer you might be expecting, but you could handle the Form.FormClosing event, setting e.Cancel = True
This won't disable the Close button, but will make your form remain open in this case.
See more at: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.formclosing.aspx
You should show the progress bar as modal dialog, please check whether this answer work for you javasript like model window on winform
HTH.

How to create a non-modal form but blocking?

Should sound weird, but this is just for my hobby. I would want a (custom) messagebox to pop up with a YesNo buttons which should ideally block the code. But I should be able to click on the parent form so that I can dismiss the message box without having to specifically click on the messagebox buttons (equivalent to clicking No on the message box)..
something like this:
void Foo()
{
CustomMsgBox.Show("do you really wanna delete?", CustomMsgBox.Buttons.YesNo);
//block the code here, but user should be able to click on form, so that its equivalent to have clicked No;
//if clicked No, return;
//delete.
}
So the solution I thought was make the custom message box non modal - so that user can click on form, but I'm not able to block code.. How can i do that?
It would look like this:
void Foo()
{
NonModalMsgBox.Show("do you really wanna delete?", CustomMsgBox.Buttons.YesNo);
//block thread till user clicks on form or messagebox buttons.
//unblock when user clicks.
//if No, return;
//delete.
}
Edit: I know this is not a standard practice and I know non modal forms do not block, while modal forms do. So please do not recommend to be content with either modal form's or non-modal form's behavior. My question would be is there any way to simulate the behaviour of ContextMenu with windows forms.
You can solve this quite easily. Create and use a modal dialog but override the WndProc of the dialog and process the WM_MOUSEDOWN event. Check the position of the mouse down and if it is over the parent window but not over the dialog itself then simply dismiss the dialog.
Essentially you can't do this in a 'blocking' call easily. What you could do easily enough is to either pass the information required to perform the delete, or a delegate to perform the operation, to the form. When they click Ok you simply perform the operation. If they activate the parent form, then just close the child.
You want the user to be able to click the background window to cancel the dialog box? Add a handler to the background window so that when the user clicks on it you check to see if the non-modal window is displayed, if so close it.
Sounds easy, but you will need to be careful to handle every possible click on the background window and child windows. That sounds like a can of worms I wouldn't want to go down.
Perhaps instead you could detect if the non-modal dialog box loses focus and automatically close it. I can see this behavior making sense for a simple "confirm delete" dialog box, but as a user my first reaction is going to be to spam the ESC key to close the dialog box.
Another way of handling this is by manually enabling the parent form when calling ShowDialog, from here
[DllImport("user32.dll")]
private static extern bool EnableWindow(IntPtr hWnd, bool enable);
internal static DialogResult ShowDialogSpecial(this Form formToBeShown, Form parent)
{
parent.BeginInvoke(new Action(() => EnableWindow(parent.Handle, true)));
formToBeShown.ShowDialog(parent);
return formToBeShown.DialogResult;
}
Just call the extension method from any parent form like this:
var f = new Form();
f.ShowDialogSpecial(this);
//blocks but parent window will be active.
Of course you need to handle the clicks on parent form to close child form.
You could do something like:
public void ShowMe() {
Show();
while (!_receivedDeactivateEvent)
Application.DoEvents();
}
I'm not sure I'd recommend it, though -- I'm not sure how stable it would be, nor am I sure whether it would behave the way you want if you click the Delete button on the parent form while the 'dialog' is up (would it close the first dialog first, or leave it up? might be the latter, which could get messy).
An easier way: set form's "TopMost" property to be True. Then it will act like blocking

C# MDI Parent Gain Focus by clicking on MDI Parent background

I want to set focus to an MDI Parent Form when I click on the background of the form. However, the only way I can get it to set focus is when I resize the form.
I have tried using mouse click event, click event, key press event etc to manually set the focus when you click on the MDI Parent but none of these events fire. Is there ANY way to set the focus to the MDI Parent when you click on the background of the form?
That background is a separate control, try to find it in MainForm.Controls and assign it's click event.
You may want to look at the Win32 WM_MDIACTIVATE message. Now that we've discussed a possible solution, the real question can begin:
I think you should look long and hard at what your trying to accomplish. You risk (not necessarily will, but risk) creating a behavior that is abnormal and confusing to users. Why do you want to move the focus? What will you once it gets moved? How will you indicate to the user that this has been done? How will then get out of this state?

Categories

Resources