SQLDependency thread - c#

i am in the process implementing SQLdepenency i would like to know in case of Dependency Handler exeuctues will it spun a different thred from main Process ? What will happen when the event handler triggers? Do i need to worry about any multithreds issues?
public void CreateSqlDependency()
{
try
{
using (SqlConnection connection = (SqlConnection)DBFactory.GetDBFactoryConnection(Constants.SQL_PROVIDER_NAME))
{
SqlCommand command = (SqlCommand)DBFactory.GetCommand(Constants.SQL_PROVIDER_NAME);
command.CommandText = watchQuery;
command.CommandType = CommandType.Text;
SqlDependency dependency = new SqlDependency(command);
//Create the callback object
dependency.OnChange += new OnChangeEventHandler(this.QueueChangeNotificationHandler);
SqlDependency.Start(connectionString);
DataTable dataTable = DBFactory.ExecuteSPReDT(command);
}
}
catch (SqlException sqlExp)
{
throw sqlExp;
}
catch (Exception ex)
{
throw ex;
}
}
public void QueueChangeNotificationHandler(object caller, SqlNotificationEventArgs e)
{
if(e.Info == SqlNotificationInfo.Insert)
Fire();
}

It works in a separate thread, but there is only one such thread for all notifications. Have a look at the SQLDependency section in this article

SqlDependency documentation on MSDN mention about possibility that the OnChange event may be generated on a different thread from the thread that initiated command execution.
You should read Detecting Changes with SqlDependency (ADO.NET) article from MSDN which explain similar scenario.

It will spawn a new worker thread to wait for the dependency notifications--but that's what you want (otherwise your main program loop would be held up waiting for something that may never happen!).
The example code at this page shows to how avoid issues where the worker thread that gets the dependency/query notifications doesn't have the right to update the UI; their method passes the task to the UI thread so it will succeed (see step #12).

It does spawn in a different thread!! You can create a simple Windows Application to test this, and you'll see how the OnChange handler can't modify any UI controls directly (you'd get something like "Cross-thread operation not valid: Control XXX accessed from a thread other than the thread it was created on"). To overcome this, you call BeginInvoke.
Here's a simple Windows application to test SqlDependencies (I hope you can imagine the UI).
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Linq;
using System.Data.Linq.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
namespace TestSqlDependancies
{
public partial class SqlDependencyTester : Form
{
SqlDependency sqlDepenency = null;
SqlCommand command;
SqlNotificationEventArgs msg;
public Form1()
{
InitializeComponent();
}
private void label1_Click(object sender, EventArgs e)
{
}
public delegate void InvokeDelegate();
void sqlDepenency_OnChange(object sender, SqlNotificationEventArgs e)
{
msg = e;
this.BeginInvoke(new InvokeDelegate(Notify));
}
private void Notify()
{
listBox1.Items.Add(DateTime.Now.ToString("HH:mm:ss:fff") + " - Notfication received. SqlDependency " + (sqlDepenency.HasChanges ? " has changes." : " reports no change. ") + msg.Type.ToString() + "-" + msg.Info.ToString());
}
private void button1_Click(object sender, EventArgs e)
{
SetDependency();
}
private void SetDependency()
{
try
{
using (TicketDataContext dc = new TicketDataContext())
{
SqlDependency.Start(dc.Connection.ConnectionString);
command = new SqlCommand(textBox1.Text, (SqlConnection)dc.Connection);
sqlDepenency = new SqlDependency(command);
sqlDepenency.OnChange += new OnChangeEventHandler(sqlDepenency_OnChange);
command.Connection.Open();
command.ExecuteReader();
}
}
catch (Exception e)
{
listBox1.Items.Add(DateTime.Now.ToString("HH:mm:ss:fff") + e.Message);
}
}
}
}

Related

Async Ping PingComplete only in Console firing [duplicate]

I am trying to write an application the is constantly searching for host on a lan. When I run this as a console as the countdown.Wait() seems to work fine. However when I bring the code into a windows form the countdown.Signal() does not seem to decrement its counter. Not sure what the problem is.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.NetworkInformation;
using System.Diagnostics;
using System.Net;
using System.Threading;
namespace Multi_Threaded
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
PortScanner ps = new PortScanner();
ps.ProbeCompleted += new PingProbeCompleted(ps_ProbeCompleted);
ps.run_ping_probe();
}
void ps_ProbeCompleted(object sender, PingProbeCompletedArguments e)
{
MessageBox.Show("I found " + e.ip_adresses_list_of_host.Count.ToString() + "host(s)");
}
}
public delegate void PingProbeCompleted(object sender,PingProbeCompletedArguments e);
public class PingProbeCompletedArguments : EventArgs
{
public List<string> ip_adresses_list_of_host;
}
public class PortScanner
{
public event PingProbeCompleted ProbeCompleted;
static List<string> ip_adresses = new List<string>();
static CountdownEvent countdown;
public void run_ping_probe()
{
ip_adresses.Clear();
countdown = new CountdownEvent(1);
string ipBase = "10.125.";
for (int sub = 0; sub < 14; sub++)
{
for (int i = 1; i < 255; i++)
{
string ip = ipBase + sub.ToString() + "." + i.ToString();
Ping p = new Ping();
p.PingCompleted += new PingCompletedEventHandler(p_PingCompleted);
countdown.AddCount();
p.SendAsync(ip, 100, ip);
}
}
countdown.Signal();
countdown.Wait();
PingProbeCompletedArguments e = new PingProbeCompletedArguments();
e.ip_adresses_list_of_host = ip_adresses;
ProbeCompleted(this, e);
}
private void p_PingCompleted(object sender, PingCompletedEventArgs e)
{
string ip = (string)e.UserState;
if (e.Reply.Status == IPStatus.Success)
{
ip_adresses.Add(ip + "\t" + e.Reply.RoundtripTime + " ms");
}
countdown.Signal();
}
}
Yes, your code deadlocks when you use it in a Winforms project. The problem is that the Ping class makes a best effort to raise the PingCompleted event on the same thread that called SendAsync(). It uses the AsyncOperationManager.CreateOperation() method to do so.
Problem is, that actually works in a Winforms app. It tries to raise the event on the main thread. But that cannot work since you blocked the main thread with the countdown.Wait() call. The ping cannot complete since the main thread is blocked. The main thread cannot complete since the ping doesn't complete. Deadlock city.
It works in a Console mode app since it doesn't have a synchronization provider like Winforms does. The PingComplete event will be raised on a threadpool thread.
Blocking the UI thread is fundamentally flawed. The quick fix is to run the code on a worker thread. Beware that this makes the ProbeCompleted event fired on that worker as well. Use Control.BeginInvoke() to marshal it to the UI thread. Or use BackgroundWorker.
private void Form1_Load(object sender, EventArgs e) {
PortScanner ps = new PortScanner();
ps.ProbeCompleted += new PingProbeCompleted(ps_ProbeCompleted);
ThreadPool.QueueUserWorkItem((w) => ps.run_ping_probe());
}
And don't forget to remove the extra Signal() call.
your wait handler is run under a thread from the threadpool.
you need to get back into the UI thread to have the UI updated (due to the message loop that the UI runs on) - for that you use SynchronizationContext
Here more info on how to you it:
http://www.codeproject.com/KB/threads/SynchronizationContext.aspx

C# thread on forms [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to update GUI from another thread in C#?
I've currently got a C# program to run a query and display the results in a datagridview.
The query due to size of records takes a while (20-30 seconds) to run.
I thought I would add an animation so the user at least knows the software is running and has not stopped working.
Of course I can't run anything when the call is being made to the procedure so I looked into threading.
Here is my code (forgive me, I haven't really put in comments yet):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Threading;
namespace RepSalesNetAnalysis
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
pictureBox2.Visible = false;
}
private void button1_Click(object sender, EventArgs e)
{
GetsalesFigures();
}
private void Form1_Load(object sender, EventArgs e)
{
AutofillAccounts();
}
private void GetsalesFigures()
{
try
{
string myConn = "Server=herp;" +
"Database=shaftdata;" +
"uid=fake;" +
"pwd=faker;" +
"Connect Timeout=120;";
string acct;// test using 1560
SqlConnection conn = new SqlConnection(myConn);
SqlCommand Pareto = new SqlCommand();
BindingSource bindme = new BindingSource();
SqlDataAdapter adapt1 = new SqlDataAdapter(Pareto);
DataSet dataSet1 = new DataSet();
DataTable table1 = new DataTable();
Thread aniSql = new Thread(new ThreadStart(animateIcon));//CREATE THE THREAD
acct = accCollection.Text;
string fromDate = this.dateTimePicker1.Value.ToString("MM/dd/yyyy");
string tooDate = this.dateTimePicker2.Value.ToString("MM/dd/yyyy");
Pareto.Connection = conn;
Pareto.CommandType = CommandType.StoredProcedure;
Pareto.CommandText = "dbo.GetSalesParetotemp";
Pareto.CommandTimeout = 120;
Pareto.Parameters.AddWithValue("#acct", acct);
Pareto.Parameters.AddWithValue("#from", fromDate);
Pareto.Parameters.AddWithValue("#too", tooDate);
aniSql.Start(); //START THE THREAD!
adapt1.Fill(dataSet1, "Pareto");
aniSql.Abort(); //KILL THE THREAD!
//pictureBox2.Visible = false;
this.dataGridView1.AutoGenerateColumns = true;
this.dataGridView1.DataSource = dataSet1;
this.dataGridView1.DataMember = "Pareto";
dataGridView1.AutoResizeColumns(
DataGridViewAutoSizeColumnsMode.AllCells);
}
catch (Exception execc)
{
MessageBox.Show("Whoops! Seems we couldnt connect to the server!"
+ " information:\n\n" + execc.Message + execc.StackTrace,
"Fatal Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
}
private void AutofillAccounts()
{
//get customers list and fill combo box on form load.
try
{
string myConn1 = "Server=derp;" +
"Database=AutoPart;" +
"uid=fake;" +
"pwd=faker;" +
"Connect Timeout=6000;";
SqlConnection conn1 = new SqlConnection(myConn1);
conn1.Open();
SqlCommand accountFill = new SqlCommand("SELECT keycode FROM dbo.Customer", conn1);
SqlDataReader readacc = accountFill.ExecuteReader();
while (readacc.Read())
{
this.accCollection.Items.Add(readacc.GetString(0).ToString());
}
conn1.Close();
}
catch(Exception exc1)
{
MessageBox.Show("Whoops! Seems we couldnt connect to the server!"
+ " information:\n\n" + exc1.Message + exc1.StackTrace,
"Fatal Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
}
public void animateIcon()
{
// animate
pictureBox2.Visible = true;
}
}
}
As you can see I want to run the animation just before the procedure call and then end it just after.
My knowledge on threads is brand new. I've looked around but i'm getting a little confused at the moment.
Here's my error:
Thrown: "Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on." (System.InvalidOperationException) Exception Message = "Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on.", Exception Type = "System.InvalidOperationException"
I need a very simple way of performing an animation while my sql proc is reading.
Something like picture.visible = true when its started and false when it ends.
Invoke is needed if you want to do this.
private delegate void InvokeDelegate();
public void DoSomething()
{
if (InvokeRequired)
{
Invoke(new InvokeDelegate(DoSomething));
return;
}
// dosomething
}
you can also add variables to the delegate and use them:
private delegate void InvokeDelegate(string text);
public void DoSomething(string text)
{
if (InvokeRequired)
{
Invoke(new InvokeDelegate(DoSomething), text);
return;
}
// dosomething with text
}
hope this helps :).
stefan
As others have pointed out, you cannot perform UI-related operations on a separate thread.
If you want your application to be responsive, you should perform the data operation on a separate thread instead.
If you just want to show the PictureBox control, you don't need the extra thread at all:
pictureBox2.Visible = true;
pictureBox2.Refresh(); // <-- causes the control to be drawn immediately
...large operation...
pictureBox2.Visible = false;
However if the user for instance alt-tabs back and forth, or drags another window over yours, the application would seem to hang as the UI thread is busy performing the data operation.
I'm suprised that so many people advise you to keep your current code and use InvokeRequired and Invoke, even though Invoke will only execute when the UI thread has time to process it (AFTER the data operation).
You need to use InvokeRequired to access/modify a control from a thread other than the main thread of your form. Documentation here: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx
Have you tried with Tasks???
I make a simple test to show how I would make something similar (in WPF):
The XAML:
<Window x:Class="TaskLoading.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="90,33,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
<Image Height="118" HorizontalAlignment="Left" Margin="90,80,0,0" Name="imgLoading" Stretch="Fill" VerticalAlignment="Top" Width="122" Visibility="Hidden" Source="/TaskLoading;component/loader_big.gif" />
</Grid>
</Window>
The code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;
using System.Threading.Tasks;
namespace TaskLoading
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void bigProcess(){
Thread.Sleep(5000);
}
private void button1_Click(object sender, RoutedEventArgs e)
{
imgLoading.Visibility = Visibility.Visible; //Make the icon visible.
/* Start the bigProcess in a background thread: */
Task changeIcon = Task.Factory.StartNew(() =>
{
bigProcess();
});
/* At the end of the process make invisible the icon */
changeIcon.ContinueWith((r) =>
{
imgLoading.Visibility = Visibility.Hidden;
},
TaskScheduler.FromCurrentSynchronizationContext()
);
}
}
}
public void animateIcon()
{
Action action=()=>pictureBox2.Visible = true;
// animate
this.Invoke(action);
}

Asynchronous code that works in Console but not in Windows Forms

I am trying to write an application the is constantly searching for host on a lan. When I run this as a console as the countdown.Wait() seems to work fine. However when I bring the code into a windows form the countdown.Signal() does not seem to decrement its counter. Not sure what the problem is.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.NetworkInformation;
using System.Diagnostics;
using System.Net;
using System.Threading;
namespace Multi_Threaded
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
PortScanner ps = new PortScanner();
ps.ProbeCompleted += new PingProbeCompleted(ps_ProbeCompleted);
ps.run_ping_probe();
}
void ps_ProbeCompleted(object sender, PingProbeCompletedArguments e)
{
MessageBox.Show("I found " + e.ip_adresses_list_of_host.Count.ToString() + "host(s)");
}
}
public delegate void PingProbeCompleted(object sender,PingProbeCompletedArguments e);
public class PingProbeCompletedArguments : EventArgs
{
public List<string> ip_adresses_list_of_host;
}
public class PortScanner
{
public event PingProbeCompleted ProbeCompleted;
static List<string> ip_adresses = new List<string>();
static CountdownEvent countdown;
public void run_ping_probe()
{
ip_adresses.Clear();
countdown = new CountdownEvent(1);
string ipBase = "10.125.";
for (int sub = 0; sub < 14; sub++)
{
for (int i = 1; i < 255; i++)
{
string ip = ipBase + sub.ToString() + "." + i.ToString();
Ping p = new Ping();
p.PingCompleted += new PingCompletedEventHandler(p_PingCompleted);
countdown.AddCount();
p.SendAsync(ip, 100, ip);
}
}
countdown.Signal();
countdown.Wait();
PingProbeCompletedArguments e = new PingProbeCompletedArguments();
e.ip_adresses_list_of_host = ip_adresses;
ProbeCompleted(this, e);
}
private void p_PingCompleted(object sender, PingCompletedEventArgs e)
{
string ip = (string)e.UserState;
if (e.Reply.Status == IPStatus.Success)
{
ip_adresses.Add(ip + "\t" + e.Reply.RoundtripTime + " ms");
}
countdown.Signal();
}
}
Yes, your code deadlocks when you use it in a Winforms project. The problem is that the Ping class makes a best effort to raise the PingCompleted event on the same thread that called SendAsync(). It uses the AsyncOperationManager.CreateOperation() method to do so.
Problem is, that actually works in a Winforms app. It tries to raise the event on the main thread. But that cannot work since you blocked the main thread with the countdown.Wait() call. The ping cannot complete since the main thread is blocked. The main thread cannot complete since the ping doesn't complete. Deadlock city.
It works in a Console mode app since it doesn't have a synchronization provider like Winforms does. The PingComplete event will be raised on a threadpool thread.
Blocking the UI thread is fundamentally flawed. The quick fix is to run the code on a worker thread. Beware that this makes the ProbeCompleted event fired on that worker as well. Use Control.BeginInvoke() to marshal it to the UI thread. Or use BackgroundWorker.
private void Form1_Load(object sender, EventArgs e) {
PortScanner ps = new PortScanner();
ps.ProbeCompleted += new PingProbeCompleted(ps_ProbeCompleted);
ThreadPool.QueueUserWorkItem((w) => ps.run_ping_probe());
}
And don't forget to remove the extra Signal() call.
your wait handler is run under a thread from the threadpool.
you need to get back into the UI thread to have the UI updated (due to the message loop that the UI runs on) - for that you use SynchronizationContext
Here more info on how to you it:
http://www.codeproject.com/KB/threads/SynchronizationContext.aspx

Im trying to use backgroundworker i want to see the upload progress but it dosent work why?

In the designer i put backgroundworker and i have two events: Do Work and Progress Changed.
I used breakpoint and its getting inside the Do Work event but it never get into the Progress Changed event. Its never stop there like the event isnt working. Why the progrss changed event isnt working ?
This is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Google.GData.Client;
using Google.GData.Extensions;
using Google.GData.Extensions.MediaRss;
using Google.GData.YouTube;
using Google.YouTube;
using System.Threading;
namespace YoutubeTesting
{
public partial class Form1 : Form
{
YouTubeRequestSettings settings;
YouTubeRequest request;
string devkey = "AI39si6xhSQXx95FTYIACWPfq-lLIphblgaReuz9z6VEjR1Q6YjrV6FRN2U6FN6P6-lGF2OYaUZhCVOKJ_MCk4o6kPeUszvf5A";
string username = "chocolade13091972#gmail.com";
string password = "password";
public Form1()
{
InitializeComponent();
worker.RunWorkerAsync();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void upload()
{
try
{
settings = new YouTubeRequestSettings("You Manager", devkey, username, password);
settings.Timeout = -1;
request = new YouTubeRequest(settings);
Video video = new Video();
video.Title = "test";
video.Tags.Add(new MediaCategory("Comedy", YouTubeNameTable.CategorySchema));
video.Keywords = "Comedy";
video.Private = false;
video.MediaSource = new MediaFileSource("d:\\VIDEO0037.3gp", "video/3gp");
request.Upload(video);
MessageBox.Show("Successfully Uploaded");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
upload();
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
textBox1.Text = e.ProgressPercentage.ToString();
}
}
}
You need to report the progress using worker.ReportProgress()
From MSDN:
If you need the background operation to report on its progress, you
can call the ReportProgress method to raise the ProgressChanged event.
The WorkerReportsProgress property value must be true, or
ReportProgress will throw an InvalidOperationException.
It is up to you to implement a meaningful way of measuring your
background operation's progress as a percentage of the total task
completed.
The call to the ReportProgress method is asynchronous and returns
immediately. The ProgressChanged event handler executes on the thread
that created the BackgroundWorker.
You have to set this.
backgroundWorker.WorkerReportsProgress = true;
Gets or sets a value indicating whether the BackgroundWorker can
report progress updates.
EDIT
If still not working checks whether you have bind the event properly in the designer code. Or just add something like below in your class.
backgroundWorker1.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.worker_ProgressChanged);
In your Upload method you have to report progress. Otherwise above event won't fire. Keep in mind that, it's not easy to report actual progress always.
Below is an example code for a DoWork method. Look at here if you want to see a complete example.
static void bw_DoWork (object sender, DoWorkEventArgs e)
{
for (int i = 0; i <= 100; i += 20)
{
if (_bw.CancellationPending) { e.Cancel = true; return; }
_bw.ReportProgress (i);
Thread.Sleep (1000); // Just for the demo... don't go sleeping
} // for real in pooled threads!
e.Result = 123; // This gets passed to RunWorkerCompleted
}

Availability of windows form during processing

I'm doing an application that does some sort of scanning (it checks availability of URL's through a short list) and depending on the result, it adds to one or another listbox. if it exists, it goes to lstOK, else, it goes to lst404.
The issue is that these web checks take time (specially when it is OK), it takes an awfully long time, and inserts all the items in the listboxes in the end, while the form is "not responding" and nothing appears or can be clicked or displays any interaction.
Is there a way for the form to be still usable and the listboxes to update on the go ?
This should be simple, I just don't know it (yet)
I'm using C# in Visual Studio
--[update]--
The whole url checking is in one single function Start()
try the background worker
If this is a desktop application that is performing these "web checks" then you can use a BackgroundWorkerThread to perform the processing, and get the results.
Or you could do something like this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace ThreadWithDataReturnExample
{
public partial class Form1 : Form
{
private Thread thread1 = null;
public Form1()
{
InitializeComponent();
thread1 = new Thread(new ThreadStart(this.threadEntryPoint));
Thread1Completed += new AsyncCompletedEventHandler(thread1_Thread1Completed);
}
private void startButton_Click(object sender, EventArgs e)
{
thread1.Start();
//Alternatively, you could pass some object
//in such as Start(someObject);
//With apprioriate locking, or protocol where
//no other threads access the object until
//an event signals when the thread is complete,
//any other class with a reference to the object
//would be able to access that data.
//But instead, I'm going to use AsyncCompletedEventArgs
//in an event that signals completion
}
void thread1_Thread1Completed(object sender, AsyncCompletedEventArgs e)
{
if (this.InvokeRequired)
{//marshal the call if we are not on the GUI thread
BeginInvoke(new AsyncCompletedEventHandler(thread1_Thread1Completed),
new object[] { sender, e });
}
else
{
//display error if error occurred
//if no error occurred, process data
if (e.Error == null)
{//then success
MessageBox.Show("Worker thread completed successfully");
DataYouWantToReturn someData = e.UserState as DataYouWantToReturn;
MessageBox.Show("Your data my lord: " + someData.someProperty);
}
else//error
{
MessageBox.Show("The following error occurred:" + Environment.NewLine + e.Error.ToString());
}
}
}
#region I would actually move all of this into it's own class
private void threadEntryPoint()
{
//do a bunch of stuff
//when you are done:
//initialize object with data that you want to return
DataYouWantToReturn dataYouWantToReturn = new DataYouWantToReturn();
dataYouWantToReturn.someProperty = "more data";
//signal completion by firing an event
OnThread1Completed(new AsyncCompletedEventArgs(null, false, dataYouWantToReturn));
}
/// <summary>
/// Occurs when processing has finished or an error occurred.
/// </summary>
public event AsyncCompletedEventHandler Thread1Completed;
protected virtual void OnThread1Completed(AsyncCompletedEventArgs e)
{
//copy locally
AsyncCompletedEventHandler handler = Thread1Completed;
if (handler != null)
{
handler(this, e);
}
}
#endregion
}
}
If it's a web form look into AJAX.NET. There are several controls (UpdatePanel being one off the top of my head) that will help you do this.
Take a look at the toolkit.
EDIT: Only for web apps.
Application.DoEvents(); will do all the events that have happened up to that point.
so in your loop, after each website is checked, for example. do Application.DoEvents();
on the other hand if you just want to refresh your listboxes it'll be listboxname.Refresh();
both of these options, however will still have a time where it freezes while the website is pinged, unless you do many of them, which i dont suggets doing.
both methods also only use a single thread and is very linear.
The best option would be to create a new thread to do the tests on, or use a background worker that can do the tests on a seperate thread, so the events of the form can be handled instantly without a need to wait.
Manually controlling another thread shouldnt be too difficult.
here's an example.
using System.Threading;
public class MultiThreadingClass
{
private void FunctionForNewThread()
{
//do stuff
}
private void FunctionWithParameter(object param)
{
//Should do checks with typeof() on param before casting
int convertedparam = (int)param;
//do stuff
}
Thread t, t2;
static void Main()
{
ThreadStart ts = new ThreadStart(FunctionForNewThread);
t = new Thread(ts);
t.Start();
int x = 5;
ParameterizedThreadStart pts = new ParameterizedThreadStart(FunctionWithParameter);
t2 = new Thread(pts);
t2.Start(x);
}
}
it may be important to note here that you should never add a Thread as a local variable that will dissapear, as you can only really get the thread instance back by doing Thread.CurrentThread in the function which was called by the new thread, but if that thread has already locked up, you have a bit of a problem there :)
To easily handle Threads in a global variable either create an Array of threads and call Thread.Abort(); on each running thread when the program closes, or use the ThreadPool class in System.Threading.

Categories