I've looked in many places for this but still haven't found a solution. What I'm trying to achieve is being able to use BackgroundWorker on a timed basis. Here's an example:
public Main()
{
isDbAvail = new BackgroundWorker();
isDbAvail.DoWork += isOnline;
isDbAvail.RunWorkerCompleted += rewriteOnlineStatus;
}
private void rewriteOnlineStatus(object sender, RunWorkerCompletedEventArgs e)
{
Subs.Connection connection = new Subs.Connection();
changeStatus(connection.isDbAvail());
}
private void isOnline(object sender, DoWorkEventArgs e)
{
while (true)
{
Console.WriteLine("Checking database connection");
System.Threading.Thread.Sleep(8000);
}
}
public void changeStatus(bool status)
{
if (status)
{
serverStatusVal.Text = "Connected";
serverStatusVal.ForeColor = System.Drawing.Color.DarkGreen;
}
else
{
serverStatusVal.Text = "Not connected";
serverStatusVal.ForeColor = System.Drawing.Color.Red;
}
}
What's happening here is that the isOnline method checks if there is a connection to the database (just an example) every 8 seconds and changes the text accordingly. What I've noticed though, is that the while loop inside the isOnline method causes the rewriteOnlineStatus method never to fire because it runs indefinitely. Is there another workaround to this?
I suggest you use BackgroundWorker.ReportProgress, and check connectivity in the background thread.
Something like this:
public Main()
{
isDbAvail = new BackgroundWorker();
isDbAvail.WorkerReportsProgress = true;
isDbAvail.DoWork += isOnline;
isDbAvail.ProgressChanged += rewriteOnlineStatus;
isDbAvail.RunWorkerAsync();
}
private void rewriteOnlineStatus(object sender, ProgressChangedEventArgs e)
{
changeStatus((bool)e.UserState);
}
private void isOnline(object sender, DoWorkEventArgs e)
{
while (true)
{
Console.WriteLine("Checking database connection");
Subs.Connection connection = new Subs.Connection();
isDbAvail.ReportProgress(0, connection.isDbAvail);
System.Threading.Thread.Sleep(8000);
}
}
Now the BackgroundWorker is doing the work, and reporting back to the UI thread via ProgressChanged.
Related
Unfortunately I was not able to find relevant answer to my problem. I have a object encoder that has an event "VideoEncoding". It passes custom EncodingEventArgs that include various Properties like Progress, Size etc. I can output this info to Console or write to text file. But when I try to utilize it in WinForms I'm not able to pass that information to UI like label or progress bar. I tried different approaches. Background Worker seems like a good idea, The problem is that Background Worker cannot subscribe to VideoEncoding event, neither it will take my custom EventArgs. This is what i was able to put together. Maybe there is a different way to do it using delegates that would communicate with UI. Any suggestions are welcome. Thank you.
public partial class Form1 : Form
{
private BackgroundWorker bw;
int _progress;
public Form1()
{
InitializeComponent();
this.bw = new BackgroundWorker();
this.bw.DoWork += new DoWorkEventHandler(bw_DoWork);
this.bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
this.bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
this.bw.WorkerReportsProgress = true;
this.button1.Click += new EventHandler(button1_Click);
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.label1.Text = "The job is: " + e.Result.ToString();
this.button1.Enabled = true;
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.label2.Text = e.ProgressPercentage.ToString() + "% complete";
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker)sender;
this.Encode
worker.ReportProgress(_progress);
e.Result = "Completed";
}
private void button1_Click(object sender, EventArgs e)
{
if (!this.bw.IsBusy)
{
this.bw.RunWorkerAsync();
this.button1.Enabled = false;
}
}
public void Encode()
{
var job = new EncodingJob();
//setup encoding job
//subscribe to an event
ffmpeg.VideoEncoding += GetProgress;
ffmpeg.DoWork(job);
}
public void GetProgress(object sender, EncodingEventArgs e)
{
_progress = (int)e.Progress;
}
}
Try to call the background workers ReportProgress in the GetProgress Method. How should the form know your progress if you don't signalize it?
I have a method in my class that has some loops inside.
Main purpose of this method is converting some files so I put a progressbar in my form that should get updated after each file has been converted.
I tried every possible combination and I read everything I could but I couldn't solve this issue.
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
converterProgressBar.Value = e.ProgressPercentage;
}
is called only after the main loop of my method has been executed.
This is my method:
public string Convert()
{
convertBtn.Enabled = false;
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
totalCount = files.length;
bw.RunWorkerAsync();
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
foreach (string file in files)
{
countFile++;
if (chk.Checked)
{
class1.DoJob();
}
using (// some code))
{
using (//some other code))
{
try
{
using (// again some code)
{
// job executing
}
}
catch (exception
{
}
}
}
convertedVideosL.Text = txtToUpdate;
convertedVideosL.Refresh();
}
countFile = countFile + 1;
MessageBox.Show("Done");
countFile = -1;
return outputFile;
}
And here are the BackgroundWorker Event Handlers:
void bw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i <= totalCount; i++)
{
if (bw.CancellationPending)
{
e.Cancel = true;
}
else
{
int progress = Convert.ToInt32(i * 100 / totalCount);
(sender as BackgroundWorker).ReportProgress(progress, i);
}
}
}
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
converterProgressBar.Value = e.ProgressPercentage;
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == false)
{
convertedVideosL.Text = "Finished!";
}
else
{
convertedVideosL.Text = "Operation has been cancelled!";
}
}
But I cannot get to update the progress bar for every file that is converted.
It waits for the foreach loop to end and then calls bw_ProgressChanged.
If I put RunWorkerAsync() inside the foreach loop an exception is thrown that says the BackgroundWorker is busy and cannot execute other tasks.
It seems to me obvious that DoWork() only executes a for loop then it shouldn't be aware of the conversion going on but ProgressChanged should be fired by ReportProgress(progress,i).
Could please someone explain me why and help me with a solution?
Thanks!
Currently the conversion is not executed by the instance of the BackgroundWorker type. The conversion should be called from the DoWork event handler.
Please consider extracting the conversion-related functionality:
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
foreach (string file in files)
{
// Details...
}
into the separate method. After that just call the method from the DoWork event handler.
Pseudo-code to demonstrate the idea:
public void StartConversion()
{
...
TWorkerArgument workerArgument = ...;
worker.RunWorkerAsync(workerArgument);
// No message box here because of asynchronous execution (please see below).
}
private void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
// Get the BackgroundWorker that raised this event.
BackgroundWorker worker = sender as BackgroundWorker;
e.Result = Convert(worker, (TWorkerArgument)e.Argument);
}
private static TWorkerResult Convert(BackgroundWorker worker, TWorkerArgument workerArgument)
{
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
foreach (string file in files)
{
// Details...
worker.ReportProgress(percentComplete);
}
return ...;
}
private void BackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Show the message box here if required.
}
Please replace the TWorkerArgument and TWorkerResult types appropriately.
Also, please refer to the example which uses the BackgroundWorker class for the additional details: How to: Implement a Form That Uses a Background Operation, MSDN.
I have a class SendCountingInfo() and it will send a message to server every 5 minutes. The code inside this class are:
public void StartSendCountingInfo()
{
DoStartSendCountingInfo(300000);
}
private void DoStartSendCountingInfo(int iMiSecs)
{
_pingTimer = new System.Timers.Timer(iMiSecs);
_pingTimer.Elapsed += new System.Timers.ElapsedEventHandler(pingTimer_Elapsed);
_pingTimer.Start();
}
void pingTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
PingRemoteHost();
}
When I try to call it in the Windows Form class, it didn't work.
But, when I remove the timer and call PingRemoteHost() directly, it works. However, the form didn't load properly. It shows blank screen but the method PingRemoteHost() work.
Here is the code inside the windows form:
private void Layout_Load(object sender, EventArgs e)
{
tSystemChecker = new System.Timers.Timer(1000);
tSystemChecker.Elapsed += new System.Timers.ElapsedEventHandler(tSystemChecker_Elapsed);
tSystemChecker.Start();
this.WindowState = FormWindowState.Maximized;
}
void tSystemChecker_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
UIThreadWork(this, delegate
{
try
{
SuspendLayout();
DoCheckHardwareStatus();
DoCheckLanguage();
SendCountingInfo sci = new SendCountingInfo();
sci.StartSendCountingInfo();
}
catch (Exception exp)
{
System.Diagnostics.Debug.WriteLine(exp.Message);
System.Diagnostics.Debug.WriteLine(exp.Source);
System.Diagnostics.Debug.WriteLine(exp.StackTrace);
}
ResumeLayout(true);
});
}
Do you have any idea what's wrong?
Use a thread and see if the problem persist
using System.Threading;
//Put this where you want to start the first timer
Thread thread = new Thread(dowork =>
{
public void StartSendCountingInfo();
}
If you are updating the GUI use for your controls
guicontrol.BeginInvoke((MethodInvoker)delegate()
{
guicontrol.Text = "aa";
//etc
});
I have a C# winform application which needs to run multiple instance in synchronous way. The goal is to:
If the exe runs 3 times, it runs the first instance of the exe and the rest will wait until the first instance finishes the processing. Then, a next waiting exe intance will run and process and so on.
The exe will run one by one until it finish processing then the exe will terminates automatically af.
Any idea how to do this?
I already tried below:
private void CheckInstance()
{
bool _returnValue = true;
string _lockFile = string.Empty;
Random _rnd = new Random();
int _randomValue = _rnd.Next(100, 200);
int _rndmiliSec = 0;
_rndmiliSec = DateTime.Now.Millisecond * _rnd.Next(2, 6);
_lockFile = string.Concat(AppDomain.CurrentDomain.BaseDirectory, string.Format("/{0}", instanceFileName));
while (_returnValue)
{
_returnValue = File.Exists(_lockFile);
if (_returnValue)
{
Thread.Sleep(1000);
this.Hide();
}
else
{
try
{
Thread.Sleep((_rnd.Next(1000) + _rndmiliSec) + _rnd.Next(1000, 1500));
Functions.WriteLog(_lockFile, "Starting the process...");
Functions.WriteLog(_lockFile, string.Format("Start Time : {0}", paramPrintTime));
File.SetAttributes(_lockFile, FileAttributes.ReadOnly);
this.Show();
break;
}
catch (Exception)
{
_returnValue = false;
}
}
}
}
private void DeleteInstance()
{
try
{
File.SetAttributes(string.Concat(AppDomain.CurrentDomain.BaseDirectory, string.Format("/{0}", instanceFileName)), FileAttributes.Normal);
File.Delete(string.Concat(AppDomain.CurrentDomain.BaseDirectory, string.Format("/{0}", instanceFileName)));
}
catch (Exception)
{
}
}
private void Form_Shown(Object sender, EventArgs e)
{
_backWorker.RunWorkerAsync();
}
private void FormClosed(object sender, FormClosedEventArgs e)
{
DeleteInstance();
}
private void Form_Load(object sender, System.EventArgs e)
{
CheckInstance();
}
BackgroundWorker _backWorker = new BackgroundWorker();
public Form()
{
InitializeComponent();
_backWorker.WorkerReportsProgress = true;
_backWorker.ProgressChanged += _backWorker_ProgressChanged;
_backWorker.RunWorkerCompleted += _backWorker_RunWorkerCompleted;
_backWorker.DoWork += _backWorker_DoWork;
}
private void _backWorker_DoWork(object sender, DoWorkEventArgs e)
{
Do some work processing...
}
private void _backWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Close();
}
private void _backWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pg.Value = e.ProgressPercentage;
lblIndicator.Text = e.UserState.ToString();
}
When the exe run 3 instance, the first instance will run while 2nd and third hides for a while awaiting the 1st instance to be finisih. However, after the 1st instance finish the process, The 2nd and 3rd instance are running simultaneously.
Any Ideas? Thanks.
Maybe this can work:
public static bool IsProgramRunning(string TitleOfYourForm)
{
bool result = false;
Process[] processes = Process.GetProcesses();
foreach (Process p in processes)
{
if (p.MainWindowTitle.Contains(TitleOfYourForm))
{
result = true;
break;
}
}
return result;
}
Call this function in the Main function(before opening the mainForm), if it is false Application.Exit() else show your form..
If this answer helped you, vote me.
This case is using C# WPF. I want to instantly disable a button after clicking it to prevent clicking it twice in short succession. I disabled the button in OnClick_Event but still clickable.
Part of source is as below.
private void Button_Click_UpdateBurndownChart(object sender, RoutedEventArgs e)
{
if(threadNotWorking)
{
updateButton.IsEnabled = false;
startWorkThread();
}
}
private void startWorkThread()
{
... ...
//after finish required process
updateButton.IsEnabled = true;
}
Is there any way to accomplish this?
you may want to use a dispatcher, there is probably a threading problem (callback function running on seperate thread and trying to access ui which runs on another thread). try this . .
updateButton.Dispatcher.BeginInvoke(
new ThreadStart(() => updateButton.IsEnabled = false),
System.Windows.Threading.DispatcherPriority.Input, null);
instead of
updateButton.IsEnabled = false;
What happens if you were instead to change the order of your events from:
updateButton.IsEnabled = false;
startWorkThread();
To
startWorkThread();
updateButton.IsEnabled = false;
Let me know how this goes.
What it looks like is that you are starting your thread then immediatly enabling your button before your thread has finished. You would be better off using a BackgroundWorker and enable your Button in the RunWorkerCompleted Event. Though you can do something similar by enabling your button using a BeginInvoke at the end of your Process.
public void doWork()
{
System.Threading.Thread.Sleep(10000); //Simulating your Process
Dispatcher.BeginInvoke(new System.Threading.ThreadStart(delegate() { updateButton.IsEnabled = true; }), System.Windows.Threading.DispatcherPriority.Background);
}
Example with BackgroundWorker
using System.ComponentModel;
public partial class MainWindow : Window
{
BackgroundWorker bgw;
public MainWindow()
{
InitializeComponent();
bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
updateButton.IsEnabled = true;
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(10000); //Simulating your work
}
private void startWorkThread()
{
bgw.RunWorkerAsync();
}
private void updateButton_Click(object sender, RoutedEventArgs e)
{
if (bgw.IsBusy != true)
{
updateButton.IsEnabled = false;
startWorkThread();
}
}
}