I have a button that when pressed gets the status of various windows services on remote PCs. I would like to refresh this button automatically every minute so that the latest status of the services are always shown.
I have tried to set a timer but I keep getting the error "Cross-thread operation not valid: Control 'btnRefreshServices' accessed from a thread other than the thread it was created on"
Any help appreciated
private void btnRefreshServices_Click(
object sender,
EventArgs eventArgs)
{
this.btnRefreshServices.Enabled = false;
// Setting up progress bar in a separate thread to update the progress bar
// This is necessary so that the dialog doesn't freeze while the progress bar is reporting its progress
this.prgbServiceStatus.Minimum = 1;
this.prgbServiceStatus.Maximum = 11;
this.prgbServiceStatus.Step = 1;
this.prgbServiceStatus.Value = 1;
this.prgbServiceStatus.Increment(1);
this.prgbServiceStatus.PerformStep();
var _backgroundWorker = new BackgroundWorker();
_backgroundWorker.ProgressChanged += ProgressChanged;
_backgroundWorker.DoWork += DoWork;
_backgroundWorker.WorkerReportsProgress = true;
_backgroundWorker.RunWorkerAsync();
_backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(RunWorkerCompleted);
}
private void DoWork(
object sender,
DoWorkEventArgs doWorkEventArgs)
{
// Get the current status of each Windows service and reflect the progress in the progress bar
// NOTE: If you add a new service, divide the number of services by 100 and update each call to report progress
((BackgroundWorker)sender).ReportProgress(15);
CurrentStatus(
this.grdResults,
ServerA,
ServiceName,
RowIndexA);
((BackgroundWorker)sender).ReportProgress(25);
CurrentStatus(
this.grdResults,
ServerB,
ServiceNameB,
RowIndexB);
((BackgroundWorker)sender).ReportProgress(35);
}
I was using something like this code for the timer
Timer myTimer = new Timer();
myTimer.Elapsed += new ElapsedEventHandler(DisplayTimeEvent);
myTimer.Interval = 1000; // 1000 ms is one second
myTimer.Start();
public static void DisplayTimeEvent(object source, ElapsedEventArgs e)
{
// code here will run every second
}
Using Emile Pels code I was able to fix my problem.
public frmServicesManager()
{
InitializeComponent();
// The interval in milliseconds (1000 ms = 1 second)
const double interval = 5000.0;
// Create a new timer
new System.Timers.Timer()
{
Enabled = true,
Interval = interval
}.Elapsed += TimerCallback;
}
private void TimerCallback(
object sender,
ElapsedEventArgs elapsedEventArgs)
{
// SignalTime is now of type DateTime and contains the value indicating when the timer's Elapsed event was raised
var _signalTime = elapsedEventArgs.SignalTime;
// Create a new Action
var _setButtonClick = new Action<DateTime>(dateTime => this.btnRefreshServices.PerformClick());
// Check if we can access the control from this thread
if (this.btnRefreshServices.InvokeRequired)
{
// We can't access the label from this thread,so we'll call invoke so it is executed from the thread the it was created on
this.btnRefreshServices.Invoke(_setButtonClick, _signalTime);
}
}