I am reviewing some code from a sample application for an API, and need some help better understanding the Action<T> delegation throughout the sample app. I have put several questions throughout the code. Any help is appreciated
The API is implemented in the Client.cs class, and when I make requests from the application, the API sends the responses to the functions in Client.cs that have been implemented.
/***** Client.cs *****/
public event Action<int, int, int> TickSize;
void tickSize(int tickerId, int field, int size)
{
var tmp = TickSize;
//What is the point of tmp, and why do we check if it is not null?
if (tmp != null)
//This invokes the Action? ie - fires the TickSize Action event?
tmp(tickerId, field, size);
}
Then the UI.cs class handles the UI interactions and feeding the information back into the UI so the user can see what data is returned
/***** UI.cs *****/
//Delegate to handle reading messages
delegate void MessageHandlerDelegate(Message message);
protected Client client;
public appDialog(){
InitializeComponent();
client = new Client();
.
.
//Subscribes the client_TickSize method to the client.TickSize action?
client.TickSize += client_TickSize;
}
void client_TickSize(int tickerId, int field, int size){
HandleMessage(new Message(ticketID, field, size));
}
public void HandleMessage(Message message){
//So, this.InvokeRequired checks if there is another thread accessing the method?
//Unclear as to what this does and its purpose
//What is the purpose of the MessageHandlerDelegate callback
// - some clarification on what is going on here would be helpful
if (this.InvokeRequired)
{
MessageHandlerDelegate callback = new MessageHandlerDelegate(HandleMessage);
this.Invoke(callback, new object[] { message });
}
else
{
UpdateUI(message);
}
}
private void UpdateUI(Message message) { handle messages }
From the docs
Events are a special kind of multicast delegate that can only be invoked from within the class or struct where they are declared (the publisher class). If other classes or structs subscribe to the event, their event handler methods will be called when the publisher class raises the event
So in Client.cs you have a multicast delegate called TickSize. This delegate enables other classes to subscribe to the event it is associated with. So in your function void tickSize(int tickerId, int field, int size), you want to let all the other subscribers know that a tick event has happened.
To do this, you first see if you have any subscribers. This is where the null check happens in if (tmp != null). Having tmp is not needed, you could have done if(TickSize != null) If you have any eventhandlers registered, it would fire and subscribers will receive that call. In your case, you do have subscribers because you are subscribing to the event in public AppDialog with this code : client.TickSize += client_TickSize;
So whenever void tickSize(...) is called in Client.cs, the code in void client_TickSize(...) will run. This will call HandleMessage which will check if it needs to be called by an Invoke function because calling code is not on UI thread. If it does need to be called using Invoke, it will then call the same message using current Control's Invoke function (Not sure which control, could be Form). The HandleMessage will then see that Invoke is not required because caller is on UI thread and then it will call UpdateUi which will update controls.
Related
I'm working on a software where software issues commands for hardware panel and once a command is issued, its response received after few seconds . there are different functions for different hardware commands like
public void FunctionA()
{
StartCommandA();
}
and other functions on the same pattern that will be used to run other commands.
FunctionB();
FunctionC();
Once we receive the response of command A , I invoke the other function from the response but this approach is not good as per design pattern practices.
All i want to do is to make a list of functions and invoke all these functions one after other, But next function will be called once i get response of first functions.
I tried this by using Multicast delegate but I'm unable to find out how we can call get the list of functions once i add all functions to that delegates. This is what i'm trying do since.
FunList funList_ConfigAndSerialTests = new FunList(StartSerialTest);
funList_ConfigAndSerialTests += StartSerialTest;
funList_ConfigAndSerialTests += StartMsrTest;
funList_ConfigAndSerialTests += StartContactLessTest;
//funList_ConfigAndSerialTests.Invoke();
Delegate[] del = funList_ConfigAndSerialTests.GetInvocationList();
foreach (Delegate item in funList_ConfigAndSerialTests.GetInvocationList())
{
while (true)
{
if (IsResponseReceived == true)
{
// Call function here
}
}
}
The simplest way to do this is to call the functions one by one:
FunctionA();
FunctionB();
FunctionC();
Each method will be called only after the previous has returned.
But you said you want to call the next function after the previous one has a response. Now that sounds like your functions run asynchronously. I strongly suggest you use the async keyword to mark your functions and make them return a Task<ResonseType>. You can learn about this here.
You'll then be able to do something like this:
await FunctionA(); // you obviously want to do something with the returned response
// I do not know your requirements so I did not show that part
await FunctionB();
await FunctionC();
It seems what you're trying to achieve is what Events are for. In the class, where the handlers (FunctionA, FunctionB, ...) are defined create an event instance as follows:
public class MyClass
{
private event Action Event;
public void RegisterHandlers()
{
Event += FuncA;
Event += FuncB;
Event();
}
public void HandleCommand()
{
this.Event();
}
private void FuncA() { /*...*/ }
private void FuncB() { /*...*/ }
}
The simple call to Events() will actually result in all the registered handlers to be invoked in the order they've been registered.
I'm quite new to C# and certainly OOP concepts.. so forgive the stupidity of my question.
I have a system I wish to communicate with, It has a number of commands that can be called with an associated response. (Communication is done via TCP/IP or Serial) (I implemented an Interface with SendMessage so that I can use multiple transport mechanisms)
I want to create a method for each command and then expose these, which is simple enough. The device also lets say 'broadcasts' messages as well which I want to act on, so I was using an event handler for this which works well..
At the moment in the event handler I catch OK and ERROR style messages, but ideally I would like to also be able to send the command from the above method and catch an error and return a bool value based on the command.
Can anyone think of a way I can do something like this and point me in the right direction?
Thanks
David
You can use helper to wait for event. Some ugly code from past:
public class ComWait
{
ManualResetEvent _waitEvent;
SomeEvent _eventHandler;
public ComWait()
{
_waitEvent = new ManualResetEvent(false);
_eventHandler = new SomeEvent(Watch);
}
void Watch()
{
_waitEvent.Set();
}
public bool Wait(int time = 3000)
{
_waitEvent.Reset();
SomeEvent += _eventHandler;
bool result = _waitEvent.WaitOne(time, false);
SomeEvent -= _eventHandler;
return result;
}
}
Usage is
ComWait wait = new ComWait();
if(!wait.Wait())
return; // timeout
// process
It will simply block synchronous method until event is rised or timeout occurs. It should be easy to add parameters: to unblock on specific event and to pass event handler parameters back to caller.
Otherwise I would simply have method inside communication class to use as a blocker:
readonly object _waitLock = new object();
public void Wait()
{
lock (_waitLock)
if (!Monitor.Wait(_waitLock, 3000))
throw new TimeoutException("No communications");
}
Signal at same time as you rise event:
lock (_waitLock)
Monitor.PulseAll(_waitLock);
I am fairly new to C# and was working on a a way to implement a dynamic GUI which uses the serial communication. I originally come from C, so the concept of function pointer is familiar.
Basically I want to invoke a answerFunction() function when the serial command has been processed.
In Theory:
I have a Class lbl_txtBox_Pair which is dynamically created on runtime.
I have a Class comObject which communicates with the serial Port.
I have a third class comPacket which holds all information regarding one serial command.
in an Object of Class lbl_txtBox_Pair I instantiate a Packet and tell it which function should be called when the serial command is finished.
I give the packet Object to the comObject Instance.
after being processed the comObject wants to signal the original sender of the packet by calling the delegate which is stored in the Packet Object.
For some reason I can't get it to work. It tells me that the Attribute of Packet is not callable. Am I doing something terribly wrong?
Here is the Code:
first the code in Class "lbl_txtBox_Pair". I create the comPacket here and give it to the comObject.
public delegate void answerHandler( comPacket packet);
public void txb_value_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Return)
{
answerHandler answerMethod = new answerHandler(this.processAnswer);
comPacket question = new comPacket(this.command, answerMethod, 1);
comObject.addPacket(question);
}
}
The constructor of comPacket. Here the delegate gets stored to be called later.
public Delegate answerFunction;
public comPacket(string cmd, Delegate func, int prio)
{
this.cmd = cmd;
answerFunction = func;
this.prio = prio;
}
In the comObject the Packets get processed. When finished I want to call the function stored in the Packet. The comObject runs in a different Thread by the way.
if (this.isEndtocken(inputline))
{
listen = false;
packet.answerFunction(packet);
}
And here it is were it breaks. packet.answerFunction(packet); wont execute and says it can't be called as Method.
Can anybody see where it goes wrong? I think it seems like the delegate looses the information that it is a delegate or something.
Or do I have to completely restructure the code to use other types of callback / Event Methods?
Change your comPacket to take a strongly typed delegate:
public answerHandler answerFunction;
public comPacket(string cmd, answerHandler func, int prio)
{
this.cmd = cmd;
answerFunction = func;
this.prio = prio;
}
If you still want to keep the delegate reference weakly typed, you can leverage DynamicInvoke instead: http://msdn.microsoft.com/en-us/library/system.delegate.dynamicinvoke.aspx
EDIT: Another option if you want to maintain strongly typed delegates yet have different usages is to leverage generics. Your delegate can be housed in a generic class and tie its signature against that generic type.
I can't leave a comment so I have to post this as an answer instead.
Delegates (and events and stuff) can usually only be "invoked" by the object that contains them.
So if you have
class MyClass {
public event Action someEvent;
// you can also replace Action with the name of your delegate type
}
and you try to do
MyClass x = new MyClass();
x.someEvent.Invoke();
Then that's an error. If you want other objects to be able to invoke the event, you'll have do add a method to MyClass like this:
public void InvokeMyEvent() {
someEvent.Invoke();
}
(I forget whether you still have to do this for static events)
Problem:
I am working on a application where in for some time consuming operation, i am supposed to show a progress bar on a form (WinForm) with a cancel button. So obviously i am using BackgroundWorker thread for it. Below is the code which simulates roughly of what i am trying to achieve.
namespace WindowsFormsApplication1
{
public delegate void SomeDelegateHandler();
public partial class Form1 : Form
{
public event SomeDelegateHandler DoSomeAction;
BackgroundWorker bgWorker;
public Form1()
{
InitializeComponent();
bgWorker = new BackgroundWorker();
bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
}
void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
//Some logic code here.
for (int i = 0; i < 100; i++)
{
DoSomeAction();
}
}
private void Form1_Shown(object sender, EventArgs e)
{
if (DoSomeAction != null)
bgWorker.RunWorkerAsync();
else throw new EventNotSubscribedException();//Is this a valid style??
}
}
public class EventNotSubscribedException : ApplicationException
{
//Some custom code here
}
}
My Solution
As per the above code, as soon as the form is displayed to the user (OnShown event) i am starting the backgroundworker thread. This is because, the user need not to initiate any action for this to happen. So onshown does time consuming operation job. But the issue is, as i have shown above, the main time consuming job is executed on other class/component where it is kind of tight bounded too (legacy code: cant refactor). Hence i have subscribed to the event DoSomeAction in that legacy code class which launches this form.
Doubt/Question:
Is it valid to throw exception as shown above? (Please read my justification below).
Justification:
The OnShown event does check for null on event handler object. This is because, to make this form usable, the event has to be subscribed by the subscriber (usage code), then only it shall work. If not, then the form just displays and does noting at all and usage code may not know why it is happenings so. The usage code may assume that subscribing to the event is option just like button click events per say.
Hope my post is clear and understandable.
Thanks & Happy Coding,
Zen :)
Do you mean that you need to throw an exception to the caller of the form? Is it called using showDialog or Show?
BTW, I dont prefer to generate an exception from an event. Rather it would be rather nice to keep it such that it returns from the place with some status set on the Form class.
for instance, I would prefer using
IsEventSubscribed = false
this.Close()
rather than EventNotSubscribedException
BTW, One problem I can see in the code, when the bgWorker_DoWork is called, you should check DoSomeAction to null, because otherwise it might cause NullReferenceException.
Preferably,
Start the run the RunWorkerAsync from Form_shown
Check Delegate to null in DoWork, if it is null, do not call DoSomeAction otherwise call it.
On RunWorkerCompleted of the BackgroundWorker, close the form.
Let me know if you need anything more.
I would suggest making the consuming code construct the BackgroundWorker and pass it to the form's constructor. You can do a null test in the constructor and side-step this whole issue. Alternatively, take the delegate as a constructor argument instead. I mean, how likely is it that the consuming code will need to change the worker delegate mid-operation?
Another approach is to have the dialog monitor a task, instead of having a dialog control a task (as you have here). For example, you could have an interface like this:
public interface IMonitorableTask {
void Start();
event EventHandler<TData> TaskProgress;
}
Where TData is a type that provides any information you might need to update the dialog (such as percent completed).
The downside to this is that each task needs to be a type of its own. This can lead to very ugly, cluttered code. You could mitigate that issue somewhat by creating a helper class, something like:
public class DelegateTask : IMonitorableTask {
private Action<Action<TData>> taskDelegate;
public event EventHandler<TData> TaskProgress;
public DelegateTask(Action<Action<TData>> taskDelegate) {
if (taskDelegate == null)
throw new ArgumentNullException("taskDelegate");
this.taskDelegate = taskDelegate;
}
protected void FireTaskProgress(TData data) {
var handler = TaskProgress;
if (handler != null)
handler(this, data);
}
public void Start() {
taskDelegate(FireTaskProgress);
}
}
Then your task methods become factories:
public IMonitorableTask CreateFooTask(object argument) {
return new DelegateTask(progress => {
DoStuffWith(argument);
progress(new TData(0.5));
DoMoreStuffWith(argument);
progress(new TData(1));
});
}
And now you can easily(*) support, say, a command-line interface. Just attach a different monitor object to the task's event.
(*) Depending on how clean your UI/logic separation already is, of course.
Hi i have some question related to call back feature in libraries created by user in c#
i have created a winform application named "Sample"
i have also created a class library named "Library"
Sample contains only one form that has a button say "CALL"
i have implemented all the coding part in a library
when i click on the call button on form then a method "ACTIVATE CALL" of the library is called.
this method performs some work on a thread.
What i want is when thread work if finished then "CALLBACK" method placed in my winform must be called.
To achieve this i have passed "this" reference of the form to the library
i collected "this" as obj "Object" type in formal arguement in library.
can anybody suggest me how to call callback method?
i tried this:
if(obj.GetType()== typeOf(what to specify here))
{
obj.callback();
}
hope somebody can provide me help.
note: both library and sample are different projects
how to achieve callback feature?
Define your library method with a callback.
public void ACTIVATE(object arg, object arg, Action callback)
{
// Do what you have to do here.
callback.Invoke();
}
Then, in your Sample WinForms client you can call something like this.
public void MethodInSample()
{
Library lib = new Library();
Action callback = () => { DoSomethingHere };
Lib.ACTIVATE(1,1,callback);
}
If you want the callback to return some parameters, you could use a Func<> instead and define the arguments that way.
Alternatively, you could use an event. The BackgroundWorker object is a good example of this. This class has a method called RunWorkerAsync(), which causes some work to be done on a background thread. There is then an event called RunWorkerCompleted which you listen on to indicate when the background thread has completed.
Both methods are valid I think, but the second has the benefit of allowing more than one party to listen for completion of the work.
Have the user of the ActivateCall function supply a callback so in you library:
function void ActivateCall(Action callback){
//Do Stuff
if (null != callback){
callback();
}
}
and then in your main form:
function button1_Click(object sender, EventArgs e){
library.ActivateCall(DoStuff);
}
There are a number of things to look out for though since you say you are doing stuff in a separate thread within the library call. If you are altering the GUI at all in the callback you will need to make sure you do the work in the GUI thread. You will also need to make sure you run the callback once all the work in the thread has been completed (I suspect).
To make sure your callback is run in the GUI thread (if required) do something like this:
function button1_Click(object sender, EventArgs e){
library.ActivateCall(DoStuff());
}
function void DoStuff(){
if (InvokeRequired(){
Invoke(DoStuff);
return;
}
//Do stuff here....
}
Finally i achieved this using Delegate+Event
*****************Sample class**************************
call()
{
//activate method of library is called
libraryObject.stop += new LibraryClass.callback(setCallbackMethod);
libraryObject.activate();
}
public void setCallbackMethod(String str)
{
// most important to be back on main thread
this.Invoke((MethodInvoker)delegate
{
btn.Enabled = true;
});
}
*******************Library***************************
public delegate void callback(String str);
public event callback stop;
activate()
{
//instantiates a thread/timer
aTimer = new System.Timers.Timer();
aTimer.Elapsed += new ElapsedEventHandler(CheckForMessage);
aTimer.Interval = 1000;
aTimer.Start();
}
public void CheckForMessage(object source, ElapsedEventArgs e)
{
//performs some work
//calls callback method of ui thread in sample code
if (stop != null)
{
stop("COMPLETED");
}
}