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.
Related
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);
So, around a week ago I asked a question about activex and UDP. Here it is:
C# UDP Socket client and server
Now, I created two applications, one (the sender) to send pre-defined strings via UDP. The other is activex component that is called from a webpage, and it's thread is working in the background. Once an UDP message arrives, then it's doing it's stuff (writing in database, writing in log.txt, and so on).
The last thing i need is to return data (it's yet to be said if it will be string or something else). However, the method in the activex which is called must be a void, because if it's made to be string, the threading wont work, and only the first message will arrive.
My question is, how to do that? How to return data from a void function? For example, the web app now is calling the activex DLL like this:
ClassLibrary1.Class1 activex = new ClassLibrary1.Class1();
activex.StartThread();
And the StartThread() calls the listening thread and it's working in the background, and once UDP msg arrives, its doing some stuff like i said above.
How can i return value with the threads (events) and the web app will catch it and use it?
Thanks a lot.
You can use events (which implement the Observable pattern) to alert any listener that a new message has arrived:
public class NewMessageArgs : EventArgs
{
public string Message { get; private set; }
public NewMessageArgs(string message)
{
Message = message;
}
}
public class ActiveXComponent
{
public event EventHandler<NewMessageArgs> OnMessage;
public void StartThread()
{
while (true)
{
//do stuff
//raise "message received" event
if (OnMessage != null)
OnMessage(this, new NewMessageArgs("hi"));
}
}
}
You can then listen to these events like so:
ActiveXComponent activex = new ActiveXComponent();
activex.OnMessage += ProcessMessage;
activex.StartThread();
public void ProcessMessage(object sender, NewMessageArgs args)
{
var msg = args.Message;
//process
}
Basically you have to store some data in a spot where you can access it from both places (from the thread, and from the place where you started the thread). So you have a couple of options from the top of my head.
Store it in a database
Create a specific object (whatever type you need), and store it in a place where it is accessible from both places. For example, a singleton. A simpler better solution is to create a property on your ClassLibrary.Class1 class: set it from within the Class1-class, and get it from the place where you created an instance of your Class1-class.
Add an event to your Class1-class which fires when it is finished doing its job. And add some data to the EventArgs.
I'm assuming here you get notified when your thread is done doing whatever it is doing.
Edit: added events
The threading function can change the fields values of the class and you can access those fields, also your thread can fire events that other classes can subcribe to and then act on it.
Class1
{
private string value;
public string Value{get{return value;} set{value=value; FireTheEvent();}}
}
I'm new in C# async/await and facing some issues while trying to work with async method.
I have a collection:
private IList<IContactInfo> _contactInfoList
And an async method:
public async Task<IList<IContactInfo>> SelectContacts()
{
_contactInfoList = new List<IContactInfo>();
ContactsSelector selector = new ContactsSelector();
selector.ShowPicker();
selector.ContactsSelected += (object sender, ContactsSelectorEventArgs e) =>
{
this._contactInfoList = e.Contacts;
};
return _contactInfoList;
}
Contact selector is a popup user control which allows to select some contacts from phone and after the "OK" button tapped it fires ContactsSelected event. I need to get the selected contacts list from the event arguments e.Contacts and return that list in above mentioned SelectContacts() async method. And here is the issue: My method is already returning empty list _contactInfoList before the ContactsSelected event has finished his job. I know that async/await even doesn't matter in this case and this issue will be exist in usual method, but I just need to make that method to wait event handling result.
What you need to do here is convert an event style of asynchronous programming to a task style of asynchronous programming. The use of a TaskCompletionSource make this fairly straightforward.
public static Task<IList<IContactInfo>> WhenContactsSelected(
this ContactsSelector selector)
{
var tcs = new TaskCompletionSource<IList<IContactInfo>>();
selector.ContactsSelected += (object sender, ContactsSelectorEventArgs e) =>
{
tcs.TrySetResult(e.Contacts);
};
return tcs.Task;
}
Now that we have a method that returns a task with the result that we need, the method that uses it is quite straightforward:
public Task<IList<IContactInfo>> SelectContacts()
{
ContactsSelector selector = new ContactsSelector();
selector.ShowPicker();
return selector.WhenContactsSelected();
}
There are a few things to note here. First, I removed the instance field; that seems like a bad idea here. If SelectContacts is called several times it would result in the two fighting over that field. Logically if you do need to store the list it should be a local variable. Next, there are no await uses here, so the method shouldn't be marked as async. If you wanted to await the call to WhenContactsSelected then feel free to add async back in, but as of now I see no real need for it.
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");
}
}
How can the event System.ComponentModel.CancelEventArgs be used? Suppose we have the following code:
public event CancelEventHandler EventTest = delegate { };
public void MakeSomethingThatRaisesEvent()
{
CancelEventArgs cea = new CancelEventArgs();
EventTest(this, cea);
if (cea.Cancel)
{
// Do something
}
else
{
// Do something else
}
}
What happens if more than one delegate is registered on the event? There is any way to get the results of all the subscribers?
This is used on Winforms (at least) sometimes. If not possible to get all values, they suppose only one subscriber to the event?
To ask each subscriber separately, you need to access the list:
foreach (CancelEventHandler subHandler in handler.GetInvocationList())
{
// treat individually
}
Then you can check each in turn; otherwise you just get the final vote.
Normally, in most cases, the class just allows multiple subscribers, but each gets the same instance of CancelEventArgs.
If any of the subscribers set Cancel to true, the operation will be treated as canceled.
You can work around this by getting the invocation list, and sending an event to each subscriber, but this is not usually necessary.