C# Call a showdialog inside backgroundworker from a Class library [duplicate] - c#

I am working on a VS project/solution that is used by different applications. My job is to refactor the project and change it from using xxxAsync method to using BeginInvoke.
I came up to something similar to the following code:
public class AsyncTestModel {
private delegate string DoTaskDelegate();
public static EventHandler<TaskCompletedEventArgs> OnTaskCompleted;
public static void InvokeTask() {
DoTaskDelegate taskDelegate = Task;
taskDelegate.BeginInvoke(new AsyncCallback(TaskCallback), null);
}
private static string Task() {
Thread.Sleep(5000);
return "Thread Task successfully completed.";
}
private static void TaskCallback(IAsyncResult ar) {
string result = ((DoTaskDelegate)((System.Runtime.Remoting.Messaging.AsyncResult)ar).AsyncDelegate).EndInvoke(ar);
if (OnTaskCompleted != null) {
OnTaskCompleted(null, new TaskCompletedEventArgs(result));
}
}
}
public class TaskCompletedEventArgs : EventArgs {
private string _message;
public TaskCompletedEventArgs(string message) : base() {
_message = message;
}
public string Message {
get {
return _message;
}
}
}
I've tested this on a new UI project I've created. The UI project contains a button and a label controls. The UI has the following code:
private void button1_Click(object sender, EventArgs e) {
AsyncTestModel.OnTaskCompleted += OnTaskCompleted;
AsyncTestModel.InvokeTask();
}
private void OnTaskCompleted(object sender, TaskCompletedEventArgs e) {
UpdateLabel(e.Message);
}
private void UpdateLabel(string message) {
this.label1.Text = message;
}
After running this, I've encountered the cross-thread exception saying the the control 'label1' is being accessed from other thread aside the thread that it was created.
Is there a way for me to invoke the OnTaskCompleted event handler on the same thread that calls the BeginInvoke method? I know I could just use the form's InvokeRequired and call the form's BeginInvoke like the following:
private delegate void DoUpdateLabelDelegate(string message);
private void UpdateLabel(string message) {
if (this.InvokeRequired) {
IAsyncResult ar = this.BeginInvoke(new DoUpdateLabelDelegate(UpdateLabel), message);
this.EndInvoke(ar);
return;
}
this.label1.Text = message;
}
But the solution above will require me to ask and apply that solution to the other development team handling applications that uses my project/solution. Those other developers shouldn't be required to know that the methods hooked to the event handler are running from different thread.
Thanks, in advance.

As designed, no, you have absolutely no idea which thread is the one on which the client's UI runs.
You can arbitrarily demand that your InvokeTask() is to be called from that UI thread. Now you know, you can copy SynchronizationContext.Current in the InvokeTask() method and, later, call its Post() or Send() method to call a method that fires the event. This is the pattern used by, for example, BackgroundWorker and async/await. Do note that copying the Current property is required to make this work, don't skip it.
That of course still won't work when your InvokeTask() method is not called from the UI thread, you'll see that Synchronization.Current is null and have no hope to marshal the call. If that's a concern then you could expose a property of type ISynchronizeInvoke, call it SynchronizingObject. Now it is up to the client code to make the call, they'll have no trouble setting the property, they'll simply assign this in their form class constructor. And you use the property's Post or Send method to call the method that raises the event. This is the pattern used by for example the Process and FileSystemWatcher classes. Don't use it if you expect your library to be used by non-Winforms client apps, unfortunately later GUI libraries like WPF and Silverlight don't implement the interface. Otherwise the exact same problem with approaches like calling Control.Begin/Invoke() yourself.

try to use this, maybe it can help you.
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
//Do something...
});

Related

Using Control.Invoke in an optimal way

I have started a typical windows forms project (c#) with visual studio. I'm using a BackgroundWorker to fill up a TreeView control and display current progress for user. I have to use a Control.Invoke method to get access for the my TreeView control's methods (like TreeView.Nodes.Add(string ...) ). I have two questions.
Is it possible to "automatically" get reference to the object which invoke delegate method? For example, when I call myTree.Invoke(tbu, new object[] {myTree}) , I send a myTree object as an argument for the method. Is it the only possible way or I can do it in a someway like EventHandlers do (like an "Object sender" argument)?
And what is the best practice: to declare a class method used for delegate as static (TreeBU in this code), or as I have done below - Declare a static public variable for MainForm object and then use it when initialize a delegate object ( TreeStart tbu = Program.thisForm.TreeBU )?
Sorry for my c# and english, and thanks in advance!
namespace SmartSorting
{
public delegate void TreeStart(TreeView xmasTree);
static class Program
{
public static MainForm thisForm;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
thisForm = new MainForm();
Application.Run(thisForm);
}
}
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
treeView1.Nodes.Clear();
backgroundWorker1.RunWorkerAsync(treeView1);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker1 = (BackgroundWorker) sender;
e.Result = stage1(worker1, (TreeView)e.Argument);
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null) MessageBox.Show(e.Error.Message);
}
private bool stage1(BackgroundWorker wrkr, TreeView myTree)
{
TreeStart tbu = Program.thisForm.TreeBU;
myTree.Invoke(tbu, new object[] {myTree});
return true;
}
public void TreeBU (TreeView xmasTree)
{
xmasTree.BeginUpdate();
}
}
}
You usually assign a delegate by directly passing it a function (which must match the delegate signature!):
MyCrossThreadDelegateInstance += invokeMe;
or
new MyCrossThreadDelegate(invokeMe);
Check this:
Youre on different thread and would like to update the TreeControl using your invokeMe() method.
private void invokeMe()
{
MyTree.BeginUpdate();
}
Due to this call on MyTree.BeginUpdate() is coming from a different thread, crossthread exception is thrown.
To prevent this we modify our invokeMe() method to avoid throwing the exception:
private void invokeMe()
{
if (MyTree.InvokeRequired)
MyTree.Invoke(new CrossThreadDelegate(invokeMe);
else
MyTree.BeginUpDate();
}
Before invoking u check if invoke is required - this is the case when u try to access a control from a different thread then the one the control was created on. This way it tries to find the thread which owns and created the control by bubbling up you thread tree.
If Control.InvokeRequired returns true, the same method (passed over by the delegate) is called again from the next thread. This is repeated until the owning thread is found. Now Control.InvokeRequired returns false and your ELSE-block is executed on the proper thread whithout throwing a crossthread exception.
For more details see MSDN Control.Invoke
There is no need to declare anything static except you want your delegate to be available in a global scope.
Edit: If you would use the BackgroundWorker like it was meant to be, the ProgressChanged event would do the job since this event is risen on the proper thread (UI thread). This event is fired by calling the BackgroundWorker.ReportProgress() member. See MSDN - BackgroundWorker class for more details

Creating a thread to handle events for a particular class

I have a WPF application and I need to listen to, and handle events for the lifetime of the application for a certain class.
Is it bad practice to create a wrapper class, create a static instance of it and call "StartListening()"? What if an unhanded exception happens on this static instance? Will it tear down the entire application as it would in an ASP.NET application?
Should I QueueUserWorkItem, create the class, attach events, and then put some kind of while(true){} statement to keep the thread alive?
What is the best practice?
To me this seems like a classic publisher/listener problem.
I would create an interface: IMyClassNameEventListener and make MyClass take an instance of it as a constructor parameter. Then in the constructor I would call the Attach(MyClass obj) method on the interface instance. Of course, the listener would have a singleton lifecycle, it doesn't need to be static.
A slightly better approach would be to use a factory to create instances of MyClass which would then do the attaching, so the Attach call and the dependency are out of the constructor.
Wether the app would fail would be dependent on how you start the listener. You can look into the TaskFactory class, it provides options to handle exception propagation. How would you want the app to behave if the listener fails?
Of course in the listener object itself, you only need to have code run when there is something to handle. So, when you receive an event, you startup a thread. You can use a queue of actions if you'd want to have only one thread running.
Inside the listener class, you might want to have something like the following:
private Queue<Action> ActionQueue = new Queue<Action>();
private object LockObj = new Object();
private volatile bool IsRunning;
public void Attach(Class1 obj)
{
obj.SomeEvent += this.HandleEvent;
}
private void HandleEvent(object sender, EventArgs e)
{
lock(this.LockObj)
{
this.ActionQueue.Enque(() => this.Handle(sender, e));
if (!this.IsRunning)
{
Task.Factory.StartNew(() => this.Loop() );
}
}
}
private void Loop()
{
this.IsRunning = true;
while ((Action action = this.DequeueAction()) != null)
action();
this.IsRunning = false;
}
private Action DequeueAction()
{
lock (this.LockObj)
{
return this.ActionQueue.Count > 0 ? this.ActionQueue.Dequeue() : null;
}
}
private void Handle(object sender, EventArgs e)
{
//handling code
}

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 ;)

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(/*...*/));

How can I call a method on a form from a method called from an external class from a backgroundWorker?

How can I call a method on a form from a method called from an external class from a backgroundWorker? I believe that delegates are somehow the answer to this question, but after spending time reading, I still am confused by this problem.
This is in Visual Studio 2008, the backgroundWorker is run from the form and calls ExternalClass.Method. The form is in namespace ProgramName and the ExternalClass is using ProgramName. When i declare public delegate MyDelegate in the namespace ProgramName in the file of my windows.form I can create an instance of MyDelegate and call it in a method of my form (but this does not help me), but if I try to create an instance of MyDelegate and call it from a method of my external class I cannot access the method of the windows.form, even though it is public.
thanks
yes, I want to pass progress reports (int percent, string status) back from ExternalClass.Method. Can you explain a bit more about that CSharpAtl (or anyone)?
Please do yourself a favor and read up on the BackgroundWorker Component, especially "How to: Implement a Form That Uses a Background Operation".
Other resources:
Windows Client Development Portal
Using the BackgroundWorker Control (video)
Windows Forms Videos
The main thing to realize is that you actually have two levels of synchronization going on here: between the Form and the BackgroundWorker, and between the BackgroundWorker and the ExternalClass object.
The Form is asynchronously invoking BackgroundWorker.DoWork(), which is running in another thread. Any updates to the Form should come through Form.Invoke() (which fires an arbitrary delegate in the Form's thread) or, better yet, through the BackgroundWorker.ProgressChanged event (which fires a specific event in the Form's thread).
So what you want to do is proxy the status updates from the ExternalClass method back to the BackgroundWorker, which will in turn push them on to the Form. One way I've done this in the past is to use a callback delegate:
public delegate void ProgressCallback(double percentCompleted, string status);
And have my expensive worker method take the callback as an argument:
public void ExpensiveMethod(ProgressCallback callback) {
while(doingThings) {
if(callback != null) callback(percentDone, statusString);
}
}
Then in your BackgroundWorker class, define a method that matches your callback delegate, and have it call BackgroundWorker.ReportProgress() to trigger the BackgroundWorker.ProgressChanged event, which can in turn update your Form's state.
Update: this is basically the same as the solution Henk Holterman suggested in his new edit.
Note that your question (afaik) is not just about the backgroundwiorker but just as much about how to break a circular reference between classes. This is a standard problem with a standard solution.
You can pass a delegate (referring to a Form-method) around just as any object so also to a Backgroundworker. And the Bgw can pass it to the external method. A delegate includes a reference to the object (in this case the Form).
Note that since you are on another thread you will need to use Control.Invoke inside the delegate, or use the Bgw ReportProgress event.
public partial class Form1 : Form
{
private void ReportProgresshandler(int percent, string state)
{
backgroundWorker1.ReportProgress(percent); // also does the Invoke
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var ex = new ExampleClass();
ex.Dowork(ReportProgresshandler);
}
}
and something like
class ExampleClass
{
delegate void ReportDelegate(int percent, string status);
public void Dowork(ReportDelegate report)
{
report(0, "starting");
}
}
I'm not sure what the trouble is. And also you can use a delegate, but don't need one.
using System.Windows.Forms;
using System.ComponentModel;
public partial class ExampleForm : Form
{
public ExampleForm()
{
InitializeComponent();
var worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(doWork);
worker.RunWorkerAsync(this);
}
void doWork(object sender, DoWorkEventArgs e)
{
ExampleForm f = e.Argument as ExampleForm;
f.Hello();
}
private void Hello()
{
}
}

Categories