In Windows Forms, if you change the method name (for example, button1_Click) to something else, it doesn't work any more.
I find this strange because in a console application, as far as I remember, you could name the methods as you wished. I'm trying to understanding what's happening.
How can I change the name of these methods (such as button1_Click)?
This questions is about the case where renaming a method causes the forms designer to stop working. Although I have covered (all that I can think of) how events works in general.
What happened?
What you experience is an artifact of the forms designer.
Sure, you can have any method name you want, the matter is the forms designer is binding those methods to events behind the scenes, if you change the method name after the forms designer has linked it to the event it will no longer work (it can't find the method).
Giving proper names to your event handlers
In Visual Studio, look at the properties of the object you want to bind an event to, and then select events (on the top of the panel):
There you will see a list the available events and you will be able to bind an existing method or type the name for a new one:
If I have already screwed, how do I fix it?
If your designer is not appearing because of this you will have to edit the code file that is generated by the designer. The file generated by the designer has the name of the form followed by .Designer.cs (for example: Form1.Designer.cs), you can find it with your solution explorer:
Note: You may have to expand the sub-tree created on your form to reveal the file.
There you will find a line that looks something like this:
this.button1.Click += new System.EventHandler(this.button1_Click);
And Visual Studio will tell you that button1_Click is not defined. You can edit there the name of the method to the new name, or remove the line to have the designer work again, and bind a new method.
Renaming an existing method without the hassle
You can summon the Rename dialog. This can be done by several ways:
From the Menus: Edit -> Refactor -> Rename
By contextual Menu on the name of the Method: Refactor -> Rename
Put the cursor on the Method name and type Alt + Shift + F10 and then select Rename
Put the cursor on the Method name and press F2
Note: You can customise your Visual Studio, the above menus and keyboard shortcuts may be changed.
The Rename dialog looks like this:
There you can type a new name for the method, and by doing so any reference or call to that method withing the loaded projects will be changed too. That includes the code generated by the Forms Designer.
Binding an event handler by hand
All that the forms designer does is present a UI that facilitates editing the form and write code on your behalf. Don't let it fool you into thinking that you can't write code yourself.
In fact, you can create your own methods and even bind them to the events of your Form. I have been saying "bind" because it is easier to understand at this level, although the accepted lingo is subscribe. So what we are going to do, is create a button and subscribe to its Click event.
First let's take a look at the class of your form, it looks something like this:
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
}
Notice it says partial, that means that there could be more code for this class in another file, in fact that is the file Form1.Designer.cs where the forms designer has been adding code.
Second notice it calls a method InitializeComponent inside the constructor of the form. This method has been created by the forms designer and it takes responsibility of initializing all the controls and components you have added using the forms designer (hence the name of the method).
Now, let's say we want to add a button without the forms designer we can do it like this:
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private Button myButton;
public Form1()
{
InitializeComponent();
// Create a new Button
myButton = new Button();
// Set the properties of the Button
myButton.Location = new System.Drawing.Point(50, 12);
myButton.Size = new System.Drawing.Size(100, 23);
myButton.Text = "My Button";
// Add the Button to the form
this.Controls.Add(myButton);
}
}
}
We have created a private field named myButton of type Button that will hold the new button. Then inside the constructor we add some new lines to create a new Button and assign it to myButton and give it position (Location), Size and Text. And finally we have added the newly created button to the Controls of the form.
Now we want to add an event handler for the Click event on this new button. Remember that this button is not in the forms designer, we we are going to have to do it "by hand".
In order to do so, add the new method (you can named whatever you want):
private void WhenClick(object sender, System.EventArgs e)
{
/* Code */
}
And then add it as an event handler for the Click event of the button (inside the constructor):
// Add an event handler
myButton.Click += new System.EventHandler(WhenClick);
Notice we are not calling WhenClick. instead we are making a reference to it.
Then we are creating a new Delegate of type System.EventHandler that will wrap the reference to the method WhenClick. I suggest to learn about Using Delegates.
I repeat: we are not calling WhenClick. If we were to call WhenClick we would do something like this: WhenClick(param1, param2). Please note that this is not what we are doing here, we haven't added parenthesis (/*...*/) after the method name, so we are not doing a method call.
You can also use some syntactic sugar to make all this easier:
public Form1()
{
InitializeComponent();
// Create a new Button and set its properties
myButton = new Button()
{
Location = new System.Drawing.Point(50, 12),
Size = new System.Drawing.Size(100, 23),
Text = "My Button"
};
// Add the Button to the form
this.Controls.Add(myButton);
// Add an event handler (the compiler infers the delegate type)
myButton.Click += WhenClick;
}
You can even make the event handler an anonymous method:
// Add an event handler (the compiler infers the delegate type)
myButton.Click += (sender, e) =>
{
/* code */
};
What you see here is a C# Lambda expression (more info at MSDN Lambda expressions). Get used to these syntax, because you will see them more and more often.
Understanding events
You have already seen code like this:
button1.Click += button1_Click;
As I told you we are passing a delegate object that has a reference to button1_Click. But that's not all that happens here... we are also giving it to Click.
Let's recapitulate and see how delegates behave. You can think about a delegate like an object that holds a method, or a pointer to a function if you prefer.
To understand this, I'll present some examples you can run as console applications. The first one shows that you can change the method that a delegate points to during runtime:
// Console Application Example #1 ;)
static void Main()
{
Func<int, int> myfunc = null;
myfunc = Add2;
Console.WriteLine(myfunc(7)); // This prints 9
myfunc = MultBy2;
Console.WriteLine(myfunc(7)); // This prints 14
}
static int Add2(int x)
{
// This method adds 2 to its input
return x + 2;
}
static int MultBy2(int x)
{
// This method multiplies its input by 2
return x * 2;
}
Notice myfunc is typed as Func<int, int> this is a generic delegate type that takes an int and returns an int.
Also notice that when I say myfunc = Add2;, it is not calling Add2 (there are no parenthesis there), it is passing a reference of the method itself. the same is true for myfunc = MultBy2;: it is not calling MultBy2, we are passing it.
Using anonymous methods via lambda expressions you can write equivalent code is less lines:
// Console Application Example #1 ;)
static void Main()
{
Func<int, int> myfunc = null;
// This anonymous method adds 2 to its input
myfunc = x => x + 2;
Console.WriteLine(myfunc(7)); // This prints 9
// This anonymous method multiplies its input by 2
myfunc = x => x * 2;
Console.WriteLine(myfunc(7)); // This prints 14
}
Notice that we have two anonymous methods here: x => x + 2 and x => x * 2. The first one (x => x + 2) is equivalent to the method Add2 we had before, and the second one (x => x * 2) is equivalent to the method MultBy2 we had before.
In this example I want you to see that the same delegate can point to different methods along the time. This is accomplished by having a variable that points to the methods!
For the second example, I'll present the "callback" pattern. That is a common pattern in which you pass a delegate as a "callback", that is: something that will be called "back to you" from the code you are calling:
// Console Application Example #2 ;)
static void Main()
{
Func<int, bool> filter = IsPair;
// An array with numbers
var array = new int[]{1, 2, 3, 4, 5, 8, 9, 11, 45, 99};
PrintFiltered(array, filter);
}
static bool IsPair(int x)
{
// True for pair numbers
return x % 2 == 0;
}
static void PrintFiltered(int[] array, Func<int, bool> filter)
{
if (array == null) throw new ArgumentNullException("array");
if (filter== null) throw new ArgumentNullException("filter");
foreach (var item in array)
{
if (filter(item))
{
Console.WriteLine(item);
}
}
}
Outputs:
2
4
8
In this code we are having a variable filter that points to the method IsPair. I'll repeat this again and and again: in the line Func<int, bool> filter = IsPair; we are not calling the method IsPair, instead we are taking a reference to it.
Of course, it is possible to do the same without declaring the filter variable, you can pass the method reference directly:
// Console Application Example #2 ;)
static void Main()
{
// An array with numbers
var array = new int[]{1, 2, 3, 4, 5, 8, 9, 11, 45, 99};
PrintFiltered(array, IsPair); //<---
}
static bool IsPair(int x)
{
// True for pair numbers
return x % 2 == 0;
}
static void PrintFiltered(int[] array, Func<int, bool> filter)
{
if (array == null) throw new ArgumentNullException("array");
if (filter== null) throw new ArgumentNullException("filter");
foreach (var item in array)
{
if (filter(item))
{
Console.WriteLine(item);
}
}
}
I cannot stress this hard enough: When I say PrintFiltered(array, IsPair); it is not calling IsPair, it is passing it as a parameter to PrintFiltered. Here effectively you have a method (PrintFiltered) that can take a reference to another method (IsPair) as a reference.
Of course you can write the same code using an anonymous method that replaces IsPair:
// Console Application Example #2 ;)
static void Main()
{
// An array with numbers
var array = new int[]{1, 2, 3, 4, 5, 8, 9, 11, 45, 99};
PrintFiltered(array, x => x % 2 == 0);
}
static void PrintFiltered(int[] array, Func<int, bool> filter)
{
if (array == null) throw new ArgumentNullException("array");
if (filter== null) throw new ArgumentNullException("filter");
foreach (var item in array)
{
if (filter(item))
{
Console.WriteLine(item);
}
}
}
Outputs:
2
4
8
In this example x => x % 2 == 0 is an anonymous method that is equivalent to the method IsPair we had before.
We have successfully filtered the array to only show the numbers that are pair. You can easily reuse the same code for a different filter. For example, the following line can be used to output only the items in the array that are less than 10:
PrintFiltered(array, x => x < 10);
Outputs:
1
2
3
4
7
8
9
With this example I want to show you that you can take advantage of the delegates to improve the reusability of your code, by having parts that change depending on the delegate you pass.
Now that - hopefully - we understand this, it is not hard to think that you could have a list of Delegate objects, and call them in succession:
// Console Application Example #3 ;)
static void Main()
{
// List<Action<int>> is a List that stores objects of Type Action<int>
// Action<int> is a Delegate that represents methods that
// takes an int but does not return (example: void func(int val){/*code*/})
var myDelegates = new List<Action<int>>();
// We add delegates to the list
myDelegates.Add(x => Console.WriteLine(x));
myDelegates.Add(x => Console.WriteLine(x + 5));
// And we call them in succesion
foreach (var item in myDelegates)
{
item(74);
}
}
Outputs:
74
79
You can see both anonymous methods (x => Console.WriteLine(x) and Console.WriteLine(x + 5)) has been called, one after the other... this happens inside the foreach loop.
Now, we can accomplish similar results with a multicast delegate:
// Console Application Example #3 ;)
static void Main()
{
// This is a delegate... we haven't give it a method to point to:
Action<int> myDelegates = null;
// We add methods to it
myDelegates += x => Console.WriteLine(x);
myDelegates += x => Console.WriteLine(x + 5);
// And we call them in succession
if (myDelegates != null) // Will be null if we don't add methods
{
myDelegates(74);
}
}
Outputs:
74
79
Again, both anonymous methods has been called. And this is exactly how events work. The default implementation of an event uses a multicast delegated wrapped inside. Custom implementation of an event may use a list or similar structure to hold the delegates.
Now, if the event is just a list of delegates... that means the event is keeping a reference to all the methods it wants to call. And it also means that you could remove delegates from the list (or add more than one).
If you want to unsubscribe or unbind from an event, you can do so like this:
this.button1.Click -= button1_Click;
For a delegate object to an anonymous method it is a little bit more complicated, because you will need to keep the delegate in a variable to able to pass it back for removal:
Action<int> myDelegates = null;
// Create the delegate
var myDelegate = x => Console.WriteLine(x);
// Add the delegate
myDelegates += myDelegate;
// ...
// Remove the delegate
myDelegates -= myDelegate;
Did you say custom implementation of an event?
Does that means you can create your own events? Yes, and yes. If you want to publish an event in one of your classes you can declare it just like any other member.
This is an example that uses a multicast delegate:
// Event declaration:
public event EventHandler MyEvent;
// Method to raise the event (aka event dispatcher):
priavet void Raise_MyEvent()
{
var myEvent = MyEvent;
if (myEvent != null)
{
var e = new EventArgs();
myEvent(this, e);
}
}
For a custom implementation take this example:
// List to hold the event handlers:
List<EventHandler> myEventHandlers = new List<EventHandler>();
// Event declaration:
event EventHandler MyEvent
{
add
{
lock (myEventHandlers)
{
myEventHandlers.Add(value);
}
}
remove
{
lock (myEventHandlers)
{
myEventHandlers.Remove(value);
}
}
}
// Method to raise the event (aka event dispatcher):
private void Raise_MyEvent()
{
var e = new EventArgs();
foreach (var item in myEventHandlers)
{
item(this, e);
}
}
Hopefully this not hard to read, now that you know how events work. The only details should be lock, it is there because List is not thread-safe. You could also use a thread-safe data structure or a different locking mechanism, I kept this one for simplicity.
Even if you don't write your own events, there are a few things to learn from here:
Event handlers execute consecutively (by default), so it is good idea that event handlers execute fast (maybe defer to asynchronous operations for the hard work) to prevent "clogging" the event dispatcher.
The event dispatcher usually don't handle exceptions (it can be done), so it is good idea to avoid throwing excepting in event handlers.
The "publisher" of the event is keeping a list of the event handlers, it is a good idea to unsubscribe when you don't need need the event handler anymore.
Notes:
While looking for example I found the series of articles "Delegates in C# - Attempt to Look Inside" by Ed Guzman (Part 1, Part 2, Part 3 and Part 4) very easy to read - although a bit outdated - you should check them out. You may want to read the Evolution of Anonymous Functions in C# for a grasp of what's missing.
Some commonly used Delegate Types built-in in .NET include:
Generic
Action<*> (that is: Action<T>, Action<T1, T2> ...)
Func<*, TResult> (that is: Func<T, TResult>, Func<T1, T2, TResult> ...)
EventHandler<TEventArgs>
Comparison<T>
Converter<TInput, TOutput>
Non Generic
Action
Predicate
EventHandler
ThreadStart
ParametrizedThreadStart
You may be interested in LINQ.
Threading and thread-safety it a even broader topic than delegates and events, don't rush to understand it all.
If you want play along with Lambda Expression and C# in general, I suggest to get a copy of LINQPad. This make reduce the hassle of creating new project to test things.
You can of course change the name of your event. It just sounds like you don't know about the designer file :)
The designer file is just the result of your UI design, and if you don't update the name of your event in the UI it does not compile :)
Related
I'm losing my mind trying to figure this out. I am developing a large windows application that requires all the controls in the main form to have their values updated in near real time. I moved the processing of this continuous method to its own thread, which in general is fine, but I knew that it required me to create a Delegate for setting my controls that were created in a different thread. However, I have a series of buttons that need to have the same various properties set for each one, but with different values. I was thinking I could setup a Delegate with a Generic type being Button, so I could simply pass in the proper button control when it is time to update its properties. But I am missing something, and it doesn't work:
//If this is wrong, please let me know
private delegate void SafeButtonText<T>(string value) where T : Button;
private void SetButtonTextSafe<T>(string value) where T : Button
{
//Using the generic Button passed in, set its values
if (T.InvokeRequired) //This doesn't compile
{
var d = new SafeButtonText<T>(SetButtonTextSafe<T>);
T.Invoke(d, new object[] { value }); //This doesn't compile
}
else
T.Text = value; //This doesn't compile
}
I thought I could use it like this (which doesn't seem possible)
SetButtonTextSafe<qualityButton>(values[0]);
If this is possible, or if there is a much better way of doing this, please feel free to tell me in detail. (if I can using this on a Button, I'd create another delegate for other control types as well)
Thanks in advance.
A type is just that...a type. You can't invoke an instance of it because you have no instance. It is merely reflected metadata.
You need to pass an instance of your button to your method.
private delegate void SafeButtonText<T>(T button, string value) where T : Button;
private void SetButtonTextSafe<T>(T button, string value) where T : Button
{
//Using the generic Button passed in, set its values
if (button.InvokeRequired) //This now compiles
{
var d = new SafeButtonText<T>(SetButtonTextSafe<T>);
button.Invoke(d, new object[] { value }); //This now compiles
}
else
button.Text = value; //This now compiles
}
public static void OnAutoScrollToEndChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
{
/* ... */
var scrollToEndHandler = new NotifyCollectionChangedEventHandler((sender, args) => // 수정
{
if (listBox.Items.Count > 0)
{
object lastItem = listBox.Items[listBox.Items.Count - 1];
listBoxItems.MoveCurrentTo(lastItem);
listBox.ScrollIntoView(lastItem);
}
});
if (isAutoScroll)
{
source.CollectionChanged += scrollToEndHandler; // A
}
else
{
source.CollectionChanged -= scrollToEndHandler; //B
}
}
https://michlg.wordpress.com/2010/01/17/listbox-automatically-scroll-to-bottom/
This code is referenced by upper URL.
A(scrollToEndHandler) and B(scrollToEndHandler) are in a function.
When 'AutoScrollToEndProperty' is changed, 'OnAutoScrollToEndChanged' will be called all the time.
I wondering whether These are same reference. Thanks.
If your question is basically, "Does unsubscription actually work here?" the answer is C# compiler implementation-specific, theoretically.
On a practical basis, the body of the lambda expression doesn't capture any local variables, but does capture this (by referring to listBox)... so I'd expect the compiler to generate an instance method containing the body of the code in the lambda expression.
If the method is called multiple times on the same target (i.e. this refers to the same object), I'd expect scrollToEndHandler to be a distinct but equal delegate each time - in other words, it would create a new delegate object in each call (which it probably wouldn't if the lambda expression didn't capture anything, and could be implemented as a static method and the delegate cached)... but the event subscription/unsubscription will still work because the delegates are equal (referring to the same target for the same method).
If the lambda expression referred to any local variables in the method, then event handling wouldn't work, because the compiler would capture those local variables via a separate nested class containing the relevant variables and a method for the delegate code, and each method invocation of OnAutoScrollToEndChanged would create a new instance of that nested class, leading to unequal delegates.
As I say though, that's all implementation-specific... it would be better to just move that code into a separate instance method, to make it clearer that it would work.
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.
I have this simple event :
public class ClassA
{
public event Func<string, int> Ev;
public int Do(string l)
{
return Ev(l);
}
}
And 2 Methods :
static int Display(string k)
{
return k.Length;
}
static int Display_2(string k)
{
return k.Length*10;
}
Im registering this event :
ClassA a = new ClassA();
a.Ev += Display;
a.Ev += Display_2;
Now , I'm executing :
Console.WriteLine(a.Do("aaa"));
the output :
What ???
he has in invocation list 2 methods ! it did run them , but why does it shows only the result from the last registration ?
Where does the result of "3" has gone ? ( the first invocation ) ? ( although both display+display_2 was executed... I didn't expect console.write to iterate through results . but also didn't expect him to decide which to show.)
edit :
There are three aspects at play here:
The implementation of the event
The behaviour of delegate combination
The behaviour of invoking a delegate whose invocation list has multiple entries
For point 1, you have a field-like event. Section 10.8.1 of the C# 4 spec gives an example, and states that:
Outside the declaration of the Button class, the Click member can be used only on the left-hand saide of the += and -= operators, as in
b.Click += new EventHandler(...);
which appends a delegate to the invocation list of the Click event
(emphasis mine). The spec also makes it clear that a field-like event creates a delegate field, which is used from within the class for invocation.
More generally (point 2), section 7.8.4 of the C# 4 spec talks about delegate combination via + and +=:
Delegate combination. Every delegate type implicitly provides the following predefined operator, where D is the delegate type:
D operator +(D x, D y)
The binary + operato performs delegate combination when both operands are of some delegate type D. [... skip bits where x or y are null ...] Otherwise, the result of the operation is a new delegate that, when invoked, invokes the first operand and then invokes the second operand.
(Again, emphasis mine.)
Finally, point 3 - event invocation and return values. Section 15.4 of the C# spec states:
If the delegate invocation includes output parameters or a return value, their final value will come from the invocation of the last delegate in the list.
More generally, it depends on the event implementation. If you use an event implementation which uses the "normal" delegate combination/removal steps, everything is guaranteed. If you start writing a custom implementation which does crazy things, that's a different matter.
As a general rule, it doesn't make sense for events to return a value.
If you want to get information from an event handler it makes more sense for the event handlers to mutate an input parameter, or just call another method of whatever object fired the event to communicate something else.
Normally this doesn't even come up because events logically are passing information to the event handlers, and don't have any need to get information from the event handlers. It's honestly a sign of code smell. An event shouldn't care if anyone has subscribed to it, who they might be, what they might be doing, or even if there are any subscribers. Relying on a return value from them then just creates overly tight coupling.
Invoking a multicast non-void delegate returns the value of the last handler that was executed.
You have very little control over who is first or last. It is a lousy system to use.
That is why most events and delegates return void.
The events are just iterated in the order they were attached. Because you are using a return value, the value you get is the last invoked.
This is not really a normal pattern for events though. You probably want something a bit more like:
public class MyEventArgs : EventArgs
{
public MyEventArgs()
{
Results = new List<int>();
}
public string InputString{get;set;}
public List<int> Results{get;set;}
}
public event EventHandler<MyEventArgs> Ev
public int Do(string l)
{
MyEventArgs e = new MyEventArgs();
e.InputString = l;
if(Ev != null) Ev(this, e);
return e.Results.Sum();
}
and then
static int Display(object sender, MyEventArgs e)
{
return e.Results.Add(k.Length);
}
static int Display_2(object sender, MyEventArgs e)
{
return e.Results.Add(k.Length*10);
}
As my code suggests, I'm trying to create a delegate which will point to the StringBuff method BuffString, which creates a StringBuilder that is going to have a fair amount of settings, etc.
My problem is that, for some reason, no matter what it is I try I can't pass the reference to the StringBuff class I made within my Sprite class to the delegate's constructor without receiving an error. Ontop of that, I feel like creating an event may be useful to help initiate the delegate.
The main problem is that I'm just now barely grasping these two concepts, as well as how to use them as replacements for function pointers which are allowed in other programming languages.
If anyone has any idea on what it is I need to do to make this work, I would definitely appreciate it.
Here's the code:
public class StringBuff
{
private static StringBuilder stringBuffer = new StringBuilder();
public static StringBuilder BuffString(string _string) //--may possibly have to use IntPtr to reference stringBuffer here.
//This is the equivalent to the "strbuff_new" C++ method variant, designed to update the stringBuffer.
{
int iCounter = 0;
stringBuffer.Append(_string + " ");
iCounter += _string.Length + 1;
if (iCounter == stringBuffer.Capacity - 1)
{
stringBuffer.Capacity += stringBuffer.Capacity;
}
return stringBuffer;
}
}
public delegate void UpdateStringBuffer(StringBuff sender);
public class Sprite : SpriteInterface.ISprite
{
private StringBuff stringBuff = new StringBuff();
public event UpdateStringBuffer stringBuffEvent
{
add
{
Console.WriteLine("Adding");
stringBuffEvent += value;
}
remove
{
Console.WriteLine("Removing...");
stringBuffEvent -= value;
}
}
static void Main()
{
new Sprite().stringBuffEvent += new UpdateStringBuffer(stringBuff);
}
}
I believe you are in need for some reading. Refer to the following:
Events Tutorial
Introduction to Delegates and Events
Events and Delegates simplified
You are misunderstanding the use of events and delegate.
When you want to add an Event Handler to an event, you pass a delegate of the same type as the event (which you did correctly)
But when you create a delegate, what you should pass in the constructor (most of the time) is a Method Name and not some variable, since a delegate is a kind of pointer to a (list of) functions.
I reccomend you to read more about delegates as Akram Shahda suggested but just for now i'll tell you that the method that you should pass as parameter to the delegate constructor should have the same signature - means return the same value and accept the same parameters. so for example you could have:
// This method have the same signature as UpdateStringBufferDelegate
public void SomeMethod (StringBuff buff)
{
// Doing somthing here
}
And then you can do in your main:
// Passing method's name and not a variable!!
new Sprite().stringBuffEvent += new UpdateStringBuffer(SomeMethod);
The Actuall parameters that will be passed to the function itself (some StringBuff) only determined at the time of the invokation of the event.
You should read more about that.
Good Luck!
you are doing it wrong,
new Sprite().stringBuffEvent += new UpdateStringBuffer(stringBuff);
Above code is invalid due to following reasons.
1. stringBuff that your UpdateStringBuffer is taking is an instance of StringBuff within Sprite.
2. You are accessing stringBuff from the static Main method which does not have any idea about stringBuff where it is located.
1- The delegate's constructor can only have a parameter Method. Ex
public delegate void UpdateStringBuffer(StringBuff sender);
2- You can declare ur event and add a method to define ur method in ur Splite class. Ex:
public event UpdateStringBuffer stringBuffEvent;
public ProcessUpdateStringBuffer(UpdateStringBuffer yourMethod)
{
stringBuffEvent += yourMethod
}
3- and from ur main u can define ur method to the event and invoke it like this:
Sprite sprite = new Sprite();
sprite.ProcessUpdateStringBuffer(UpdateStringBuffer(urMethod));
sprite.stringBuffEvent(ur parameters);