Programmatically triggering an event? - c#

How can I call this method programmatically?
If I simple do KillZombies(), it says I don't have the correct parameters, but I don't know what parameters to specify when I'm just using code...
public static void KillZombies(object source, ElapsedEventArgs e)
{
Zombies.Kill();
}

Have you tried:
KillZombies(null, null);
Perhaps refactor your design:
public static void KillZombies(object source, ElapsedEventArgs e)
{
//more code specific to this event, logging, whathaveyou.
KillSomeZombies();
}
public static void KillSomeZombies()
{
Zombies.Kill();
}
//elsewhere in your class:
KillSomeZombies();

KillZombies(null, null);
However, I would question whether that's a good design.

You'd have to create the parameters and pass them through too. Why not just call the function directly by putting it in another function that is available for other classes to call? It'll make for much neater design.
i.e.
internal void MakeZombiesKill()
{
Zombies.Kill();
}
?

Your method signature requires two arguments. You cannot just call KillZombies(), you will need to pass the correct arguments to the method.
KillZombies(source, e);
If you do not have your source or e, you can simply pass null.
KillZombies(null, null);

You usually use the object from inside which you call the method as source (or null if static).
And set the ElapsedEventArgs to something relevant for the method. For ElapsedEventArgs it would be something like: new ElapsedEventArgs() { SignalTime = DateTime.Now}
KillZombies(this, new ElapsedEventArgs() { SignalTime = DateTime.Now});
If you don't really use source or e inside the method you can call it with null arguments.
KillZombies(null, null);

Technically speaking, you should be separating out the task from inside the event handler and have the event handler call the method containing the code you want run, this way you can call that code without tripping the event handler. However, if you want to trip the event handler programmatically:
KillZombies(this, new ElapsedEventArgs())
I however would break it out as is a frequently used best practice...

Related

Pass extra parameter to C# callback

How to add extra parameters to the following callback :
objXmpp.OnLogin += new ObjectHandler(objXmppArun_OnLogin);
private void objXmppArun_OnLogin(object sender)
{
}
Is it possible to send one extra parameter to the objXmppArun_OnLogin event handler?
No, it's not possible. Events (and delegates in general) in C# define a specific method signature with fixed parameters, so you cannot add extra ones.
The best thing to do is create a separate method which your event handler can call and pass the extra parameter to:
objXmpp.OnLogin += new ObjectHandler(objXmppArun_OnLogin);
private void objXmppArun_OnLogin(object sender)
{
LoginCheck(sender, "Some Info");
}
private void LoginCheck(object sender, string extraParameter)
{
// do your thing here
}
Or if the value you need is only known when you attach the handler, you can wrap it up in an anonymous method:
private void AttachHandlers()
{
string parameter = "Some Info";
objXmpp.OnLogin += new ObjectHandler(sender => {
objXmppArun_OnLogin(sender, parameter);
});
}
private void objXmppArun_OnLogin(object sender, string extraParameter)
{
}
You cant change the delegate expected by whatever component you're using (objXmpp.OnLogin) so you therefore cant change the parameters that you handler method expects.
However, that handler has access to properties & methods of the class it is within, just like any normal method would.
(You might like to update youre question to what you're trying to achieve rather than how you're trying to achieve it - you might be able to get a better answer)

Temporarily stop form events from either being raised or being handled?

I have a ton on controls on a form, and there is a specific time when I want to stop all of my events from being handled for the time being. Usually I just do something like this if I don't want certain events handled:
private bool myOpRunning = false;
private void OpFunction()
{
myOpRunning = true;
// do stuff
myOpRunning = false;
}
private void someHandler(object sender, EventArgs e)
{
if (myOpRunning) return;
// otherwise, do things
}
But I have A LOT of handlers I need to update. Just curious if .NET has a quicker way than having to update each handler method.
You will have to create your own mechanism to do this. It's not too bad though. Consider adding another layer of abstraction. For example, a simple class called FilteredEventHandler that checks the state of myOpRunning and either calls the real event handler, or suppresses the event. The class would look something like this:
public sealed class FilteredEventHandler
{
private readonly Func<bool> supressEvent;
private readonly EventHandler realEvent;
public FilteredEventHandler(Func<bool> supressEvent, EventHandler eventToRaise)
{
this.supressEvent = supressEvent;
this.realEvent = eventToRaise;
}
//Checks the "supress" flag and either call the real event handler, or skip it
public void FakeEventHandler(object sender, EventArgs e)
{
if (!this.supressEvent())
{
this.realEvent(sender, e);
}
}
}
Then when you hook up the event, do this:
this.Control.WhateverEvent += new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler;
When WhateverEvent gets raised, it will call the FilteredEventHandler.FakeEventHandler method. That method will check the flag and either call, or not call the real event handler. This is pretty much logically the same as what you're already doing, but the code that checks the myOpRunning flag is in only one place instead of sprinkled all over your code.
Edit to answer question in the comments:
Now, this example is a bit incomplete. It's a little difficult to unsubscribe from the event completely because you lose the reference to the FilteredEventHandler that's hooked up. For example, you can't do:
this.Control.WhateverEvent += new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler;
//Some other stuff. . .
this.Control.WhateverEvent -= new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler; //Not gonna work!
because you're hooking up one delegate and unhooking a completely different one! Granted, both delegates are the FakeEventHandler method, but that's an instance method and they belong to two completely different FilteredEventHandler objects.
Somehow, you need to get a reference to the first FilteredEventHandler that you constructed in order to unhook. Something like this would work, but it involves keeping track of a bunch of FilteredEventHandler objects which is probably no better than the original problem you're trying to solve:
FilteredEventHandler filter1 = new FilteredEventHandler(() => myOpRunning, RealEventHandler);
this.Control.WhateverEvent += filter1.FakeEventHandler;
//Code that does other stuff. . .
this.Control.WhateverEvent -= filter1.FakeEventHandler;
What I would do, in this case, is to have the FilteredEventHandler.FakeEventHandler method pass its 'this' reference to the RealEventHandler. This involves changing the signature of the RealEventHandler to either take another parameter:
public void RealEventHandler(object sender, EventArgs e, FilteredEventHandler filter);
or changing it to take an EventArgs subclass that you create that holds a reference to the FilteredEventHandler. This is the better way to do it
public void RealEventHandler(object sender, FilteredEventArgs e);
//Also change the signature of the FilteredEventHandler constructor:
public FilteredEventHandler(Func<bool> supressEvent, EventHandler<FilteredEventArgs> eventToRaise)
{
//. . .
}
//Finally, change the FakeEventHandler method to call the real event and pass a reference to itself
this.realEvent(sender, new FilteredEventArgs(e, this)); //Pass the original event args + a reference to this specific FilteredEventHandler
Now the RealEventHandler that gets called can unsubscribe itself because it has a reference to the correct FilteredEventHandler object that got passed in to its parameters.
My final advice, though is to not do any of this! Neolisk nailed it in the comments. Doing something complicated like this is a sign that there's a problem with the design. It will be difficult for anybody who needs to maintain this code in the future (even you, suprisingly!) to figure out the non-standard plumbing involved.
Usually when you're subscribing to events, you do it once and forget it - especially in a GUI program.
You can do it with reflection ...
public static void UnregisterAllEvents(object objectWithEvents)
{
Type theType = objectWithEvents.GetType();
//Even though the events are public, the FieldInfo associated with them is private
foreach (System.Reflection.FieldInfo field in theType.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance))
{
//eventInfo will be null if this is a normal field and not an event.
System.Reflection.EventInfo eventInfo = theType.GetEvent(field.Name);
if (eventInfo != null)
{
MulticastDelegate multicastDelegate = field.GetValue(objectWithEvents) as MulticastDelegate;
if (multicastDelegate != null)
{
foreach (Delegate _delegate in multicastDelegate.GetInvocationList())
{
eventInfo.RemoveEventHandler(objectWithEvents, _delegate);
}
}
}
}
}
You could just disable the container where all these controls are put in. For example, if you put them in a GroupBox or Panel simply use: groupbox.Enabled = false; or panel.Enabled = false;. You could also disable the form From1.Enabled = false; and show a wait cursor. You can still copy and paste these controls in a container other than the form.

How to attach event to dynamic object or COM object

I think this article has the same problem with me. However, there's no workable solution for my case.
I'm using Windows Media Player ActiveX in my program.
For some reason, I don't want to add a reference of it and convert to AxHost automatically by IDE.
I create the instance by Activator and ProgID
protected const string WMP_PROG_ID = "WMPlayer.OCX.7";
private dynamic _wmp;
protected virtual bool init(){
try{
_wmp = Activator.CreateInstance(Type.GetTypeFromProgID(WMP_PROG_ID));
}
catch{ return false; }
return true;
}
I was tried to do this by Reflection, but I found that dynamic is suitable to my case.
Every property and method works alright, like these:
protected override bool setSpeed(float speed){
try{
_wmp.settings.rate = speed;
}
catch { return false; }
return true;
}
protected override int getLength(){
double res;
try{
res = _wmp.currentMedia.duration;
}
catch { return 0; }
return (int)(res * 1000);
}
Unfortunately, when I want to attach event like the article I indicated in the top, it got no work.
My code like this:
protected bool connectEvent(){
_wmp.StatusChange += new EventHandler(_wmp_StatusChange);
return true;
}
protected void _wmp_StatusChange(object sender, EventArgs e){
Console.WriteLine(_wmp.Status);
}
I've checked the type of event handler of StatusChange, it's EventHandler.
These codes compiled well, and I can load some music, play it, pause it, ...do anything I like.
But the StatusChange event never triggered.
I tried to set a break-point at connectEvent.
When run at _wmp.StatusChange += new EventHandler(...), the IntelliTrace give me some information.
Those information had written in Trad. Chinese, I think it means:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Could not apply operator "+=" to type System.Dynamic.DynamicObject and System.EventHandler
Even though there's an exception, but just like I said, compile was passed, everything still work -- except I could not listen event.
So, how can I attach event successfully in the dynamic object _wmp?
Any possible solution (like Reflection) is useful to me.
Also, in the case above, the handler type of StatusChange is EventHandler.
But if I want to handle PlayStateChange event, it is an "Unknown handle" if I don't add a reference of wmp.dll.
I hope the solution is suitable to this case, too.
Thanks everyone in advance for all of your support, and please forgive me for my poor English.
The generic strategy to turn a program that uses a COM object from early bound to late bound calling is to first write it early bound. IntelliSense will help you fall in the pit of success, ensuring that you use correctly named methods, pass the right kind of arguments and particularly useful to help you find out what the event handler signatures should look like.
Which produces this bit of test code:
void testEarlyBound() {
var wmp = new WMPLib.WindowsMediaPlayer();
wmp.StatusChange += new WMPLib._WMPOCXEvents_StatusChangeEventHandler(wmp_StatusChange);
}
void wmp_StatusChange() {
throw new NotImplementedException();
}
With the StatusChange event handler assignment and method body completely auto-generated by IntelliSense. Note the signature of the event handler, it is not an EventHandler. Just a method that returns void and takes no arguments, it matches the Action delegate type. Now you have a good shot at writing the late-bound version without the undiagnosable runtime exceptions:
void testLateBound() {
dynamic wmp = Activator.CreateInstance(Type.GetTypeFromProgID("WMPlayer.OCX"));
wmp.StatusChange += new Action(wmp_StatusChange);
}

storing/passing delegates as variables

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)

Are there any pitfalls for making an event handling method static?

I have the following code (from https://github.com/timabell/PageStructureBuilder ) and the ever knowledgeable ReSharper is suggesting that I make the DataFactoryCreatingPage() method static.
Is this safe, or would I be introducing a potential fault when used as an event handler?
public void Initialize(InitializationEngine context)
{
DataFactory.Instance.CreatingPage += DataFactoryCreatingPage;
DataFactory.Instance.MovedPage += DataFactoryMovedPage;
}
void DataFactoryCreatingPage(object sender, PageEventArgs e)
{
var parentLink = e.Page.ParentLink;
var page = e.Page;
parentLink = GetNewParent(parentLink, page);
e.Page.ParentLink = parentLink;
}
I can't think of any issues, but I'm wondering if I have a gap in my knowledge.
Thanks!
there's no reason why that handler should be static; the reason ReSharper suggests to make it static is probably because you're not using any instance variables within its body, so there's no harm, but event handlers shouldn't be static as they should be able to modify/use internal fields of the class that provides the handler's implementation
Resharper would do that if your method only uses the parameters passed in and does not access any member variables.
You dont have to do it.

Categories