Right now, I'm using a background worker thread to check something every so often and if the conditions are met a messagebox is generated.
I didn't notice for awhile that because I'm calling the messagebox in the background worker I lose the usual messagebox behavior of not letting the user click back on the main form before they click yes/no/cancel on the messagebox.
So, is there some option on the messagebox to keep it in the foreground always? Or is it possible to send a message from the background worker to the main form so I can generate the messagebox from there? Is there another way?
Thanks
Isaac
A background worker is a different thread than your windows form. Therefor you need to let your background worker somehow return information back to the main thread.
In the example below, I use the reportProgress functionality of the backgroundworker, as the event is triggered on the windows form thread.
public partial class Form1 : Form
{
enum states
{
Message1,
Message2
}
BackgroundWorker worker;
public Form1()
{
InitializeComponent();
worker = new BackgroundWorker();
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
worker.WorkerReportsProgress = true;
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
//Fake some work, report progress
worker.ReportProgress(0, states.Message1);
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
states state = (states)e.UserState;
if (state == states.Message1) MessageBox.Show("This should hold the form");
}
private void button1_Click(object sender, EventArgs e)
{
worker.RunWorkerAsync();
}
}
Note: The background worker will NOT halt at reportProgress. If you want your bgworker to wait until the mbox is pressed, you need to make a halt something manually for it.
You can use the Invoke method of the Form1 class to invoke that form's UI thread.
this.Invoke(() => MessageBox.Show("Hi"));
Related
I implemented a windows form in c# with a progress bar in marquee style and a backgroudworker to do a job. The progress bar animation is working correctly when the backgroundworker sleeps, but it hangs when the backgroundworker starts to do something. Does anyone know what I am doing wrong?
Thanks in advance for your answers.
Here is my code:
public FormProgressBarMarquee()
{
InitializeComponent();
this.progressBar1.Style = ProgressBarStyle.Marquee;
this.progressBar1.MarqueeAnimationSpeed = 50;
Shown += new EventHandler(FormProgressBar_Shown);
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_Completed);
}
void FormProgressBar_Shown(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(10000);
// the progress bar animation works correctly
longtimerunningprocess.start();
// the progress bar animation stops
}
void backgroundWorker1_Completed(object sender, RunWorkerCompletedEventArgs e)
{
Debug.Print(" :: FormProgressBar :: ...Pack And Go loaded, close form...");
this.DialogResult = DialogResult.OK;
this.Close();
}
I could finally solve the problem myself. Thanks anyway for the comment #digvijay which put me on the right track.
The program I am writing is part of a class library. longtimerunningprocess is part of the main program and is executed in the main UI thread.
Although I always try to keep the splash screen in the main UI thread and put the non UI work into a separate thread using a backgroundworker, this time I had to put the splash screen in a separate thread.
To do so, I used this suggestion:
https://stackoverflow.com/a/48946
I am trying to make a windows application that start in the system tray as a NotifyIcon and then shows some forms based on events and user input.
I'm using Visual Studio 2013
So what I did is delete the default form VS creates and delete the Application.run() from Program.cs and did Application.run(new MyApplicationContext()) where MyApplicationContext is a class that extends ApplicationContext where I initialize and show the NotifyIcon
Then I made a woker thread that queries a database for information and tries to show that information in a NotificationForm that I created.
If I do something like this in the woker thread code:
NotificationForm form = new form();
form.Top = // change the location;
form.show();
The notification shows in the default position, and any UI element on it appears transparent and I can see-through to desktop
But if I call Application.run(form) in the worker thread the form works right and shows in the right position, but it blocks my worker thread.
If I had a Form I would call Invoke on that Form. But what am I supposed to do in my case?
EDIT: As a workaround I initiated a Form called parentForm in the MyApplicationContext then called show on it then made it invisible. And then I invoke from that. But it seems a dirty work around and not the right one;
BackgroundWorker _backgroundWorker;
private void Init()
{
_backgroundWorker = new BackgroundWorker();
_backgroundWorker.WorkerReportsProgress = true;
_backgroundWorker.ProgressChanged += _backgroundWorker_ProgressChanged;
_backgroundWorker.DoWork += _backgroundWorker_DoWork;
_backgroundWorker.RunWorkerAsync();
}
private void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker backgroundWorker = sender as BackgroundWorker;
Thread.Sleep(5000);
backgroundWorker.ReportProgress(0);
Thread.Sleep(5000);
backgroundWorker.ReportProgress(10);
}
private void _backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Form form = new Form();
form.Text = "Percentage:" + e.ProgressPercentage.ToString();
form.Show();
}
I didn't test it, but it might works like that.
I have an application that when busy will open a busy form (FormWaitingForm) to indicate to the user that the application is busy. How do i close FormWaitingForm in the event backgroundWorker1_RunWorkerCompletedbelow ?
private void radButtonCheckFiles_Click(object sender, EventArgs e)
{
var bw = new BackgroundWorker();
// define the event handlers
bw.DoWork += new DoWorkEventHandler(ProcessTickTemp);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
bw.RunWorkerAsync(); // starts the background worker
// execution continues here in parallel to the background worker
using (var FormWaitingForm = new WaitingForm()) //
{
var result = FormWaitingForm.ShowDialog();
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// How do i close FormWaitingForm here ?
}
You could try something like this. Retain a reference to the form outside of the click method and then open it non-modally (so that you don't have to wait for the user to close it).
WaitingForm formWaitingForm;
private void radButtonCheckFiles_Click(object sender, EventArgs e)
{
// background code here
formWaitingForm = new WaitingForm();
formWaitingForm.Show();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
formWaitingForm.Close();
formWaitingForm.Dispose();
}
You would have to add some code to handle if the user closes the waiting form without waiting for you to do it.
That said, the way I usually implement a waiting/progress-type form is to incorporate the background process into the progress form itself and show something like a progress bar.
This link might give you some more ideas.
I must sleep my main thred 5 times, pausing 10 seconds each time for a certain task.
Problem is that my main windows form freezes during the duration. So, I'd like to show a pop-up window wich is not frozen.
I've added a background worker to my main form:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// ... how do I involve this?
}
When I push a button on my main form it does this:
BussyWindow bussyWindow = new BussyWindow();
bussyWindow.ShowDialog();
And then my main form goes into a loop for about 50 seconds.
I've tried:
BackgroundWorker bw = new BackgroundWorker();
bw.RunWorkerAsync(bussyWindow);
I'm stuck! What to try next?
You don't need another form if you are using BackgroundWorker,try this:
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += bw_DoWork;
bw.RunWorkerAsync();
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
// do your work here
}
Your work will be done asynchronously..
There is a process in the project I wrote. It takes time, and I want to use a progress bar. I want to allow the user to cancel the process and the ProgressBar by clicking a button. I do not want the user to be able to click any other controls on that form when my process is running. If I use a thread, then the user can click other controls on the form.
Perhaps one solution is to use another form, and set the ProgressBar and cancel button on the second form. But how can I set the value of the ProgressBar according my process, which is taking part on the first form.
What's the solution?
Thanks in advance.
This is best done with a dialog, it automatically makes the rest of your UI inaccessible. Add a new form to your project and drop a ProgressBar and a Button on it. And add a public method so you can update the progress bar from the event handler in your main form:
public partial class ProgressDialog : Form {
public ProgressDialog() {
InitializeComponent();
}
public void ShowProgress(int progress) {
progressBar1.Value = progress;
}
private void CancelProcess_Click(object sender, EventArgs e) {
this.DialogResult = DialogResult.Cancel;
}
}
You'll need to display the dialog when you start the worker:
ProgressDialog dlg;
private void RunProcess_Click(object sender, EventArgs e) {
backgroundWorker1.RunWorkerAsync();
using (dlg = new ProgressDialog()) {
dlg.ShowDialog(this);
}
dlg = null;
if (backgroundWorker1.IsBusy) backgroundWorker1.CancelAsync();
}
Note how it calls CancelAsync() to stop the worker so closing the dialog is enough to make it stop. You'll need to update the progress bar:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) {
dlg.ShowProgress(e.ProgressPercentage);
}
And you need to automatically close the dialog when the worker completes and the user hasn't close the dialog herself:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (dlg != null) dlg.Close();
}
Use a BackgroundWorker, this provides an API for reporting progress and cancellation.
Use BackgroundWorker for that. Add it to your first form and on BackgroundWorker progress changed event change progress bars value. Look at example shown in documentation.