Accessing WebBrowser on different Threads - c#

I want to access a static WebBrowser from different threads.
Here is my sample code:
public partial class MainFrame : Form
{
public static WebBrowser webBrowser = new WebBrowser();
public MainFrame()
{
InitializeComponent();
}
}
class Job
{
public void Process()
{
MainFrame.webBrowser.Navigate("http://www.google.com");
while (MainFrame.webBrowser.ReadyState != WebBrowserReadyState.Complete)
{
Thread.Sleep(1000);
Application.DoEvents();
}
}
}
For simplicity suppose I have 2 threads. Thread 1 calls Process() function and waits for it to finish, so at this stage webBrowser should be in Complete WebBrowserReadyState mode.
10 seconds after thread 1 is finished, Thread 2 calls Process() function. At this moment If i debug my code and put a BreakPoint at the first line of Process() function and watch MainFrame.webBrowser variable I would see this:
In another words it's somehow inaccessible. Anyone knows any solution to this issue?
Additional info: 10 seconds after thread 1 is
finished, If I call Thread 1 again, then everything looks fine.

You cannot directly call WebBrowser control's methods or properties from a thread the control was not created on. You'd need to proxy such calls into the control's parent thread. One way of doing this is with BeginInvoke, but it is asynchronous.
If you really need to do it synchronously, you could use SynchronizationContext.Send, like this:
public partial class MainFrame : Form
{
public static WebBrowser webBrowser = new WebBrowser();
public static System.Threading.SynchronizationContext mainThreadContext = System.Threading.SynchronizationContext.Current;
public MainFrame()
{
InitializeComponent();
}
}
class Job
{
public void Process()
{
mainThreadContext.Send(delegate
{
MainFrame.webBrowser.Navigate("http://www.google.com");
}, null);
bool ready = false;
while (!ready)
{
mainThreadContext.Send(delegate
{
ready = MainFrame.webBrowser.ReadyState != WebBrowserReadyState.Complete;
}, null);
Thread.Sleep(1000);
// if you don't have any UI on this thread, DoEvent is redundant
Application.DoEvents();
}
}
}
Anyway, the above code doesn't looks like a good design to me. What are you trying to achieve? There might be a better way of do it. Perhaps, you can just use WebBrowser.DocumentCompleted event?

Related

Updating UI in batches with RX c#

I'm having an issue with updating WPF UI with the RX. Currently I have a class that has an event which is called within its functions. Event is subscribed from the UI thread and updates the UI like below :
SomeClass.cs
public partial class SomeClass
{
public delegate Task ProgressUpdate(string value);
public delegate Task BarUpdate(int value);
public event ProgressUpdate OnProgressUpdateList;
public event BarUpdate OnProgressUpdateBar;
public async Task DoSomething()
{
// execute code
<some code>
// update UI
if (OnProgressUpdateList != null)
{
OnProgressUpdateList(update);
}
}
}
And in MainWindow.xaml
var someClass = new SomeClass();
someClass.OnProgressUpdateList += Export_OnProgressUpdateList;
someClass.OnProgressUpdateBar += Export_OnProgressUpdateBar;
private async Task Export_OnProgressUpdateList(string text)
{
await Dispatcher.InvokeAsync(() =>
{
OutputLog.AppendText(text);
OutputLog.AppendText(Environment.NewLine);
OutputLog.ScrollToEnd();
});
}
This code works except the program processes huge number of files and I'm assuming this is why the UI becomes frozen very quickly (I see the updates being done in the first half a second). I searched for a way around this and I came into a solution to use RX for batching the UI calls. I've searched through several SO posts but I couldn't find an answer on how to correctly implements this (or convert C# events to RX observables) when I call those events from the class and subscribe to this event from outside that class. Can someone help me understand this?
I'm posting an answer to myself as I couldn't get one here and I finally figured it out so for anyone looking for that in the future - here you go:
public partial class SomeClass {
public Subject<string> outputLogSubject = new Subject<string>();
public IObservable<string> OutputLog => outputLogSubject.AsObservable();
//Add string for collection updating UI
outputLogSubject.OnNext(string);
//After finishing the work you can call outputLogSubject.OnCompleted() to stop buffering
outputLogSubject.OnCompleted();
}
It needs to be added in the class that will be calling the executing the work.
Below needs to be added in the UI thread after initialization and BEFORE processing work :
var buffer = someClass.OutputLog.Buffer(TimeSpan.FromMilliseconds(1000), 6);
var chunked = buffer.ObserveOnDispatcher(DispatcherPriority.Background);
var update = chunked.Subscribe(name =>
{
foreach (var item in name)
{
OutputLog.AppendText(item);
}
OutputLog.ScrollToEnd();
});
This allowed me to keep the UI responsive to the point of seeing the output log is real time

Calling Invoke/BeginInvoke from a thread

I have a C# 2.0 application with a form that uses a class that contains a thread.
In the thread function, rather than call the event handler directly, it is invoked. The effect is that the owning form does not need to call InvokeRequired/BeginInvoke to update its controls.
public class Foo
{
private Control owner_;
Thread thread_;
public event EventHandler<EventArgs> FooEvent;
public Foo(Control owner)
{
owner_ = owner;
thread_ = new Thread(FooThread);
thread_.Start();
}
private void FooThread()
{
Thread.Sleep(1000);
for (;;)
{
// Invoke performed in the thread
owner_.Invoke((EventHandler<EventArgs>)InternalFooEvent,
new object[] { this, new EventArgs() });
Thread.Sleep(10);
}
}
private void InternalFooEvent(object sender, EventArgs e)
{
EventHandler<EventArgs> evt = FooEvent;
if (evt != null)
evt(sender, e);
}
}
public partial class Form1 : Form
{
private Foo foo_;
public Form1()
{
InitializeComponent();
foo_ = new Foo(this);
foo_.FooEvent += OnFooEvent;
}
private void OnFooEvent(object sender, EventArgs e)
{
// does not need to call InvokeRequired/BeginInvoke()
label_.Text = "hello";
}
}
This is obviously contrary to the method used by Microsoft APIs that use background threads like System.Timers.Timer and System.Io.Ports.SerialPort. Is there anything inherently wrong with this method? Is it dangerous in some way?
Thanks,
PaulH
Edit: also, what if the form did not subscribe to the event right away? Would it clog the Form's message queue with events the form wasn't interested in?
This is a threadsafe call, the method will be processed in the thread of the form.
Nothing wrong with it when looking at it from a conceptual perspective.
Timers are more elegant for such tasks, though. However, it could be that a timer with an interval of 10ms slows down the GUI, that's probably why Invoke was used.
You do not need a call to InvokeRequired, since it is clear that the Control is in an other thread. Also, BeginInvoke only needs to be called when you want to call a method asynchronously, which obviously isn't the case here.
Regarding your edit:
No, the message queue will not be clogged. No event will be fired if no handler has been registered. Take another look at your code ;)

Should my Wait Dialog implement Singleton pattern?

i'm currently working on my personal Wait Dialog implementation, wich supports task progress update and task cancellation. ATM it is something like:
public partial class WaitDialog : Form
{
WaitDialog()
{
InitializeComponent();
}
public static WaitDialog Instance
{
get { return WaitDialogCreator.uniqueInstance; }
}
public DialogResult ShowDialog(Form owner, string message)
{
Instance.lblWaitMessage.Text = message;
return Instance.ShowDialog(owner);
}
public DialogResult ShowDialog(Form owner, BackgroundWorker worker)
{
...
}
public DialogResult ShowDialog(Form owner, string message, BackgroundWorker worker)
{
...
}
private class WaitDialogCreator
{
static WaitDialogCreator() { }
internal static readonly WaitDialog uniqueInstance = new WaitDialog();
}
}
In my ShowDialog() method I can pass a worker object parameter, so that i can set some properties/handlers that depends on its properies, such as the type of progress bar used (marquee if it reports progress changes, continuous otherwise), the possibility to cancel the task (according to WorkerSupportsCancellation prop), etc. The method looks like this:
public DialogResult ShowDialog(Form owner, BackgroundWorker worker)
{
if (worker == null)
{
throw new ArgumentNullException("worker", "A non-null worker must be provided.");
}
else
{
Instance.btnCancel.Enabled = worker.WorkerSupportsCancellation;
//This handler close the dialog
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(onWorkerWorkComplete);
if (worker.WorkerReportsProgress)
{
Instance.pbProgress.Style = ProgressBarStyle.Continuous;
//Update the progress bar
worker.ProgressChanged += new ProgressChangedEventHandler(onWorkerProgressChanged);
}
if (worker.WorkerSupportsCancellation)
{
Instance.btnCancel.Click += (sender, e) => { worker.CancelAsync(); };
}
}
return Instance.ShowDialog(owner);
}
I would access the wait dialog thru a controller on my parent form in this way:
public Controller(Form window)
{
this.window = window;
this.waitDialog = WaitDialog.Instance;
}
...
public void ShowWaitDialog(BackgroundWorker worker)
{
if (worker == null)
{
this.ShowWaitDialog();
}
else
{
window.BeginInvoke((MethodInvoker)delegate() { waitDialog.ShowDialog(window, worker); });
}
}
Maybe that's a very noobish question, but here it is: is it correct to apply (as I do) the Singleton Pattern in this case, or shoud i opt for normal instance creation, given that WaitDialog class ends will normally handle more than a BackGroundWorker in its lifecycle?
The thing that makes me wonder is that I can (and i will) modify WaitDialog's single instance properties each time I pass a new BackGroundWorker in my call to ShowDialog(Form, BackGroundWorker).
Is it a correct behavior, according to the pattern? Are there other path i can take for a better implementation? I am open to any suggestion.
I would creating a new instance every time.
The reason I would not use a singleton is because the form does not have any meaning beyond the use of one specific wait operation. Singleton patterns are used when you want to setup an instance of a class only once and re-use that instance over and over, with its specific settings.
No, it's a bad idea. The Form class was very much designed as a single-use class. Once a form object is disposed it is dead and cannot be revived. You'll get an ObjectDisposedException when you try to display it again. To prevent this, you'll have to intercept the FormClosing event and stop the default processing. You could call Hide() and set e.Cancel = true. But now you've got the hassle of killing it when you really want to get rid of it.
But perhaps more convincingly, you should only ever cache objects that are very expensive to create but don't take a lot of resources. The Form class is the exact opposite. Creating it is cheap but it takes a very large amount of both managed and unmanaged resources. Especially the latter, a window is a very costly OS object. It may look like a Form is expensive to create but what you see is the cycles that are burned on painting the form. You'll burn the exact same number of cycles when you show a hidden form.

Calling a void async. - Event based pattern, or another method?

I have a class that basically stores files in amazon s3.
Here is what it looks like (simplified)
public class S3FileStore
{
public void PutFile(string ID, Stream content)
{
//do stuff
}
}
In my client app, I want to be able to call:
var s3 = new() S3FileStore();
s3.PutFile ("myId", File.OpenRead(#"C:\myFile1"));
s3.PutFile ("myId", File.OpenRead(#"C:\myFile2"));
s3.PutFile ("myId", File.OpenRead(#"C:\myFile3"));
I want this to be an asynchronous operation - I want the S3FileStore to handle this (i don't want my caller to have to execute PutFile asynchronously so to speak) but, i want to be able to trap exceptions / tell if the operation completed for each file.
I've looked at event based async calls, especially this:
http://blogs.windowsclient.net/rendle/archive/2008/11/04/functional-shortcuts-2-event-based-asynchronous-pattern.aspx
However, I can't see how to call my PutFile (void) method?
Are there any better examples?
Look at the solution for this question: Adding cancel ability and exception handling to async code . Hope it helps.
The BackgroundWorker base class might be worth a look, and also the Thread Pool:
ThreadPool.QueueUserWorkItem(delegate
{
s3.PutFile ("myId", File.OpenRead(#"C:\myFile1"));
});
This is basically what you would do with the Action/BeginInvoke pattern. With BeginInvoke, you additionally receive an IAsyncResult on which you can call .WaitOne() to block the current thread until the operation finished, in case you need that. You would trigger a new BeginInvoke for every file you'd like to save.
If you need to do this frequently, a more sophisticated version could be to use a Queue in combination with the BackgroundWorker, e.g.:
public sealed class S3StoreLikePutFileWorker<TYourData> : BackgroundWorker
{
private AutoResetEvent WakeUpEvent = new AutoResetEvent(false);
private Queue<TYourData> DataQueue = new Queue<TYourData>();
private volatile bool StopWork = false;
public void PutFile(TYourData dataToWrite)
{
DataQueue.Enqueue(dataToWrite);
WakeUpEvent.Set();
}
public void Close()
{
StopWork = true;
WakeUpEvent.Set();
}
private override void OnDoWork(DoWorkEventArgs e)
{
do
{
// sleep until there is something to do
WakeUpEvent.WaitOne();
if(StopWork) break;
// Write data, if available
while(DataQueue.Count > 0)
{
TYourData yourDataToWrite = DataQueue.Dequeue();
// write data to file
}
}
while(!StopWork);
}
}
Depending on how much complexity you need.
The BackgroundWorker supports progress feedback (set WorkerReportsProgress = true; in the constructor), and you can also add a custom event to report errors, if that is necessary:
// create a custom EventArgs class that provides the information you need
public sealed class MyEventArgs : EventArgs {
// Add information about the file
}
// ... define the event in the worker class ...
public event EventHandler<MyEventArgs> ErrorOccured;
// ... call it in the worker class (if needed) ...
if(ErrorOccured != null) ErrorOccured(this, new MyEventArgs(/*...*/));

Access return value from Thread.Start()'s delegate function

I've got a program that executes a method through a Thread.Start. The method has a return value that I'd like to get access to. Is there a way to do this? Here's a sampling...
var someValue = "";
Thread t = new Thread(delegate() { someValue = someObj.methodCall(); });
t.Start();
while (t.isAlive) Thread.Sleep(1000);
// Check the value of someValue
So once the while loop ends, the someValue should be set - but because it's executed in another thread it doesn't get set. Is there a simple way to get access to it?
When the caller and the threaded method share a variable, you already have access to it - once the thread has completed, you just check someValue.
Of course, you have to know when the threaded method is complete for this to be useful. At the bottom, there are two ways to do this:
Send a callback into the threaded method that it can execute when it's finished. You can pass your callback method someValue. You can use this technique if you don't care when the callback executes.
Use a WaitHandle of some kind (or Thread.Join). These tell you when a resource is ready or an event has completed. This technique is useful if you want to start a thread, do something else, then wait until the thread completes before proceeding. (In other words, it's useful if you want to sync back up with the thread, just not right away.)
I can't recreate your issue, I've got the same code and I'm seeing the expected result. If you're just going to sleep the current thread until it's complete you could just call .Join() on the thread and wait to be sure it's done executing.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
string someValue = "";
private void Form1_Load(object sender, EventArgs e)
{
Thread t = new Thread(delegate() { someValue = "asdf"; });
t.Start();
t.Join();
//while (t.IsAlive) Thread.Sleep(1000);
System.Diagnostics.Debug.Print(someValue);
}
}
One of possible methods to return a value from a Thread is to use a context class as a parameter object. It can be used to pass parameters and retrieve the result as well.
If on the other hand you could use a BackgroundWorker class, it has already a dedicated Result object - that works the same way. But BackgroundWorker cannot be used for some purposes (for instance, it doesn't support STA Apartment State).
Keep in mind that you shouldn't read from ctx.Result until the thread is finished (i.e. t.IsAlive == false).
void runThread()
{
ThreadContext ctx = new ThreadContext();
ctx.Value = 8;
Thread t = new Thread(new ParameterizedThreadStart(MyThread));
//t.SetApartmentState(ApartmentState.STA); // required for some purposes
t.Start(ctx);
// ...
t.Join();
Console.WriteLine(ctx.Result);
}
private static void MyThread(object threadParam)
{
ThreadContext context = (ThreadContext)threadParam;
context.Result = context.Value * 4; // compute result
}
class ThreadContext
{
public int Value { get; set; }
public int Result { get; set; }
}
You can retrieve data from Thread function using delegate callback. The delegate can serve as a bridge between thread and the caller. For example:
public delegate void DelReturnValue(string value);
public class SayHello
{
private string _name;
private DelReturnValue _delReturnValue;
public SayHello(string name, DelReturnValue delReturnValue)
{
_name = name;
_delReturnValue = delReturnValue;
}
public void SayHelloMethod()
{
_delReturnValue(_name);
}
}
public class Caller
{
private static string _returnedValue;
public static void ReturnValue(string value)
{
_returnedValue = value;
}
public static void Main()
{
DelReturnValue delReturnValue=new DelReturnValue(ReturnValue);
SayHello sayHello = new SayHello("test", delReturnValue);
Thread newThread = new Thread(new ThreadStart(sayHello.SayHelloMethod));
newThread.Start();
Thread.Sleep(1000);
Console.WriteLine("value is returned: " + _returnedValue);
}
}
Have a look at the Asynchronous Programming Model.
In one of the common patterns the model describes, your class will expose BeginXXX and EndXXX methods. The former starts the asynchronous operation and returns an IAsyncResult object. The latter accepts the IAsyncResult object as an argument, blocks the calling thread until the operation is complete and returns the required value.

Categories