I have two methods:
private void RvListen_OPT()
private void RvListen_FUT()
On a certain event, both call:
void OnRvMessageReceived(object sender, SigRvMessageEventArgs args)
When OnRvMessageReceived is called, how can I check which of the two methods called it? I know it can be done using the object sender, but I'm not sure how to do it.
If you can edit the SigRvMessageEventArgs class you could add a field to it which you set differently in the two calls.
sender will (usually) give you the object that called the event. It may not because its up to the caller to actually set this.
That said, I"m not sure it should matter. If the call depends on who called it, maybe they need to be setup as separate events... Or, as Jackson mentioned, the args variable could be set to allow the OnRvMessageReceived event can respond to that.
Set sender to a string if you can't change SigRvMessageEventArgs to take an additional property... But the best approach would be to modify SigRvMessageEventArgs if possible.
private void RvListen_OPT()
{
OnRvMessageReceived("RvListn_OPT()", new SigRvMessageEventArgs())
}
private void RvListen_FUT()
{
OnRvMessageReceived("RvListn_FUT()", new SigRvMessageEventArgs())
}
void OnRvMessageReceived(object sender, SigRvMessageEventArgs args)
{
if(sender.ToString() == "RvListn_OPT()"){
// do work
}
else if(sender.ToString() == "RvListn_FUT()"){
// do work
}
}
Related
I've been looking for an answer for about an hour on Google but I did not found exactly what I'm looking for.
Basically, I have a static Helper class that helps perform many things I do frequently in my App. In this case, I have a method named "CreateDataContextMenu" that creates a context menu on a given TreeView control.
public static void CreateDataContextMenu(Form parent, TreeView owner, string dataType)
{ ... }
TreeView owner is the control in which I will associate my context menu.
Then later on I add a Click event to a MenuItem like this:
menuItemFolder.Click += new System.EventHandler(menuItemFolder_Click);
The problem I have here is that I want to pass "owner" and "dataType" as arguments to the menuItemFolder_Click event.
I tried the following:
menuItemFolder.Click += new System.EventHandler(menuItemFolder_Click(sender,e,owner,dataType));
(...)
private static void menuItemFolder_Click(object sender, System.EventArgs e, Treeview owner, string dataType)
{...}
But it doesn't work at all. It might be very naive of me to do it that way but I"m not very comfortable with event handler yet.
Any idea on how I could do that?
My first guess is that I need to create my own EventHandler for this specific case. Am I going in the right direction with that?
You should create a lambda expression that calls a method with the extra parameters:
menuItemFolder.Click += (sender, e) => YourMethod(owner, dataType);
Honest admission up front: I have not tried the code below.
I think the reason
menuItemFolder.Click += new System.EventHandler(menuItemFolder_Click(sender,e,owner,dataType));
won't work is because you are actually passing to System.EventHandler () the result of the invocation of menuItemFolder_Click () with the parameters provided. You are not passing a pointer to the function itself.
Try to write another function that implements the details of menuItemFolder_Click (). See if something like
private void menuItemFolder_Click_Helper (object sender, EventArgs e, object Owner, object DataType) {
// implement details here
}
and then call the function from within menuItemFolder_Click ().
I think the simplest code would be this:
EventHandler myEvent = (sender, e) => MyMethod(myParameter);//my delegate
myButton.Click += myEvent;//suscribe
private void MyMethod(MyParameterType myParameter)
{
//Do something
//if only one time
myButton.Click -= myEvent;//unsuscribe
}
Passing custom args into an event handler is not too difficult. Below is a clean and easily reusable method of doing so. Check it:
public class MyClass
{
public CustomArgsEventHandler MyEvent1;
public MyClass(){MyEvent1+=observer;}
public void observer(object sender, CustomEventArgs e){print(e.myArg);}
//...
}
//place in the same file if you like!
public class CustomEventArgs : EventArgs
{
public float myArg {get;set;}
public CustomEventArgs (float d) { myArg = d; }
}
public delegate void CustomArgsEventHandler (object sender, CustomEventArgs e);
I have an event handler on my form for a LinkLabel linkLabel2_LinkClicked:
private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
//code here
}
I need to call it from another method that does not have an object sender and any eventargs:
private void UpdateMethod()
{
linkLabel2_LinkClicked(this, ?????)
}
If it were a Button I would just call the PerformClick method. But there is no such for a LinkLabel that I could find.
What is the best practice to execute the code in the linkLabel2_LinkClicked event handler?
Update: I guess I was not clear on this. I wonder about the best practice as I have seen this approach. I can see from the answers that this is not the correct approach but to move the code to a separate method and call it directly from the other method. Please let me know if any other reasoning goes with this.
Update 2: I rewrote the code now as follows:
private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
CreatePreview();
}
private void UpdateMethod()
{
CreatePreview();
}
private void CreatePreview()
{
//code comes here
}
It works perfectly.
You can put null in event parameter :
linkLabel2_LinkClicked(this, null);
or create a new event object :
linkLabel2_LinkClicked(this, new LinkLabelLinkClickedEventArgs());
But the best way is create a separate methode and call it in every time you need it.
You could just pass null since you're not using the parameter anyway, but I'd recommend against that. It's discouraged to call an event directly, and it leads to code that's tough to read.
Just have the other method call CreatePreview().
private void UpdateMethod()
{
CreatePreview();
}
I have a quick C# question.
I have a list that I need to pass onto a method. So I did this:
Form2 f2 = new Form2(JogadoresList);
f2.novoJogo(JogadoresList);
And on another class:
public void novoJogo(List<Jogadores> JogadoresList)
{}
But now I want to call the novoJogo method from a
private void button1_Click(object sender, EventArgs e)
{
}
method. How can I call the novoJogo method if I don't have parameters to pass onto it and don't want to replace the novoJogo's list? Thank you.
You can just call novoJogo passing null value as parameter:
novoJogo(null);
Or an empty list:
novoJogo(new List<Jogadores>());
Also in the novoJogo method, you could define the List<> as an optional parameter:
public void novoJogo(List<Jogadores> JogadoresList=null)
{}
Then, you can call it without passing the argument in the the click event as I show below:
private void button1_Click(object sender, EventArgs e)
{
novoJogo();
}
Either the method needs the list, or it doesn't. So the fact you are asking this is... troubling.
However, you have a couple options. Just pass null:
private void button1_Click(object sender, EventArgs e)
{
//Hopefully you held onto that reference!
f2.novoJogo(null);
}
Or use default arguments/optional parameters:
public void novoJogo(List<Jogadores> JogadoresList = null)
{}
private void button1_Click(object sender, EventArgs e)
{
//Hopefully you held onto that reference!
f2.novoJogo();
}
In both cases, make sure that novoJogo will be OK with a null list passed to it (NRE is really easy to get here if you weren't careful). And consider if your design makes sense here, if only part of the function needs the list, should that really have been two functions instead of one?
Change the access-level of JogadoresList to public static or internal static so you can access it via button1_click.
One thing that annoys me is that in a default Event, Sender is of type object and therefore almost always requires a manual cast before we can use it. Luckily since VB now also supports variance in delegates, we can update the signature of an event in such a way that the sender is strongly typed, see: Event parameter; "sender as Object", or "sender as T"?
Unfortunatly this doesn't work for existing declared events which senders are of type object.
Now one solution would be ofcourse to generate a fake EventHandler which internally takes care of the cast for you. I made a quick example, see:
struct EventHandler<TSender, TEventArgs>
where TEventArgs: EventArgs
{
private readonly Action<TSender, TEventArgs> _delegate;
public EventHandler(Action<TSender, TEventArgs> #delegate)
{
if (#delegate == null)
throw new ArgumentNullException("#delegate");
_delegate = #delegate;
}
public static implicit operator EventHandler<TEventArgs>(EventHandler<TSender, TEventArgs> eventHandler)
{
return new EventHandler<TEventArgs>(eventHandler.Execute);
}
private void Execute(object sender, EventArgs e)
{
TSender typedSender = (TSender)sender;
TEventArgs typedEventArgs = (TEventArgs)e;
_delegate(typedSender, typedEventArgs);
}
}
which can be used as you would expect it to be used:
class Program
{
event EventHandler<EventArgs> Test;
static void Main(string[] args)
{
new Program().Main();
}
void Main()
{
Test += new EventHandler<Program, EventArgs>(TestEventHandler);
Test(this, EventArgs.Empty);
}
void TestEventHandler(Program sender, EventArgs e)
{
throw new NotImplementedException();
}
}
Now if I really want to use this, there is alot of work to be done. (The struct should behave just like the original delegate). Yet i do have the feeling that there is either already a great implementation out there, or there is no implementation since there are some major drawbacks i overlooked.
Who can answer me the above question? Any other hints?
I can't think of any solution that would have less code than
var original = (OriginalType)sender;
Also if class is yours nothing stops you from creating your own delegate instead of EventHandler delegate
delegate void EventHandler<in TSender, in TArgs>(TSender sender, TArgs args);
This is contravariant in args and sender
People usually also have the reference of the object for which the event is raised and therefore they rarely need to get the thing out of the sender. Could it be possible in your case?
Edit: Since you mentioned you're dealing with events that are not written by you so modifying the delegate is out of question and you probably don't have reference to the object so you have to resort to the sender in that case. Now in your solution you can not unsubscribe to the event. If you modify it to support that then you'll have to keep the reference to this struct of yours which is more work than simple casting. I think casting is still the cleanest solution.
I'm of the opinion that using methods as event handlers is now bad OOP practice. Now that we have anonymous delegates we just don't need to make methods just to handle events. Creating an event handler method that could get called by every other method in a class is much like making class members public and letting any class call anything.
In the past we have had to write this:
public class Program
{
public void Main()
{
var button = new Button();
button.Click += button_Click;
}
void button_Click(object sender, EventArgs e)
{
var button = (Button)sender; //Need to cast here
}
}
But now we can write this:
public class Program
{
public void Main()
{
var button = new Button();
button.Click += (sender, e) =>
{
//Can use `button` here
//Just ignore `sender`
};
}
}
Using anonymous delegates allows us to use the event "sender" reference directly without the need of any casting.
Much cleaner object oriented coding.
Is it possible under any set of circumstances to be able to accomplish this?
My current circumstances are this:
public class CustomForm : Form
{
public class CustomGUIElement
{
...
public event MouseEventHandler Click;
// etc, and so forth.
...
}
private List<CustomGUIElement> _elements;
...
public void CustomForm_Click(object sender, MouseEventArgs e)
{
// we might want to call one of the _elements[n].Click in here
// but we can't because we aren't in the same class.
}
}
My first thought was to have a function similar to:
internal enum GUIElementHandlers { Click, ... }
internal void CustomGUIElement::CallHandler(GUIElementHandler h, object[] args) {
switch (h) {
case Click:
this.Click(this, (EventArgs)args[0]);
break;
... // etc and so forth
}
}
It's a horribly ugly kludge, but it should work... There must be a more elegant solution though? The .NET library does this all the time with message handlers and calling events in Control's. Does anyone else have any other/better ideas?
You just need to add a public method for invoking the event. Microsoft already does this for some events such as PerformClick for controls that expose a Click event.
public class CustomGUIElement
{
public void PerformClick()
{
OnClick(EventArgs.Empty);
}
protected virtual void OnClick(EventArgs e)
{
if (Click != null)
Click(this, e);
}
}
You would then do the following inside your example event handler...
public void CustomForm_Click(object sender, MouseEventArgs e)
{
_elements[0].PerformClick();
}
The event keyword in c# modifies the declaration of the delegate. It prevents direct assignment to the delegate (you can only use += and -= on an event), and it prevents invocation of the delegate from outside the class.
So you could alter your code to look like this:
public class CustomGUIElement
{
...
public MouseEventHandler Click;
// etc, and so forth.
...
}
Then you can invoke the event from outside the class like this.
myCustomGUIElement.Click(sender,args);
The drawback is that code using the class can overwrite any registered handlers very easily with code like this:
myCustomGUIElement.Click = null;
which is not allowed if the Click delegate is declared as an event.
You can shorten the code suggested in the accepted answer a lot using the modern syntax feature of the .NET framework:
public event Action<int> RecipeSelected;
public void RaiseRecpeSelected(int recipe) => RecipeSelected?.Invoke(recipe);
You really should wrap the code you want to be able to execute from the outside in a method. That method can then do whatever your event would do - and that event would also instead call that method.