Calling Invoke/BeginInvoke from a thread - c#

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

Related

Will several bindings of static/global Event handler to Events in a class, lead to a thread/memory leak?

I have a class with EventHandler bindings at the constructor, that will be instantiated thousand times within application lifecycle. The question is: Will this approach leads to memory/thread leaks?
I did this way (code below), because I need to be notified every time SomeMethod() runs, whatever instance run it. Foo class (the publisher) will be short-lived, however the handlers will live until the application closes.
I ask this because, when working with Windows Forms, each form can hold several event handlers/delegates and everything is fine because all those delegates are inside the form and will be disposed when the form closes. But how about static event handlers/delegates, that could be even on separate projects?
Will I need to write a destructor to detach those event handlers?
Should I go with Weak Event Pattern?
Restriction: I must do this with .NET 3.5. I know I could do this with TPL, setting a "Fire and Forget" Task.
Thank you in advance.
Code:
public class Foo
{
public event EventHandler SomeEvent;
public Foo()
{
SomeEvent += FooHandlers.Foo_SomeEvent1;
SomeEvent += FooHandlers.Foo_SomeEvent2;
}
public void RaiseEvents(EventHandler evt, EventArgs args)
{
var eventObj = evt;
var listeners = eventObj.GetInvocationList();
foreach (var listener in listeners)
{
var method = (EventHandler)listener;
ThreadPool.QueueUserWorkItem(callBack => method(this, args));
// Handlers will do a lot of things, so I don't want
// them blocking the Main thread
}
}
public void SomeMethod()
{
// do something here
RaiseEvents(SomeEvent, new EventArgs());
}
}
public static class FooHandlers
{
public static void Foo_SomeEvent1(object sender, EventArgs e)
{
//do something here
}
public static void Foo_SomeEvent2(object sender, EventArgs e)
{
//do something different here
}
}
Since your handlers are static methods the delegate you're adding to the event doesn't have an object instance, so there is no object instance being kept alive for the duration of the object with the event.
And even if you did use an object instance to attach the handler, it wouldn't be a problem, because the object with the event is short lived. The only time there is a problem is when the object with the event is long lived, and the object that has a handler to itself assigned is short lived, and consumes a lot of resources to keep alive.

making a cross-thread call to hide a form visual c#

Update: Solution arrived since and is now accepted. Due to the clarity of the pseudo codes on this question the solution took only a few seconds. Trying to figure out the solution from the other seemingly "duplicate" questions took a lot of time already. I had the solution in 20 minutes from the moment I asked this question. So it is not a duplicate, probably the clearest of them all to date.
While several similar questions have been asked on this, I was still not able to put together a working code from them. My main application is not on a form, but in a separate class that is a plugin and executed by a host application.
So while it seems a duplicate question it is not. Please read on.
I have my main class doing stuff. Then I have a form that displays information to the user. I need to hide this form when the user switches away from the application (host application loses focus).
I am using very limited APIs so the only methods I have at my disposal events triggered by the host application.
I created a timer that fires every 100ms and checks whether the user had the application in focus. And if not a command is sent to the form to hide itself.
The reason for this approach is because the host application loosing focus is just one of the many scenarios that I need to hide the form and I need to channel all these through the same exact method.
All works from within the rest of the classes (the Hide() method is called from the rest of the application no problem.
But it does not work when the timer calls the Hide() method, because the timer is on a different thread when it fires. So the call becomes a cross-thread call.
The very specific question is that I need an exact sample code how to make this call from the timer event handler to the form's Hide() method thread-safe with Invoke.
Thanks.
This is the timer:
private void Controllel_Opened(object sender, EventArgs e)
{
myTimer.Elapsed += new System.Timers.ElapsedEventHandler(DisplayTimeEvent);
myTimer.Interval = 50;
myTimer.Start();
}
public static System.Timers.Timer myTimer = new System.Timers.Timer();
// This method checks different scenarios when the tool tip should be hidden and calls the hiding method
public static void DisplayTimeEvent(object source, System.Timers.ElapsedEventArgs e)
{
FormHandler.Hide();
}
Then the "FormHandler" class:
public static class FormHandler
{
private static Form1 frm1 = new Form1();
public delegate void Form1HideEventHandler();
public static event Form1HideEventHandler Form1Hide;
public static void Hide()
{
if (Form1Hide != null)
{
Form1Hide();
}
}
}
Then the form's code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
FormHandler.Form1Hide += FormHandler_Form1Hide;
}
private void FormHandler_Form1Hide()
{
Hide();
}
}
I would like to get a solution with exact code if possible. Thanks.
private void FormHandler_Form1Hide()
{
if (InvokeRequired)
{
this.Invoke(new Action(() => { FormHandler_Form1Hide(); }));
}
else
{
Hide();
}
}
You need to use System.Windows.Forms.Timer instead. That will invoke back onto the dispatcher thread.

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

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

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

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