Progress bar should restrict the buttons on main window to be clicked - c#

After clicking on a button, I show a progress form and start a task. I want to disable the button or make the progress form a modal so nothing should clickable on the main form, till the progress is completed.
I Tried passing owner reference as an argument when calling the progress bar form's ShowDialog:
m_oProgressBarForm = new ProgressBarForm();
m_oProgressBarForm.ShowDialog(this);
Please help how can I prevent users to click on button again by graying out the main window or making the buttons not clickable or making the progress bar window as the modal?
Currently the user can click the button again and another instance starts which makes the application not usable, and have to manually kill the application using task manager.

If you show a form using ShowDialog() the code following it is not executed until after the dialog box is closed. But you probably need to show progress-bar form and then perform some operations and then close the form, You can not show your progress form as modal.
Instead you can disable your main form and the show your progress form by setting the main form as its parent, then perform the time-consuming task and at last, close the progress form and enable the main form:
private async void Button1_Click(object sender, EventArgs e)
{
var f = new Form(); //Your progress form
f.Show(this);
this.Enabled = false;
try
{
//For example a time-consuming task
await Task.Delay(5000);
}
catch (Exception ex)
{
//Handle probable exceltions
}
f.Close();
this.Enabled = true;
this.BringToFront();
}

Related

C# Modal dialog box (ShowDialog or MessageBox.Show) in async method not works as expected

I have a topmost WinForm with a simple button that executes some commands asynchronously:
private async void button1_Click(object sender, EventArgs e)
{
await System.Threading.Tasks.Task.Run(() =>
{
System.Threading.Thread.Sleep(2000);
//Problem1: not works as "modal" dialog box (Main form remains active!)
new Form().ShowDialog();
//Problem2: not shown as "modal" messagebox (Main form remains active!)
MessageBox.Show("Test");
});
}
Inside the async function are the Messagebox.Show() and ShowDialog() methods, BUT:
Problem 1(solved): The new form does not open as modal dialog box (the main form is still active and accessible!)
Problem 2(solved): The MessageBox.Show() method doesn't behave as modal dialog box (the main form is still active and accessible!).
I need async-await to prevent the main UI from freezing, but I also want messageboxes (and sub-forms) inside to be displayed as modal dialog box. How can i show modal dialog boxes (on the main topmost Form) via async method?
Thanks
Solution for problem-1:
ShowDialogAsync extension method solves the problem.
Solution for problem-2:
private async void button1_Click(object sender, EventArgs e)
{
var handle = this.Handle;
await System.Threading.Tasks.Task.Run(() =>
{
System.Threading.Thread.Sleep(2000);
//Solution for Problem2:
NativeWindow win32Parent = new NativeWindow();
win32Parent.AssignHandle(handle);
//Works as expected (Topmost and Modal):
MessageBox.Show(win32Parent, "Test");
});
}
Related topic
Task.Run() runs work in background thread. In common you shouldn't show windows from background threads, but you can. To solve your problem you need to use UI thread Dispatcher.
Application.Current.Dispatcher.Invoke(() => MessageBox.Show("Test"));
Or
Application.Current.Dispatcher.Invoke(() => new Form().ShowDialog());

Reset Controls for WPF

I began using C# and WPF a few months ago and now I thought I'd try to learn some new techniques like using threading. So I have an app that I want to run all the time (using an infinity while loop) but show the dialog (main window) every minute. So I am doing this by using Threading and here is how i am doing this:
public MainWindow()
{
InitializeComponent();
while (true)
{
callmyfunction()
system.Threading.Thread.Sleep(1000);
}
}
In my callmyfunction(), I am calling the dialog (which is the main WPF application) so it will show. Here's how i am doing it:
public void callmyfunction()
{
this.ShowDialog();
}
I have a regular button and when you click on it, it should hide the main window. So my button function is like this:
private void Button_Click2(object sender, RoutedEventArgs e)
{
this.Hide();
}
So what I am doing is, I am loading the main window normally and it has a button, when I click on that button, it should hide the main window and the window should sleep as per the milli-seconds I specified in thread.sleep and then it will wake up, then again the dialog will appearand it will show the button and so on and so forth. This loop is working fine with me, but the issue I am having is that after the first dialog appears and I click on the button to hide the main window, the second time the main window appears, the button would appear as a "pressed" button, not as a new button. I think it's because I "pressed" on it the first time the main window appeared. And it stays like that until I stop the program and run it again.
So my question is, any idea how I can "reset" the button control? Or do I need to reset the mouse click event? Any pointers on this would be helpful.
You should run the loop on a background thread. If you run it on the UI thread, the application won't be able to respond to user input.
The easiest and recommended way to run some code on a background thread is to start a new Task.
Also note that you cannot access the window from a background thread so you need to use the dispatcher to marshal the call back to the UI thread.
The following sample code should give you the idea.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Task.Factory.StartNew(() =>
{
while (true)
{
Dispatcher.Invoke(() => callmyfunction());
System.Threading.Thread.Sleep(5000);
}
}, TaskCreationOptions.LongRunning);
}
public void callmyfunction()
{
WindowState = WindowState.Normal;
}
private void Button_Click2(object sender, RoutedEventArgs e)
{
WindowState = WindowState.Minimized;
}
}

C# - How to cancel background working from form with a progress bar?

I'm trying to figure out how I can cancel a backgroundwoker with the following situation:
On one Winform, I have a backgroundworker that I call that basically retrieves a ton of data from a service. This operation can take anywhere from 1 second to 5 minutes. So, what I did was I created another Winform and stuck a marquee progress bar on it.
What I'm wanting to do is to add a Cancel button to that Winform with the progress bar on it that would cancel that backgroundworker.
My current code is setup as:
this.backgroundWorker1.RunWorkerAsync();
pb = new frmProgressbar();
pb.Show();
while (this.backgroundWorker1.IsBusy)
{
Application.DoEvents();
}
pb.Dispose();
So, this works fine as it displays the progressbar while the backgroundworker is chugging along, and disposes of the progressbar form afterwards.
But, I need to figure out a way to allow the user to cancel the operation by placing a Cancel button on frmProgressbar that will return a cancel to kill the backgroundworker. Any suggestions?
Start out by adding an event to the progress bar form to indicate when cancellation occurs and then fire it when the relevant button is clicked:
public class frmProgressbar : Form
{
public event Action Canceled;
void btnCancel_Click(object sender, EventArgs e)
{
if (Canceled != null)
Canceled();
}
//other stuff
}
Then in your other form you can create a new progress bar, have it cancel the background worker (which has its own cancellation support built in) and then show it. You can also add a handler to the completed event to close the progress bar (rather than trying to wait on the BGW). Then start the worker.
You'll also need to check for cancellation from throughout your DoWork handler so that you can stop doing your work in the event that cancellation is requested:
var pb = new frmProgressbar();
pb.Canceled += ()=> backgroundWorker1.CancelAsync();
pb.Show();
backgroundWorker1.RunWorkerCompleted += (s, args) => pb.Close();
backgroundWorker1.RunWorkerAsync();

How to show a WinForms Modal Dialog from a WPF App Thread

I have a WPF application. The main window of this application has a button. I am opening a WinForms modal dialog in a separate thread when this button is clicked. The trouble I am having is that the dialog does not behave like a modal i.e it is still possible to switch focus to the main window, whereas, I require to allow focus on the newly opened dialog and it should not be possible to select the main window.
Note: I cannot move the modalDialog.ShowDialog(); outside of the delegate because the dialog form creates controls dynamically and this means that these controls must remain on the thread that it was created. To be more clear, if I move the modalDialog.ShowDialog(); outside I will get an exception like so:
Cross-thread operation not vaild: Control 'DynamicList' accessed from a thread other than the one it was created on.
Any ideas as to how I might make the form behave as a modal?
Here is the code:
private void button1_Click(object sender, RoutedEventArgs e)
{
DoSomeAsyncWork();
}
private void DoSomeAsyncWork()
{
var modalDialog = new TestForm();
var backgroundThread = new Thread((
delegate()
{
// Call intensive method that creates dynamic controls
modalDialog.DoSomeLongWaitingCall();
modalDialog.ShowDialog();
}
));
backgroundThread.Start();
}
You should always create controls on the UI thread. If you do that, calling ShowDialog() through Dispatcher should work.

f2.show() method does not show the progress bar in form2

I have an application that has 2 forms. First one is where I do all the job and second one is just for displaying a progressbar.
I want to open the second one from the main form. if I use
Form2 newForm = new Form2();
newForm.Show();
Form2 opens and closes when it needs to open and close, but I cannot see the progress bar. I just can see a blank instead of it.
When I use
Form2 newForm = new Form2();
newForm.ShowDialog();
I can see the progressbar but Form2 doesn't close when it needs. It runs forever, what should I do?
I use a static public variable closeForm to close the second form. When I need to close the form I set
closeForm = true;
and in the second form, I have a timer
private void timer1_Tick(object sender, EventArgs e)
{
if (Form1.closeForm)
{
this.Dispose();
this.Close();
return;
}
else
{
progVal++;
progressBar1.Value = (progVal % 100);
}
}
this is where I put the ProgressBar value and close the form.
When I use show method, I only see blanks instead of the controls in form2. not just the progressbar, and I want form1 to close form2
first of all you need to report progress to progressbar
int iProgressPercentage = (int)(dProgressPercentage * 100);
// update the progress bar
progressBar1.ReportProgress(iProgressPercentage);
try doing that first then call this.close();
As I said above in the comment, you need to check Modal dialog from here Form.ShowDialog Method, and I just quote the following form there:
You can use this method to display a modal dialog box in your application. When this method is called, the code following it is not executed until after the dialog box is closed.
As why you can't see your ProgressBar on Form2 with Show(); you need to provide more information of how you handles it, as if I separate your program into two parts and use two button click to run them (Click button1 to show Form2; and click button2 to close it) I can see your expected result: the progressbar.
Without your further information, my best guess is something running prevents the Form2 to update its GUI.

Categories