Proper way to reuse delegate events in c# - c#

I am trying to see if I can use delegate events and reuse them so that I do not have to make multiple click events. Right now I have the following...
namespace EventsWPF
{
public partial class MainWindow : Window
{
public delegate void MyEvent(object sender, RoutedEventArgs e);
public MainWindow()
{
InitializeComponent();
btn1.Click += MyEvent;
btn2.Click += MyEvent;
}
}
}
Is this the correct way to do it? Or am I thinking about this the wrong way? I know you can use Lambda expressions as an event handler. But if I have multiple events I don't want to create multiple Lamda expressions for each handler when I can just reuse a delegate.

MyEvent is unnecessary here as you are not creating your own event, just subscribing to someone else's. The delegate keyword declares a method signature and return type - it does not create instances or define method bodies.
Here is how you re-use a lambda expression:
Action<object, RoutedEventArgs> myHandler = (o, e) =>
{
/* write event handler code here, you must */
};
btn1.Click += myHandler;
btn2.Click += myHandler;

Yes, if two buttons should have the same exact logic run; then attaching the same handler is perfectly fine. You won't be able to do it by attaching a delegate type though; you'll need an actual method (as described by #hoodaticus).
If this is in WPF:
Usually however, two buttons don't do the same thing and you can't get away with this. Far more commonly, two buttons do the same thing but with different arguments. Unfortunately, a WinForms style approach will be very painful here (you can check against sender but.... ewww).
In that case (actually, in all cases) you really want to take advantage of the MVVM pattern and set up commands for your buttons (not click handlers). Then you can use CommandParameter to get the custom piece of data into the handler.

Related

invoke datagridview events in wpf programmatically

(Beginner's question, if offended please move on, otherwise your input is welcome)
Im trying to invoke datagridview events in Wpf code. Implementing the event calling is straight forward.
for example:
dgv1.ColumnHeaderMouseClick+=delegate(
object sender, DataGridViewCellMouseEventArgs e)
{..code on event..};
My question: what is the propper way to invoke the dgv event somewhere else in the code. (press the header column programmatically).
Thank you
A cleaner way for me is to separate the method of of your custom event.
Something like this:
private void DataGrid_Sorting(object sender, DataGridSortingEventArgs e)
{
MessageBox.Show("Sorting was executed.");
}
Then set that method to the event property of the control like this:
dataGrid.Sorting += DataGrid_Sorting;
With this code won't get messy and readability is still intact.
I hope it helps you. Happy coding.
I think the only "supported" way (that is, not doing something with Windows messages and generally ignoring the .NET framework) would be to call OnColumnHeaderMouseClick. Which is what the method is for, except it's protected because it's really for someone doing their own version of the control, not for any random person to start firing off events.
So you could either subclass DataGridView and add a public method to wrap OnColumnHeaderMouseClick or you could use reflection to call the method even though it's not public.
This is a common pattern in C#. When you write
public event EventHandler XxxEvent;
it turns into something like
private EventHandler _XxxEvent;
public event EventHandler XxxEvent
{
add { _XxxEvent += value; }
remove { _XxxEvent -= value; }
}
(plus some handling of null, don't actually use that code as-is).
XxxEvent is not actually a delegate that can be invoked outside the class (you'll get a compiler error "The event 'ClassName.XxxEvent' can only appear on the left hand side of += or -="). And the _XxxEvent backing field is not something you're actually supposed to know about and is private anyway. So if you want anyone to be able to inherit from your class you conventionally have a method whose name is the same as the event prefixed with "On"
protected void OnXxxEvent(EventArgs args)
{
XxxEvent?.Invoke(this, args);
}

c# change modifier when creating event method with +=

If I subscribe a new Method to a Handler and Press "Tab" twice after the "+=" VS will implement a Body like:
public class A {
public A(){
button1.Click += OnButton1Click();
}
private OnButton1Click(object sender, EventArgs e){
}
}
How can I change VS to create the Body of the Method as public instead of private?
Kind regards,
Asat0r
How can I change VS to create the Body of the Method as public instead
of private?
Not sure if there is any option but why you would like to do that? event handlers are not meant to be public. If you want to call the logic inside handler from some other type then refactor that logic to a helper method and re-use that instead probably.
Other answers have suggested that the method shouldn't be public.
Broadly speaking, I reject that - at least without further justification. If you want to expose a method with exactly that signature, I'd normally go ahead and do so. Two caveats around that though:
Normally the signature of an event handler isn't useful except as an event handler; the parameters aren't generally useful when calling the method directly. There are exceptions to that as ever.
If you subscribe an event handler with a public method, any other code can unsubscribe that event handler by creating an equal delegate. If you control all the code in the application, that's not much of a problem.
Both cases can be solved by exposing a public method with exactly the parameters you want (which could still be event handler parameters, but often won't be) and then using a lambda expression to subscribe to the event:
// I want to be able to call this from other code
public void SaveItem()
{
// ...
}
// Hook up the event handler using a lambda expression
saveButton.Click += (sender, args) => SaveItem();
On the other hand, if neither of the bullet points are an issue, go ahead and make the method public manually. I wouldn't expect there to be a VS shortcut to do so, but simply specifying the public modifier is pretty simple.

Is it possible to put an event handler directly to a function

I have a wpf c#app.
I have an event declared in my user control and my user-control is already loaded into my main window.
In my code {somewhere appropriate) I define my event handler to a function like so:
MyUserControl.MyEvent += Myfunction;
...
void Myfunction(object someData)
{
//do something
}
To make things 'cleaner' i would like to do something like this instead:
MyUserControl.MyEvent +=> Myfunction(someData);
obviously, this does not compile but i put it in to try and illustrate what i want...
I think you are trying to create a lambda for your event
MyUserControl.MyEvent += (object o) => Myfunction(someData);
The trick is that it must match the delegate signature for the event, which in your case would be a method that takes an object and doesn't return anything. Note that by doing this you are ignoring the object that your event is sending out.

Assigning a delegate to a control

I am attempting to bind a method to the click event of a button.
var controlEvent = button.GetType().GetEvent("Click");
var eventMethod = GetType().GetMethod("button_Click");
var handler = Delegate.CreateDelegate(controlEvent.EventHandlerType, button, eventMethod);
void button_Click(object sender, EventArgs e) { }
When I call CreateDelegate I get
Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type
I feel like I am passing the wrong types into CreateDelegate but am unsure exactly.
There is no reason to use reflection here. Been a while since I've worked with winforms/webforms but it should look something like this:
button.OnClick += button_Click;
I'll comment further that button_Click is not a good name for a method unless what it does is click a button. That convention comes from some really old Microsoft guidance and it's just not good. Name functions after what they do, not how they're used. Consider how much better this reads
button.OnClick += showCalculations;
I usually go a step further and get rid of the dumb (object, EventArgs) parameters as well (unless I'm using these)
button.OnClick += (o,e) => showCalculations();
//...
void showCalculations() {
//...
}
The second parameter to Delegate.CreateDelegate is the class instance to call the method on.
Your method isn't defined on button, so you get an error.
You need to pass this.

Remove events without knowing their names

Is it possible to instead of doing this:
person.Walking -= person_Walking1;
person.Walking -= person_Walking2;
person.Walking -= person_Walking3;
Do this:
person.Walking = // remove all the handlers without knowing their names
Thanks.
No. Part of the point of events is that they prevent you from doing that. If I've subscribed to a button click and you've subscribed to a button click, what right have you to remove my handler? (Okay, that's anthropomorphising somewhat, but you get the idea.) Note that it's not a matter of knowing the "name" of an event handler - you have to be able to provide a reference to an "equal" delegate instance.
For example, if you subscribe to an event using an anonymous method or a lambda expression, you'll have to keep a reference to that somewhere:
EventHandler handler = (sender, args) => Console.WriteLine("Clicked!");
button.Click += handler;
...
button.Click -= handler;
When you use the name of a method, that's performing a method group conversion from the name of the method to a delegate instance:
button.Click += HandleEvent;
...
button.Click -= HandleEvent;
Here there are two separate delegate instances involved, but they're equal as they have the same invocation list (they do the same thing) and they have the same target (they're doing that thing "on" the same object).
EDIT: I'm assuming you only have access to it as an event, not as a field - if you're writing code in the class which publishes the event, you can do what you like, and setting the field to null (or removing it from the collection, or however your implementation works) is fine.
Sure. Just set:
person.Walking = null;
This is one of the reasons events were invented. If you wanted to do something like that, use delegates.
Not from outside the class in which the events are defined. If you really wanted to, you could define a method like this:
public void ClearEventListeners() {
MyEvent.Clear();
}
(The exact call may be different, if it exists, but IntelliSense should point you in the right direction.)

Categories