This is part of my code snippet.
I want to pass a callback function into test().
therefore, after calling the "del" delegate, the callback() can be trigger automatically?
Functions:
butOK_Click() //when click the button, disable it
test() //a wrapper function calling updateUI function
updateUI() // a long process function
callback() // a callback function enabling the button back
How can i do this?
Thanks
public delegate void updateUIDelegate(bool refresh);
public delegate void asyncCallback();
//...
void butOK_Click(object sender, EventArgs e) {
butOK.Enabled = false;
test();
}
public void updateUI() {
// long function....doing 10s
}
public void callback() {
butOK.Enabled = true;
}
public void test() {
updateUIDelegate del = new updateUIDelegate(updateUI);
del.BeginInvoke(null,null);
//??????????
}
Plesse, try the following:
void button1_Click(object sender, EventArgs e) {
button1.Enabled = false;
BeginAsyncOperation(updateUI);
}
void BeginAsyncOperation(Action operation) {
operation.BeginInvoke(OnAsyncCallback, null);
}
void OnAsyncCallback(IAsyncResult result) {
if(result.IsCompleted) {
if(!InvokeRequired)
callback();
else BeginInvoke(new Action(callback));
}
}
//
public void callback() {
button1.Enabled = true;
// something else
}
public void updateUI() {
// long function....doing 10s
System.Threading.Thread.Sleep(10000);
}
Please also take a look at the following article: Calling Synchronous Methods Asynchronously
You can pass a delegate to a function as a parameter. So add a parameter to your method 'Test' of type 'asyncCallback'. Then in the 'test' method you can just call the delegate method passed in.
Here is some sample code:
class MyClass {
public delegate void updateUIDelegate(bool refresh);
public delegate void asyncCallback();
private void butOK_Click(object sender, EventArgs e)
{
butOK.Enabled = false;
test(new asyncCallback(callback));
}
public void updateUI(bool refresh)
{
// long function....doing 10s
}
public void callback()
{
butOK.Enabled = true;
}
public void test(asyncCallback callbackMethod)
{
updateUIDelegate del = new updateUIDelegate(updateUI);
del.BeginInvoke(true, null, null);
if(callbackMethod != null) callback();
}
}
Not sure whether I understand correctly, but I think you want to re-enable the butOK button after updating the UI. If so, there are two solutions.
1) You may modify
updateUIDelegate del = new updateUIDelegate(updateUI);
into
var del = new Action(() => { updateUI(); callback(); });
I change updateUIDelegate into var here because the definition of updateUI actually doesn't match updateUIDelegate.
2) Refactor callback() to match the definition of AsyncCallback, and pass it as the parameter of BeginInvoke(). That is,
BeginInvoke(callback, null);
This is more elegant or official usage of BeginInvoke, but may require more efforts to refactor the code.
Related
Hello I have packed my standard code in a class dll. I am calling this dll from my C# service apps. But in the dll,at one point, there should be called a method with fixed name "func_X" that is not standard and has to be defined by the dll caller app. How can I realise this?
The challanging point is that the func_X is not called at a fix point in my dll. According to the flow, it is called at a different point.
My service where I call the dll
using Concheetah_Class; // my dll
namespace Concheetah_Service_Bahmuller
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Concheetah_Class.Main_Prog main_Prog = new Concheetah_Class.Main_Prog();
main_Prog.Main_Start(); // starting point of my dll
}
public void func_X()
{
// some supplementary code
}
}
}
My dll code
public void Main_Start()
{
// some long code
func_X(); // Here I should call the method that has to be defined on the caller side
// some long code
}
Update-1 My dll code
System.Timers.Timer timer1 = new System.Timers.Timer();
public void Main_Start()
{
Initialize_timer1();
}
public void Initialize_timer1()
{
timer1.Elapsed += new ElapsedEventHandler(OnTimedEvent_timer1);
timer1 = 35;
timer1.Start();
}
private void OnTimedEvent_timer1(object sender, EventArgs e)
{
//some code
func_x();
}
You will to need pass the function to your dll program.
Update according to your latest edit:
Approach 1: You can pass your function to this constructor of Main_Prog and store it in a variable.
public class Main_Prog
{
System.Timers.Timer timer1 = new System.Timers.Timer();
Action func_x;
public Main_Prog(Action func_x)
{
this.func_x = func_x;
Initialize_timer1();
}
public void Initialize_timer1()
{
timer1.Elapsed += new ElapsedEventHandler(OnTimedEvent_timer1);
timer1.Interval = 35;
timer1.Start();
}
private void OnTimedEvent_timer1(object sender, EventArgs e)
{
this.func_x();
}
}
Approach 2: Instead of storing it globally pass the function to OnTimedEvent:
public class Main_Prog
{
System.Timers.Timer timer1 = new System.Timers.Timer();
public Main_Prog(Action func_x)
{
Initialize_timer1(func_x);
}
public void Initialize_timer1(Action func_x)
{
timer1.Elapsed += (sender, args) => OnTimedEvent_timer1(sender, args, func_x);
timer1.Interval = 35;
timer1.Start();
}
private void OnTimedEvent_timer1(object sender, EventArgs e, Action func_x)
{
func_x();
}
}
In your Service1 pass func_x as an argument.
protected override void OnStart(string[] args)
{
Concheetah_Class.Main_Prog main_Prog = new Concheetah_Class.Main_Prog();
main_Prog.Main_Start(func_X);
}
In your Main_Prog receive it as an Action.
public void Main_Start(Action func_X)
{
func_X();
}
Depending on your need you can switch between Func & Action.
Action is used when the return type is void and Func is used when return type is not void.
I am not sure if I understand your question correctly but if I can take a stab at it, from what I am understanding you would like to create a method in your caller code than needs to be invoked by the code in your the dll that has already been build?
If so, I would use delegates to achieve this. You can add a parameter to your Main_Start method that accepts either a Action (void method) or Func (method with return type)
Example:
public class ActionExample // Delegate with NO return type
{
public void Run()
{
Main_Start(PrintName);
}
public void PrintName(string name)
{
Console.WriteLine($"My name is: {name}");
}
// Code in your packaged dll
// the string value in the generics represents the input value of the method
public void Main_Start(Action<string> methodToRun)
{
methodToRun("John Doe");
}
}
public class FuncExample // Delegate WITH return type
{
public void Run()
{
Main_Start(GetHelloMessage);
}
public string GetHelloMessage(string name)
{
return $"My name is: {name}";
}
// Code in your packaged dll
// First string in the generics represents input paramater and last string represents return paramater of the method
public void Main_Start(Func<string, string> methodToRun)
{
string message = methodToRun("John Doe");
Console.WriteLine(message);
}
}
i am having trouble creating a callback on a newly started thread.
I have 2 classes, an API, and the Form.cs. I start a thread running a method in API, from Form.cs, i want to notify a method in Form.cs from inside the method in API.
I am familiar with delegation in Obj-C, but not in C#.
I only included the relevant code.
public partial class Main: Form
{
private Api Connect = new Api();
private void StartStopButton_Click(object sender, EventArgs e)
{
//new thread
Thread ThreadConnect = new Thread(Connect.startAttemptingWithUsername);
ThreadConnect.Start();
}
public void AttemptingWithPasswordMessage(string password)
{
// i want to notify this method from the API
}
}
class Api : UserAgent
{
public void startAttemptingWithUsername()
{
_shouldStop = false;
while (!_shouldStop)
{
Console.WriteLine(username);
// How would i notify AttemptingWithPasswordMessage from here?
System.Threading.Thread.Sleep(1000);
}
}
}
Provide an event to your other class, and fire that event whenever it is relevant based on the processing:
class Api : UserAgent
{
public event Action<string> SomeEvent;//TODO give better name
public void startAttemptingWithUsername()
{
_shouldStop = false;
while (!_shouldStop)
{
Console.WriteLine(username);
var handler = SomeEvent;
if (handler != null)
handler("asdf");
// How would i notify AttemptingWithPasswordMessage from here?
System.Threading.Thread.Sleep(1000);
}
}
}
Then add a handler for that event: (And marshal back to the UI thread)
private void StartStopButton_Click(object sender, EventArgs e)
{
//new thread
Thread ThreadConnect = new Thread(Connect.startAttemptingWithUsername);
ThreadConnect.Start();
Connect.SomeEvent += (data) => Invoke(
new Action(()=>AttemptingWithPasswordMessage(data)));
}
I have an app that has several methods that take a long time to complete. I am using a backgroundworker to run these methods and keep my UI responsive. My methods look something like
public void DoSomething()
{
while( HaveMoreWork )
{
// do work
}
}
Now i want the UI to be able to cancel this at any time so I have changed my methods to take a Backgroundworker like so
public void DoSomething(Backgroundworker worker)
{
while( HaveMoreWork && !worker.CancelationPending )
{
// do work
}
}
My question is, is there a better way to do this. Seems like passing a Backgroundwoker as an argument to all these methods is a bit messy. What is best practice for this?
I am using global variable
private BackgroundWorker _bwSearch = new BackgroundWorker();
private void InitializeBackgroundWorker()
{
_bwSearch = new BackgroundWorker();
_bwSearch.WorkerSupportsCancellation = true;
_bwSearch.DoWork += bwSearch_DoWork;
_bwSearch.RunWorkerCompleted += bwSearch_RunWorkerCompleted;
}
when clicked on stop button
private void btnCancel_Click(object sender, EventArgs e)
{
_bwSearch.Abort();
}
Updated:
Also I am using this simple helper class that is inherited from BackgroundWorker
public class AbortableBackgroundWorker : BackgroundWorker
{
private Thread _workerThread;
protected override void OnDoWork(DoWorkEventArgs e)
{
_workerThread = Thread.CurrentThread;
try
{
base.OnDoWork(e);
}
catch (ThreadAbortException)
{
e.Cancel = true;
Thread.ResetAbort();
}
}
public void Abort()
{
if (_workerThread != null)
{
_workerThread.Abort();
_workerThread = null;
}
}
}
public class DoSomethingService
{
private volatile bool _stopped = false;
public void Start(object socketQueueObject)
{
while (!_stopped)
{
...
}
}
public void Stop()
{
_stopped = true;
}
}
...
var doSomethingService = DoSomethingService();
doSomethingService.Start();
...
doSomethingService.Stop();
I have an external library which has a method which performs a long running task on a background thread. When it's done it fires off a Completed event on the thread that kicked off the method (typically the UI thread). It looks like this:
public class Foo
{
public delegate void CompletedEventHandler(object sender, EventArgs e);
public event CompletedEventHandler Completed;
public void LongRunningTask()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(5000);
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (Completed != null)
Completed(this, EventArgs.Empty);
}
}
The code that calls this library looks like this:
private void button1_Click(object sender, EventArgs e)
{
Foo b = new Foo();
b.Completed += new Foo.CompletedEventHandler(b_Completed);
b.LongRunningTask();
Debug.WriteLine("It's all done");
}
void b_Completed(object sender, EventArgs e)
{
// do stuff
}
How do I unit test the call to .LongRunningTask given that it returns data in an event?
I'm not sure if I got it right. Do you want to check the external library if it fires the event? Or do you want to check that you do something particularly if the event is fired?
If it is the latter, I would use a mock for that. The problem is though, that your code seems to be hard to test, because you're doing logical stuff in the user interface. Try to write a "passive" view, and let a presenter do the magic. For example by using the Model View Presenter pattern http://msdn.microsoft.com/en-us/magazine/cc188690.aspx
The whole thing would then look like this.
The Model
public class Model : IModel
{
public event EventHandler<SampleEventArgs> Completed;
public void LongRunningTask()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += this.bw_DoWork;
bw.RunWorkerCompleted += this.bw_RunWorkerCompleted;
bw.RunWorkerAsync();
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (this.Completed != null)
{
this.Completed(this, new SampleEventArgs {Data = "Test"});
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(5000);
}
}
The View
public Form1()
{
InitializeComponent();
}
public event EventHandler Button1Clicked;
public void Update(string data)
{
this.label1.Text = data;
}
private void Button1Click(object sender, EventArgs e)
{
if (this.Button1Clicked != null)
{
this.Button1Clicked(this, EventArgs.Empty);
}
}
The Presenter
public class Presenter
{
private readonly IForm1 form1;
private readonly IModel model;
public Presenter(IForm1 form1, IModel model)
{
this.form1 = form1;
this.model = model;
this.form1.Button1Clicked += this.Form1Button1Clicked;
this.model.Completed += this.ModelCompleted;
}
private void ModelCompleted(object sender, SampleEventArgs e)
{
this.form1.Update(e.Data);
}
private void Form1Button1Clicked(object sender, EventArgs e)
{
this.model.LongRunningTask();
}
}
Somewhere you assemble it (e.g. in the Program class)
var form = new Form1();
var model = new Model();
var presenter = new Presenter(form, model);
Application.Run(form);
And then you can easily just test the presenter in an unit test. The part in the gui is now little enough to not be tested.
The possible test could look like this
[Test]
public void Test()
{
var form1Mock = new Mock<IForm1>();
var modelMock = new Mock<IModel>();
var presenter = new Presenter(form1Mock.Object, modelMock.Object);
modelMock.Setup(m => m.LongRunningTask()).Raises(m => m.Completed += null, new SampleEventArgs() { Data = "Some Data" });
form1Mock.Raise(f => f.Button1Clicked += null, EventArgs.Empty);
form1Mock.Verify(f => f.Update("Some Data"));
}
Well, I believe BackgroundWorker uses the current SynchronizationContext. You could potentially implement your own subclass of SynchronizationContext to allow you more control (possibly even running code on the same thread, although that will break anything which depends on it running in a different thread) and call SetSynchronizationContext before running the test.
You'd need to subscribe to the event in your test, and then check whether or not your handler was called. (Lambda expressions are good for this.)
For example, suppose you have a SynchronizationContext which lets you run all the work only when you want it to, and tell you when it's done, your test might:
Set the synchronization context
Create the component
Subscribe to the handler with a lambda which sets a local variable
Call LongRunningTask()
Verify that the local variable hasn't been set yet
Make the synchronization context do all its work... wait until it's finished (with a timeout)
Verify that the local variable has now been set
It's all a bit nasty, admittedly. If you can just test the work it's doing, synchronously, that would be a lot easier.
You can create an extension method that can help with turning it into a synchronous call. You can make tweaks like making it more generic and passing in the timeout variable but at least it will make the unit test easier to write.
static class FooExtensions
{
public static SomeData WaitOn(this Foo foo, Action<Foo> action)
{
SomeData result = null;
var wait = new AutoResetEvent(false);
foo.Completed += (s, e) =>
{
result = e.Data; // I assume this is how you get the data?
wait.Set();
};
action(foo);
if (!wait.WaitOne(5000)) // or whatever would be a good timeout
{
throw new TimeoutException();
}
return result;
}
}
public void TestMethod()
{
var foo = new Foo();
SomeData data = foo.WaitOn(f => f.LongRunningTask());
}
For testing asynchronous code I use a similar helper:
public class AsyncTestHelper
{
public delegate bool TestDelegate();
public static bool AssertOrTimeout(TestDelegate predicate, TimeSpan timeout)
{
var start = DateTime.Now;
var now = DateTime.Now;
bool result = false;
while (!result && (now - start) <= timeout)
{
Thread.Sleep(50);
now = DateTime.Now;
result = predicate.Invoke();
}
return result;
}
}
In the test method then call something like this:
Assert.IsTrue(AsyncTestHelper.AssertOrTimeout(() => changeThisVarInCodeRegisteredToCompletedEvent, TimeSpan.FromMilliseconds(500)));
When you subscribe to an event on an object from within a form, you are essentially handing over control of your callback method to the event source. You have no idea whether that event source will choose to trigger the event on a different thread.
The problem is that when the callback is invoked, you cannot assume that you can make update controls on your form because sometimes those controls will throw an exception if the event callback was called on a thread different than the thread the form was run on.
To simplify Simon's code a bit, you could use the built in generic Action delegate. It saves peppering your code with a bunch of delegate types you don't really need. Also, in .NET 3.5 they added a params parameter to the Invoke method so you don't have to define a temporary array.
void SomethingHappened(object sender, EventArgs ea)
{
if (InvokeRequired)
{
Invoke(new Action<object, EventArgs>(SomethingHappened), sender, ea);
return;
}
textBox1.Text = "Something happened";
}
Here are the salient points:
You can't make UI control calls from a different thread than the one they were created on (the form's thread).
Delegate invocations (ie, event hooks) are triggered on the same thread as the object that is firing the event.
So, if you have a separate "engine" thread doing some work and have some UI watching for state changes which can be reflected in the UI (such as a progress bar or whatever), you have a problem. The engine fire's an object changed event which has been hooked by the Form. But the callback delegate that the Form registered with the engine gets called on the engine's thread… not on the Form's thread. And so you can't update any controls from that callback. Doh!
BeginInvoke comes to the rescue. Just use this simple coding model in all your callback methods and you can be sure that things are going to be okay:
private delegate void EventArgsDelegate(object sender, EventArgs ea);
void SomethingHappened(object sender, EventArgs ea)
{
//
// Make sure this callback is on the correct thread
//
if (this.InvokeRequired)
{
this.Invoke(new EventArgsDelegate(SomethingHappened), new object[] { sender, ea });
return;
}
//
// Do something with the event such as update a control
//
textBox1.Text = "Something happened";
}
It's quite simple really.
Use InvokeRequired to find out if this callback happened on the correct thread.
If not, then reinvoke the callback on the correct thread with the same parameters. You can reinvoke a method by using the Invoke (blocking) or BeginInvoke (non-blocking) methods.
The next time the function is called, InvokeRequired returns false because we are now on the correct thread and everybody is happy.
This is a very compact way of addressing this problem and making your Forms safe from multi-threaded event callbacks.
I use anonymous methods a lot in this scenario:
void SomethingHappened(object sender, EventArgs ea)
{
MethodInvoker del = delegate{ textBox1.Text = "Something happened"; };
InvokeRequired ? Invoke( del ) : del();
}
I'm a bit late to this topic, but you might want to take a look at the Event-Based Asynchronous Pattern. When implemented properly, it guarantees that events are always raised from the UI thread.
Here's a brief example that only allows one concurrent invocation; supporting multiple invocations/events requires a little bit more plumbing.
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public class MainForm : Form
{
private TypeWithAsync _type;
[STAThread()]
public static void Main()
{
Application.EnableVisualStyles();
Application.Run(new MainForm());
}
public MainForm()
{
_type = new TypeWithAsync();
_type.DoSomethingCompleted += DoSomethingCompleted;
var panel = new FlowLayoutPanel() { Dock = DockStyle.Fill };
var btn = new Button() { Text = "Synchronous" };
btn.Click += SyncClick;
panel.Controls.Add(btn);
btn = new Button { Text = "Asynchronous" };
btn.Click += AsyncClick;
panel.Controls.Add(btn);
Controls.Add(panel);
}
private void SyncClick(object sender, EventArgs e)
{
int value = _type.DoSomething();
MessageBox.Show(string.Format("DoSomething() returned {0}.", value));
}
private void AsyncClick(object sender, EventArgs e)
{
_type.DoSomethingAsync();
}
private void DoSomethingCompleted(object sender, DoSomethingCompletedEventArgs e)
{
MessageBox.Show(string.Format("DoSomethingAsync() returned {0}.", e.Value));
}
}
class TypeWithAsync
{
private AsyncOperation _operation;
// synchronous version of method
public int DoSomething()
{
Thread.Sleep(5000);
return 27;
}
// async version of method
public void DoSomethingAsync()
{
if (_operation != null)
{
throw new InvalidOperationException("An async operation is already running.");
}
_operation = AsyncOperationManager.CreateOperation(null);
ThreadPool.QueueUserWorkItem(DoSomethingAsyncCore);
}
// wrapper used by async method to call sync version of method, matches WaitCallback so it
// can be queued by the thread pool
private void DoSomethingAsyncCore(object state)
{
int returnValue = DoSomething();
var e = new DoSomethingCompletedEventArgs(returnValue);
_operation.PostOperationCompleted(RaiseDoSomethingCompleted, e);
}
// wrapper used so async method can raise the event; matches SendOrPostCallback
private void RaiseDoSomethingCompleted(object args)
{
OnDoSomethingCompleted((DoSomethingCompletedEventArgs)args);
}
private void OnDoSomethingCompleted(DoSomethingCompletedEventArgs e)
{
var handler = DoSomethingCompleted;
if (handler != null) { handler(this, e); }
}
public EventHandler<DoSomethingCompletedEventArgs> DoSomethingCompleted;
}
public class DoSomethingCompletedEventArgs : EventArgs
{
private int _value;
public DoSomethingCompletedEventArgs(int value)
: base()
{
_value = value;
}
public int Value
{
get { return _value; }
}
}
}
As the lazy programmer, I have a very lazy method of doing this.
What I do is simply this.
private void DoInvoke(MethodInvoker del) {
if (InvokeRequired) {
Invoke(del);
} else {
del();
}
}
//example of how to call it
private void tUpdateLabel(ToolStripStatusLabel lbl, String val) {
DoInvoke(delegate { lbl.Text = val; });
}
You could inline the DoInvoke inside your function or hide it within separate function to do the dirty work for you.
Just keep in mind you can pass functions directly into the DoInvoke method.
private void directPass() {
DoInvoke(this.directInvoke);
}
private void directInvoke() {
textLabel.Text = "Directly passed.";
}
In many simple cases, you can use the MethodInvoker delegate and avoid the need to create your own delegate type.