C# cross threading with no form - c#

i have an application which turns your webcam on and off. It turns it on, on a new thread and im trying to make a button work from the main code to turn it off buts cross threading doesnt work and as their is no form, i cant invoke. here is the code:
public class Program
{
public static FilterInfoCollection CaptureDevicesList;
public static VideoSourcePlayer videoSourcePlayer = new VideoSourcePlayer();
public static VideoCaptureDevice videoSource;
public static System.Timers.Timer TimerClose = new System.Timers.Timer();
[STAThread]
static void Main()
{
TimerClose.Elapsed += (o, e) => TimerClose_Tick();
TimerClose.Interval = 10000;
TimerClose.Start();
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
CaptureDevicesList = new FilterInfoCollection(FilterCategory.VideoInputDevice);
Class1.oncam();
}).Start();
Application.Run();
}
private static void TimerClose_Tick()
{
Class1.CloseCurrentVideoSource(); // <--- function cant run
}
}
So what im trying to do is get the close function to work which is trying to turn the webcam off which is running on a different thread. Here is class1:
class Class1
{
public static void oncam()
{
Program.videoSource = new VideoCaptureDevice(Program.CaptureDevicesList[0].MonikerString);
OpenVideoSource(Program.videoSource);
}
public static void OpenVideoSource(IVideoSource source)
{
CloseCurrentVideoSource();
Program.videoSourcePlayer.VideoSource = source;
Program.videoSourcePlayer.Start();
}
public static void CloseCurrentVideoSource()
{
if (Program.videoSourcePlayer.VideoSource != null)
{
Program.videoSourcePlayer.SignalToStop();
for (int i = 0; i < 30; i++)
{
if (!Program.videoSourcePlayer.IsRunning)
break;
System.Threading.Thread.Sleep(100);
}
if (Program.videoSourcePlayer.IsRunning)
{
Program.videoSourcePlayer.Stop();
}
Program.videoSourcePlayer.VideoSource = null;
}
}
}
Any help is appriciated

VideoSourcePlayer inherits from System.Windows.Forms.Control and thus requires synchronization for cross-thread access.
Call Invoke on this control when accessing it from another thread.

Related

C# multithreaded throbber form

Working on a C# project which I would like to implement a "waiting" (throbber) indicator in a separate form. After much research and trial and error it appears as the suggested method of doing this is to load a form using a separate thread from the one from the current form/thread.
The reason I went with this method was because initially using the Show() method on the throbber form produced a transparent form. I cannot use ShowDialog because I need to run some code after the throbber is displayed, after which that completes I would like to close the throbber form.
Anyway .. after trying many different methods to load the throbber form in a separate thread I still get an error about trying to access it from a thread which is different from the one it was created in. Here is a skelton version of the project code that should shed some light on my issue:
the example I was working off of for multithreading was this popular link for creating your own spashscreen in a separate thread ... http://www.codeproject.com/Articles/5454/A-Pretty-Good-Splash-Screen-in-C
public class Main
{
public void CheckData()
{
try
{
ProgressBar pb = new ProgressBar();
pb.ShowProgressBar();
//do data checking here
pb.CloseForm()
}
catch(Exception e)
{
}
}
}
public partial class ProgressBar : Form
{
static Thread ms_oThread = null;
public bool shouldStop = false;
static ProgressBar ms_ProgBar = null;
public ProgressBar()
{
InitializeComponent();
//DoWork();
}
public void ShowForm()
{
ms_ProgBar = new ProgressBar();
Application.Run(ms_ProgBar);
}
public void CloseForm()
{
ms_ProgBar.Close();
}
public void ShowProgressBar()
{
// Make sure it is only launched once.
if (ms_ProgBar != null)
return;
ms_oThread = new Thread(new ThreadStart(ShowForm));
ms_oThread.IsBackground = true;
ms_oThread.SetApartmentState(ApartmentState.STA);
ms_oThread.Start();
while (ms_ProgBar == null || ms_ProgBar.IsHandleCreated == false)
{
System.Threading.Thread.Sleep(1000);
}
}
}
You are creating your ProgressBar twice. Once in your main function, and once in your new thread. You are also calling your CloseWindow method from your main function (and on the window that is never shown), rather than on your new thread window.
You only want to create ProgressBar and show it using your new thread. Make your static ProgressBar field public so you can call close on it directly from Main, but make sure to use Invoke to do it since it's not on that Window's GUI thread.
Also, ShowProgressBar should be static.
Here's a rewrite attempt:
public class Main
{
public void CheckData()
{
try
{
ProgressBar.ShowProgressBar();
//do data checking here
ProgressBar.CloseForm();
}
catch(Exception e)
{
}
}
}
public partial class ProgressBar : Form
{
static ProgressBar _progressBarInstance;
public ProgressBar()
{
InitializeComponent();
//DoWork();
}
static void ShowForm()
{
_progressBarInstance = new ProgressBar();
Application.Run(ms_ProgressBar);
}
public static void CloseForm()
{
_progressBarInstance.Invoke(new Action(_progressBarInstance.Close));
_progressBarInstance= null;
}
public static void ShowProgressBar()
{
// Make sure it is only launched once.
if (_progressBarInstance != null)
return;
var ms_oThread = new Thread(new ThreadStart(ShowForm));
ms_oThread.IsBackground = true;
ms_oThread.SetApartmentState(ApartmentState.STA);
ms_oThread.Start();
}
}

refreshing UI elements in work threads

Question 1: I want to refresh a label by a work thread by delegate and invoke. It works well until i try to close the form. In closing event, I stop the work thread and then the UI thread while an exception occurs(Object disposed exception). It seems that form1 is disposed. I don't know what's wrong.
Question 2: When running this code, the memory usage keep increasing. I don't think it should take so much memory space. You can see find this by checking the task manager.
here's my code:
(.Net Framework 4, winforms)
Scheduler:
class Scheduler
{
private Thread[] workThreads = null;
//Scheduler started flag
public static bool bSchedulerStarted = false;
//Work threads stop event
public static EventWaitHandle stopWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
private static Scheduler self = null;
public static Scheduler getInstance()
{
if (self == null)
{
self = new Scheduler();
}
return self;
}
private Scheduler()
{
workThreads = new Thread[1];
}
private void CreateThread()
{
workThreads[0] = new Thread(Worker.doWork);
workThreads[0].IsBackground = true;
}
public void startUp()
{
if (!bSchedulerStarted)
{
stopWaitHandle.Reset();
CreateThread();
//Start all work threads
for (int i = 0; i < 1; i++)
{
workThreads[i].Start();
}
bSchedulerStarted = true;
}
}
public void stop()
{
if (!bSchedulerStarted)
return;
//Send stop event
stopWaitHandle.Set();
bSchedulerStarted = false;
if (workThreads != null)
{
//wait for all work threads to stop
for (int i = 0; i <1; i++)
{
if (workThreads[i] != null && workThreads[i].IsAlive)
workThreads[i].Join();
}
}
}
}
Worker:
class Worker
{
public static void doWork()
{
while (true)
{
if (Scheduler.stopWaitHandle.WaitOne(10, false) == true)
{
break;
}
Form1.count++;
Form1.sysMsgEvent.Set();
Thread.Sleep(10);
}
}
}
And form:
public partial class Form1 : Form
{
public static int count = 0;
public static EventWaitHandle sysMsgEvent = new EventWaitHandle(false, EventResetMode.AutoReset);
public static EventWaitHandle stopEvent = new EventWaitHandle(false, EventResetMode.ManualReset);
private EventWaitHandle[] waitEvent = null;
Thread UIThread = null;
private delegate void ShowMsg();
public Form1()
{
InitializeComponent();
waitEvent = new EventWaitHandle[2];
waitEvent[0] = stopEvent;
waitEvent[1] = sysMsgEvent;
}
public void UpdateUI()
{
while (true)
{
switch (EventWaitHandle.WaitAny(waitEvent))
{
case 0: //Stop UI thread
return;
case 1: //Refresh UI elements
updateLabel();
break;
default:
return;
}//switch
}//while
}
private void updateLabel()
{
if (label1.InvokeRequired)
{
ShowMsg d = new ShowMsg(updateLabel);
this.Invoke(d, null);
}
else
{
label1.Text = count.ToString();
}
}
private void Form1_Load(object sender, EventArgs e)
{
UIThread = new Thread(new ThreadStart(UpdateUI));
UIThread.Start();
Scheduler sc = Scheduler.getInstance();
sc.startUp();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Scheduler sc = Scheduler.getInstance();
sc.stop();
//stop UI thread
Form1.stopEvent.Set();
}
}

How to implement monitor and system.threading for the smokers situation

The problem that I am working on deals with out to use a functional Lock, or monitor structure, to provided exclusive access to only one member on separate threads. Below, is my class definition of the monitor (note that it is different than the actual monitor class given by c# library). What I am trying to do is make pictureboxes appear or disappear on my form.
I have attempted to add in an instance of the form so I can access the individual pictureboxes, however, my program seems to freeze.
namespace SmokersProblem
{
class monitor
{
Form1 form = new Form1();
Random num = new Random();
object obj = new object();
public monitor()
{
}
public void agent(){
form.pictureBox4.Visible = false;
int r = num.Next(1, 4);
if (r == 1)
{
// put lighter and paper on table
smoker1();
}
else if (r == 2)
{
// put lighter and tobacco on table
smoker2();
}
else
{
// put paper and tobacco on table
smoker3();
}
}
public void smoker1()
{
//lock (obj)
//{
form.pictureBox9.Visible = true;
form.pictureBox1.Visible = false;
System.Threading.Thread.Sleep(5000);
//agent();
// }
}
public void smoker2()
{
//lock (obj)
//{
form.pictureBox10.Visible = true;
form.pictureBox3.Visible = false;
System.Threading.Thread.Sleep(5000);
//agent();
//}
}
public void smoker3()
{
//lock (obj)
//{
form.pictureBox11.Visible = true;
form.pictureBox2.Visible = false;
System.Threading.Thread.Sleep(5000);
//agent();
// }
}
}
}
Below is my form code, as you can see here, i try to create three seperate threads, one for each smoker.
namespace SmokersProblem
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Random rnd = new Random();
int num = rnd.Next(1, 4);
Object obj = new Object();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
pictureBox1.Visible = true;
pictureBox2.Visible = true;
pictureBox3.Visible = true;
pictureBox8.Visible = false;
pictureBox7.Visible = false;
pictureBox6.Visible = false;
monitor one = new monitor();
one.agent();
Thread vone = new Thread(one.smoker1);
Thread two = new Thread(one.smoker2);
Thread three = new Thread(one.smoker3);
vone.Start();
two.Start();
three.Start();
}
}
}
After implementing this, I went looking for the Smoker Thread Problem that it looks like OP is trying to implement. This code should be easily adaptable to that problem.
The reason your UI is freezing is that you're calling one.agent() without putting it in a new thread. one.agent() sleeps, which keeps your UI from processing events.
OK, I've implemented some code to do the smoker problem with labels. Obviously it could be improved, for instance by not coupling the form to the threads.
I put two different locking mechanisms in, and left one commented out.
Essentially, there are three labels that can either be "Smoking" or "Not Smoking". The main UI thread creates three threads:
Smoker1
Smoker2
Smoker3
Each of the threads continually tries to take the lock in a while loop. When they take the lock, they set their label to "Smoking", wait a few seconds, and then set their label to "Not Smoking". This uses thread safe code from this answer.
public partial class Form1 : Form
{
private bool running = false;
public Label OneLabel { get; set; }
public Label TwoLabel { get; set; }
public Label ThreeLabel { get; set; }
private MyMonitor one;
private Thread vone;
private Thread two;
private Thread three;
public Form1()
{
InitializeComponent();
OneLabel = new Label();
OneLabel.Text = "Not Smoking";
OneLabel.Location = new Point(10, 50);
OneLabel.AutoSize = true;
this.Controls.Add(OneLabel);
TwoLabel = new Label();
TwoLabel.Text = "Not Smoking";
TwoLabel.Location = new Point(150, 50);
this.Controls.Add(TwoLabel);
ThreeLabel = new Label();
ThreeLabel.Text = "Not Smoking";
ThreeLabel.Location = new Point(300, 50);
this.Controls.Add(ThreeLabel);
}
private void MainButton_Click(object sender, EventArgs e)
{
if (!running)
{
vone.Start();
two.Start();
three.Start();
MainButton.Text = "Stop";
running = true;
}
else
{
one.RequestStop();
MainButton.Text = "Run";
running = false;
}
}
private void Form1_Load(object sender, EventArgs e)
{
one = new MyMonitor(this);
vone = new Thread(one.Smoker1);
two = new Thread(one.Smoker2);
three = new Thread(one.Smoker3);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (running)
{
one.RequestStop();
running = false;
}
}
}
class MyMonitor
{
private int x = 1;
private Object obj = new Object();
private Form1 _form;
bool _finished = false;
public MyMonitor(Form1 form)
{
_form = form;
}
public void Smoker1()
{
while (!_finished)
{
//lock (obj)
//{
// _form.OneLabel.SetPropertyThreadSafe(() => _form.OneLabel.Text, "Smoking");
// System.Threading.Thread.Sleep(2000);
// _form.OneLabel.SetPropertyThreadSafe(() => _form.OneLabel.Text, "Not Smoking");
//}
try
{
Monitor.Enter(obj);
try
{
_form.OneLabel.SetPropertyThreadSafe(() => _form.OneLabel.Text, "Smoking");
System.Threading.Thread.Sleep(2000);
_form.OneLabel.SetPropertyThreadSafe(() => _form.OneLabel.Text, "Not Smoking");
}
finally
{
Monitor.Exit(obj);
}
}
catch (SynchronizationLockException SyncEx)
{
Console.WriteLine(SyncEx.Message);
}
}
}
public void Smoker2()
{
while (!_finished)
{
//lock (obj)
//{
// _form.TwoLabel.SetPropertyThreadSafe(() => _form.TwoLabel.Text, "Smoking");
// System.Threading.Thread.Sleep(2000);
// _form.TwoLabel.SetPropertyThreadSafe(() => _form.TwoLabel.Text, "Not Smoking");
//}
try
{
Monitor.Enter(obj);
try
{
_form.TwoLabel.SetPropertyThreadSafe(() => _form.TwoLabel.Text, "Smoking");
System.Threading.Thread.Sleep(2000);
_form.TwoLabel.SetPropertyThreadSafe(() => _form.TwoLabel.Text, "Not Smoking");
}
finally
{
Monitor.Exit(obj);
}
}
catch (SynchronizationLockException SyncEx)
{
Console.WriteLine(SyncEx.Message);
}
}
}
public void Smoker3()
{
while (!_finished)
{
//lock (obj)
//{
// _form.ThreeLabel.SetPropertyThreadSafe(() => _form.ThreeLabel.Text, "Smoking");
// System.Threading.Thread.Sleep(2000);
// _form.ThreeLabel.SetPropertyThreadSafe(() => _form.ThreeLabel.Text, "Not Smoking");
//}
try
{
Monitor.Enter(obj);
try
{
_form.ThreeLabel.SetPropertyThreadSafe(() => _form.ThreeLabel.Text, "Smoking");
System.Threading.Thread.Sleep(2000);
_form.ThreeLabel.SetPropertyThreadSafe(() => _form.ThreeLabel.Text, "Not Smoking");
}
finally
{
Monitor.Exit(obj);
}
}
catch (SynchronizationLockException SyncEx)
{
Console.WriteLine(SyncEx.Message);
}
}
}
public void RequestStop()
{
_finished = true;
}
}
//Thread Safe Extension Method
public static class Extensions
{
private delegate void SetPropertyThreadSafeDelegate<TResult>(Control #this, Expression<Func<TResult>> property, TResult value);
public static void SetPropertyThreadSafe<TResult>(this Control #this, Expression<Func<TResult>> property, TResult value)
{
var propertyInfo = (property.Body as MemberExpression).Member as PropertyInfo;
if (propertyInfo == null ||
!#this.GetType().IsSubclassOf(propertyInfo.ReflectedType) ||
#this.GetType().GetProperty(propertyInfo.Name, propertyInfo.PropertyType) == null)
{
throw new ArgumentException("The lambda expression 'property' must reference a valid property on this Control.");
}
if (#this.InvokeRequired)
{
#this.Invoke(new SetPropertyThreadSafeDelegate<TResult>(SetPropertyThreadSafe), new object[] { #this, property, value });
}
else
{
#this.GetType().InvokeMember(propertyInfo.Name, BindingFlags.SetProperty, null, #this, new object[] { value });
}
}
}
my program seems to freeze
My one.agent() is the part of the code that allows one of the smokers
to be called on, so they can smoke. Why wouldnt I want it in the main
code?
Because you shouldn't be using Sleep() from the main UI thread, which is what happens when you call one.agent() from the Button Click event. When Sleep(5000) is hit, you're telling the forms main UI thread to not do ANYTHING for five seconds, thus the freezing you're seeing.
To fix this, you'd need agent() to execute smoker1(), smoker2(), or smoker3() in a separate thread like you're doing down below.
There are several other problems with the code, however, that must also be addressed before you can "fix" your code...
The next problem lies in you creating a new instance of Form1() inside your monitor() class. This instance of Form1() is not the same one that is visible on your screen. Acting upon it is modifying an invisible form that has never even been shown. To act upon the form that is actually visible on your screen would require you to either (a) pass a reference to it into your monitor() class when you create it, or (b) have your monitor() class raise custom events that Form1() subscribes to, again when it creates monitor().
The last problem lies in you attempting to change UI controls from within a thread other than the main UI thread. This will result in a cross-thread exception (unless you've turn this off, which you shouldn't). There are various ways to overcome this problem, the most basic of which involves using delegates and the Invoke() method of the Form/Control to which you are trying to update.

Async/Await with a WinForms ProgressBar

I've gotten this type of thing working in the past with a BackgroundWorker, but I want to use the new async/await approach of .NET 4.5. I may be barking up the wrong tree. Please advise.
Goal: Create a component that will do some long-running work and show a modal form with a progress bar as it's doing the work. The component will get the handle to a window to block interaction while it's executing the long-running work.
Status: See the code below. I thought I was doing well until I tried interacting with the windows. If I leave things alone (i.e. don't touch!), everything runs "perfectly", but if I do so much as click on either window the program hangs after the long-running work ends. Actual interactions (dragging) are ignored as though the UI thread is blocked.
Questions: Can my code be fixed fairly easily? If so, how? Or, should I be using a different approach (e.g. BackgroundWorker)?
Code (Form1 is a standard form with a ProgressBar and a public method, UpdateProgress, that sets the ProgressBar's Value):
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting..");
var mgr = new Manager();
mgr.GoAsync();
Console.WriteLine("..Ended");
Console.ReadKey();
}
}
class Manager
{
private static Form1 _progressForm;
public async void GoAsync()
{
var owner = new Win32Window(Process.GetCurrentProcess().MainWindowHandle);
_progressForm = new Form1();
_progressForm.Show(owner);
await Go();
_progressForm.Hide();
}
private async Task<bool> Go()
{
var job = new LongJob();
job.OnProgress += job_OnProgress;
job.Spin();
return true;
}
void job_OnProgress(int percent)
{
_progressForm.UpdateProgress(percent);
}
}
class LongJob
{
public event Progressed OnProgress;
public delegate void Progressed(int percent);
public void Spin()
{
for (var i = 1; i <= 100; i++)
{
Thread.Sleep(25);
if (OnProgress != null)
{
OnProgress(i);
}
}
}
}
class Win32Window : IWin32Window
{
private readonly IntPtr _hwnd;
public Win32Window(IntPtr handle)
{
_hwnd = handle;
}
public IntPtr Handle
{
get
{
return _hwnd;
}
}
}
}
The async and await keywords do not mean "run on a background thread." I have an async/await intro on my blog that describes what they do mean. You must explicitly place CPU-bound operations on a background thread, e.g., Task.Run.
Also, the Task-based Asynchronous Pattern documentation describes the common approaches with async code, e.g., progress reporting.
class Manager
{
private static Form1 _progressForm;
public async Task GoAsync()
{
var owner = new Win32Window(Process.GetCurrentProcess().MainWindowHandle);
_progressForm = new Form1();
_progressForm.Show(owner);
var progress = new Progress<int>(value => _progressForm.UpdateProgress(value));
await Go(progress);
_progressForm.Hide();
}
private Task<bool> Go(IProgress<int> progress)
{
return Task.Run(() =>
{
var job = new LongJob();
job.Spin(progress);
return true;
});
}
}
class LongJob
{
public void Spin(IProgress<int> progress)
{
for (var i = 1; i <= 100; i++)
{
Thread.Sleep(25);
if (progress != null)
{
progress.Report(i);
}
}
}
}
Note that the Progress<T> type properly handles thread marshaling, so there's no need for marshaling within Form1.UpdateProgress.
#StephenCleary's answer is correct. Though, I had to make a little modification to his answer to get the behavior what I think OP wants.
public void GoAsync() //no longer async as it blocks on Appication.Run
{
var owner = new Win32Window(Process.GetCurrentProcess().MainWindowHandle);
_progressForm = new Form1();
var progress = new Progress<int>(value => _progressForm.UpdateProgress(value));
_progressForm.Activated += async (sender, args) =>
{
await Go(progress);
_progressForm.Close();
};
Application.Run(_progressForm);
}
private async void button1_Click(object sender, EventArgs e)
{
IProgress<int> progress = new Progress<int>(value => { progressBar1.Value = value; });
await Task.Run(() =>
{
for (int i = 0; i <= 100; i++)
progress.Report(i);
});
}
Correct me if I'm wrong, but this seems to be the easiest way to update a progress bar.

MultiThreading WebBrowser Control C# STA [duplicate]

This question already has answers here:
WebBrowser Control in a new thread
(4 answers)
Closed 7 years ago.
I want to make 3 threads that each run the WebBroswer control. So I would like to use the ThreadPool to make things easy.
for(int i = 0;i < 3;i++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(gotoWork), i));
}
WaitAll(waitHandles);
....../
void gotoWork(object o)
{
string url = String.Empty;
int num = (int)o;
switch(num)
{
case 0:
url = "google.com";
break;
case 1:
url = "yahoo.com";
break;
case 2:
url = "bing.com";
break;
}
WebBrowser w = new WebBrower();
w.Navigate(url);
}
But I get an error saying that I need a STA thread which the ThreadPool will never be. Before trying this method I tried this.
Thread[] threads = Thread[3];
for(int i = 0;i < 3;i++)
{
threads[i] = new Thread(new ParameterizedStart(gotoWork);
threads[i] = SetApartmentState(ApartmentState.STA); //whoo hoo
threads[i] = Start();
}
for(int i = 0; i < 3;i++)
{
threads[i].Join();
}
And the WebBrowsers all initialized and everything looks good but only one more two will actually do anything and its never consistant at all. Threading has been such a nightmare. Can anybody suggest a nice alternative?
public sealed class SiteHelper : Form
{
public WebBrowser mBrowser = new WebBrowser();
ManualResetEvent mStart;
public event CompletedCallback Completed;
public SiteHelper(ManualResetEvent start)
{
mBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(mBrowser_DocumentCompleted);
mStart = start;
}
void mBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// Generated completed event
Completed(mBrowser);
}
public void Navigate(string url)
{
// Start navigating
this.BeginInvoke(new Action(() => mBrowser.Navigate(url)));
}
public void Terminate()
{
// Shutdown form and message loop
this.Invoke(new Action(() => this.Close()));
}
protected override void SetVisibleCore(bool value)
{
if (!IsHandleCreated)
{
// First-time init, create handle and wait for message pump to run
this.CreateHandle();
this.BeginInvoke(new Action(() => mStart.Set()));
}
// Keep form hidden
value = false;
base.SetVisibleCore(value);
}
}
An other class as
public abstract class SiteManager : IDisposable
{
private ManualResetEvent mStart;
private SiteHelper mSyncProvider;
public event CompletedCallback Completed;
public SiteManager()
{
// Start the thread, wait for it to initialize
mStart = new ManualResetEvent(false);
Thread t = new Thread(startPump);
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
mStart.WaitOne();
}
public void Dispose()
{
// Shutdown message loop and thread
mSyncProvider.Terminate();
}
public void Navigate(string url)
{
// Start navigating to a URL
mSyncProvider.Navigate(url);
}
public void mSyncProvider_Completed(WebBrowser wb)
{
// Navigation completed, raise event
CompletedCallback handler = Completed;
if (handler != null)
{
handler(wb);
}
}
private void startPump()
{
// Start the message loop
mSyncProvider = new SiteHelper(mStart);
mSyncProvider.Completed += mSyncProvider_Completed;
Application.Run(mSyncProvider);
}
}
class Tester :SiteManager
{
public Tester()
{
SiteEventArgs ar = new SiteEventArgs("MeSite");
base.Completed += new CompletedCallback(Tester_Completed);
}
void Tester_Completed(WebBrowser wb)
{
MessageBox.Show("Tester");
if( wb.DocumentTitle == "Hi")
base.mSyncProvider_Completed(wb);
}
//protected override void mSyncProvider_Completed(WebBrowser wb)
//{
// // MessageBox.Show("overload Tester");
// //base.mSyncProvider_Completed(wb, ar);
//}
}
On your main form:
private void button1_Click(object sender, EventArgs e)
{
//Tester pump = new Tester();
//pump.Completed += new CompletedCallback(pump_Completed);
//pump.Navigate("www.cnn.com");
Tester pump2 = new Tester();
pump2.Completed += new CompletedCallback(pump_Completed);
pump2.Navigate("www.google.com");
}
You need to host webbrowser control in somewhere to get it work (add it to a form), secondly you should use Invoke() of the host control (or a similar delegate) such as Form.Invoke() to interact with WebBrowser control.
No need to remind now but yes, your threads should be STA
You can use such type of class for your purpose to host WebBrowser control:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SomeNameSpace
{
public class WebForm : Form
{
public WebBrowser WebBrowser { get; set; }
public WebForm()
{
WebBrowser = new WebBrowser();
}
}
}
After all I choose this solution:
http://watin.sourceforge.net/documentation.html
In your case you should do this:
...
Thread thread = new Thread(SomeMethod);
thread.SetApartmentState(ApartmentState.STA);
...

Categories