How can I show a modal dialog box without blocking? - c#

I want to show a dialog as modal( i.e. blocks all interaction with all the other ui in my application) But I don't want that call to block execution, how do I do that?
This isn't pretty, but for reasons out of my control, we just have one thread, and can't create more.
currently when we do a time consuming progress, we want to show a progress bar, but in order for it to update while the process is progressing, we have to call DoEvents() (eek).
This unsurprisingly causes a few issues sometimes, but if we could easily disable all ui except the progress bar, that might help.
I got this idea from reading this answer here:
https://stackoverflow.com/a/5183623/259846
Edit:
A modal dialog is simply one that disables all other UI - only the modal dialog can be interacted with. This is separate from whether or not the operation to show this dialog is blocking or not. I don't see any reason why you couldn't in theory have a function that shows a modal dialog box without blocking until the box is closed.
I want to show a progress bar, and I want this progress bar to update as a process progresses, I doesn't matter how I go about doing this, the fact is, that if you want to update one dialog, you have to update the whole UI. As such I want the rest of the UI except for the progress window to be disabled so it can't be interacted with while my process is in progress.
And yes, I can only have one thread, no parallelism.

Disable all other elements manually when opening the DialogBox. Then enable them when closing the box.
for example:
Button.Enabled = false;
Check this out for disabling all controls
How to disable all controls on the form except for a button?
You can also put up a transparent rectangle in front of everything that you can't click through. Then hide it when dialogbox closes.

I've thought of one way of doing it.
My question probably doesn't clearly indicate my use case, this solution still uses the blocking call to create the modal dialog, but still allows me to execute my 'do work, update progress' loop with the dialog open.
var progress = new Form();
this.BeginInvoke(new Action(() =>
{
for (int i = 0; i < 100; i++)
{
System.Threading.Thread.Sleep(16); // do a bit of my process
// Update progress dialog
Application.DoEvents();
}
progress.Close();
}));
progress.ShowDialog();

Related

Can I show a MessageBox but still use the form?

It is possible that when I use:
MessageBox.Show("hello");
..to still use the form but the MessageBox is open like a second window?
because currently, when I show the MessageBox, I need to first click yes or no then I can use my form again.
Yes, you can!
If you simply want to display a MessageBox, don't care what happens with it, and don't want to wait until it's closed, you may launch it on a separate thread. The easiest way to do that would be using Task.Run().
Here's an example:
private void button1_Click(object sender, EventArgs e)
{
Task.Run(() => MessageBox.Show("hello"));
// The remaining code will run without waiting for the MessageBox to be closed.
}
A couple of notes worth mentioning:
Only use this for simple message boxes where you don't care about the result. If you want to act based on the result and execute something (on the main thread), things get a little bit trickier.
You won't be able to keep the MessageBox on top of the form. Once you interact with the form, it will come on top. If you need to keep the MessageBox on top and still have the ability to interact with the form, a custom MessageBox (i.e., form) would be better in that case because you can set the Owner property to keep it on top.
No. The application focus remains on the Message Box until it is dismissed. According to the documentation:
It is a modal window, blocking other actions in the application until the user closes it.
What you can do is create your own form, style it to look like a standard Message Box, and show that form using the .Show() functionality on an instance of it:
var messageBox = new MyCustomMessageBox("hello");
messageBox.Show();
If you want the functionality to be identical in usage, you could even add a static method to your custom form which encapsulates it:
public static void Show(string message)
{
new MyCustomMessageBox(message).Show();
}
Though what I wouldn't recommend doing is calling your custom form MessageBox, that would just be asking for confusion.

How to display message box without any buttons in C#

I try to show a MESSAGE to the user while an operation is executed. The MESSAGE won't show any button. Just a MESSAGE (text) and maybe a background image.
The problem is the following:
MessageBox does not seem to be the good control (because of button and it blocks the running process).
Form.ShowDialog() also blocks the running process. I don't know what to do.
I want to show the message, run my process, and dispose the message when the process is done.
How to achieve this in C# ?
Create a simple form with the message (or expose a public property to be able to change the message, or a constructor with message parameter to pass it in) and show the form using this Show overload. Then disable the (entire) original (owner) form (or just disable the controls you don't want accesible).
So, in your "main" form do this:
Form f = new MessageForm();
f.Show(this); //Make sure we're the owner
this.Enabled = false; //Disable ourselves
//Do processing here
this.Enabled = true; //We're done, enable ourselves
f.Close(); //Dispose message form
Also, consider using a BackgroundWorker.
create custom form, and write own behavior
Create a custom form set it to minimal styles etc. Make sure it knows when the process is complete, say by passing in a reference to the process and checking it every now and then.
One way you could do it is create a worker class that raises an event when it is finished.
execute the worker class in a new thead so it runs it the backgroud.
create the modal form with a method to close it as the event handler for the "finished" event.
This way the ui still works and responds and the form will close once the worker thread is finished.

How to show a dialog form while main app works?

I want to have a loading form showing up while the main app connects to db and fetching initial data. Because this can take up 5-10 secs I want to inform the user that something is happening.
This is what I have come up with:
frmStart _frmStart = new frmStart();
Thread t = new Thread(() => _frmStart.ShowDialog());
t.Start();
objDAL = new DBManager();
objDAL.conSTR = Properties.Settings.Default.conDEFAULT;
PrepareForm();
t.Abort();
Is this the best way?
No, this doesn't solve the frozen UI problem, it merely papers it over. Imperfectly at that, the dialog's parent is the desktop and can easily appear underneath the frozen window and thus not be visible at all. And the dialog isn't modal to the regular windows since it runs on another thread. The failure mode when the user starts clicking on the non-responsive window is very ugly, those clicks all get dispatched when the UI thread comes back alive.
There are workarounds for that (you'd have to pinvoke SetParent and disable the main windows yourself) but that's just solving the wrong problem. You should never let the UI thread block for more than a second. Use a BackgroundWorker to do the heavy lifting, update the form with the query results in the RunWorkerCompleted event handler.
If you are using WinForms you may want to take a look at this A Pretty Good Splash Screen in C#. If you are using WPF you could take a look at this Implement Splash Screen with WPF.

WPF UI - New form to be displayed while progress in original form

I have make a file upload/download functionality where the front end is a WPF UI.
I have figured out that to make my UI not freeze, I need to do the upload/download in a separate thread.
But I also need to show a progress bar while uploading/downloading. I want to do this by showing a new WPF form with a progress bar, and during the upload/download the original form should be made inactive for the user ( user may not click any button etc. ); user can only see the progress bar moving in the new form; upon completion, the new form needs to close and original form becomes active again.
Can someone please help me.
Thanks.
You can implement a simple progress bar. Take this as a start: http://www.codeproject.com/KB/WPF/WpfProgressBar.aspx You can update the progress bar via a callback method from the downloader thread to update the progress every second or so.
First of all, to show a modal Window, all you need to do is
myModalWindow.ShowDialog();
If you use the Show() method, it will just show the window. But if you use the ShowDialog() method, all other windows in your WPF app will not respond to user input until that window closes.
Secondly, you can update a progress bar from another thread by using the UI thread's dispatcher.
Application.Current.Dispatcher.BeginInvoke(() => myProgressBar.Value = progress);

Dialog stops the execution of the code,is any way to stop it in c#?

I am displaying dialog on the main form, now one for loop is working behind but when that dialog will displayed code execution will be stopped, but I don't want to let stop the execution of the code, is any other any way to do that ?
EDIT: I am using now thread to do that and my code is like
Thread t;
private void StartParsingByLoop()
{
t = new Thread(new ThreadStart(RunProgress));
t.Start();
for (int i = 0; i < dialog.FileNames.Length; i++)
{
cNoteToParsed.AllContrctNotesFilePath.Add(dialog.FileNames[i].ToString());
}
cNoteToParsed.ParseContractNote();
if (cNoteToParsed.NOfContrctNoteParsed > 0)
LoadTransactionsInDataGridView();
t.Abort();
}
private void RunProgress()
{
frmProgress progressForImportingTran = new frmProgress("Importing Transactions", "ok");
progressForImportingTran.ShowDialog();
}
Now I have problem is that the dialog that shows the progress does not behave like dialog and gives access of the main form and if we try to access the main form then dialog goes to hide. And I dont want to make the dialog be hide.
You can let a different thread handle the loop.
Response to edit: Can you provide more details, perhaps some code? what is the loop doing? what form do you display?
(this answer is based on the assumption that we are taking about a winforms app)
Show the form using the Show method, rather than ShowDialog. By passing a reference to the main form, the dialog will stay on top of the main form even if it is not modal:
TheDialog dialog = new TheDialog();
dialog.Show(this);
Note though that the user can still interact with the controls on the main form, so you might want to disable some controls, depending on your scenario.
You state in your question that there are requirements that prevent you from using threading for this. This kind of requirement strikes me as odd, and it is a pity because this is one of the typical scenarios when you would want to use some sort of asynchronous construct. By performing heavy work on the UI thread, you get some drawbacks, including:
The UI will not be responsive - if you want to allow the user to cancel the work by clicking a button, that will be tricky to achieve in a robust manner.
The UI will not redraw properly since the UI thread is busy performing other work.
Do not use ShowDialog() but Show() to display the dialog windows. Show() will immediately return to the caller whereas ShowDialog() will hold the execution. Note that when using Show() your dialogs won't be modal anymore.
OK, so you don't need modal dialog, you need a mechanism for your user not to be able to select your main form while processing is enabled.
Modal dialog doesn't mean that execution is stopped - it just happens somewhere else.
There are several methods to do this, and you ruled out new thread creation (don't know why, it would solve it elegantly). If don't use thread, you'll have another problem - your processing should be done in CHUNKS and every little while you'll have to do something like Application.DoEvents() to enable your application to process messages and not be frozen to the user.
So, if you can create a method in the main form that shows your 'please wait' dialog which will perform some work and later do some more until is finished, you can do this:
create a new form (wait dialog)
start a timer inside of it and wire timer to the PARENT form
timer interval should be 1
ShowDialog() the form
on timer event do small amount of work (don't allow it to go more then 1/10 of seconds)
Can you do that?
Anyway:
task can't be split into small workable pieces
you can't use threads
you want your UI to be responsive
PICK 2. You can't have all 3 in Winforms.

Categories