I am writing several UserControls for other programmers here.
Some Exposed EventHandlers with same name as the base are accepted
(UserControl CodesCombo -> SelectedValueChanged)
some aren't
(UserControl TextBox -> TextChanged)
I'm writing a UserControl which contains a TextBox. I need to expose the TextChanged event to the potential consumers of this control.
I have a similar control based on a ComboBox, and in that I used
public event EventHandler SelectedValueChanged
{
add { cbMain.SelectedValueChanged += value; }
remove { cbMain.SelectedValueChanged -= value; }
}
to expose the "Change" event "SelectedValueChanged", and it works without without any problems.
However, when I try to use this technique in my TextBox based control in a similar way
public event EventHandler TextChanged
{
add { tbMain.TextChanged += value; }
remove { tbMain.TextChanged -= value; }
}
I get a warning message:
'MyTextBox.TextChanged' hides inherited member 'UserControl.TextChanged'. Use new keyword if hiding was intentional.
I'm not entirely certain what the message means, other than the obvious, but what I do know is that I don't -think- I want to hide anything. I have internal SelectedValueChanged and TextChanged functions (cbMain_SelectedValueChanged, tbMain_TextChanged) which do a few things I need, but I want to allow the consumer to get an Event call on text change as well, just like they do in the ComboBox based one.
Also, I get no "change" event at all in the available list of event in the test program.
I've gotten around this for now by exposing the event as "TextChange"
new public event EventHandler TextChange
{
add { tbMain.TextChanged += value; }
remove { tbMain.TextChanged -= value; }
}
which gives me an event in the list and seems to work well enough, but I'd prefer to have a general solution to this as we're making several more controls along these lines for our package and I don't think I can get away with having names that are just "off".
Any idea what this message is really telling me, and how I can get my event internally, and also still get the user theirs?
Thanks!
Update: Asked for more specific code:
namespace NCFLSToolbox
{
public partial class NCFLSCodesCombo : UserControl
{
//Listed in the Events for System.Windows.Forms.ComboBox
private void cbMain_SelectedValueChanged(object sender, EventArgs e)
{
ControlRequiredColoring();
}
//Exposed Event for user
public event EventHandler SelectedValueChanged
{
add { cbMain.SelectedValueChanged += value; }
remove { cbMain.SelectedValueChanged -= value; }
}
}
public partial class NCFLSTextbox : UserControl
{
//Listed in the Events for System.Windows.Forms.TextBox
private void tbMain_TextChanged(object sender, EventArgs e)
{
ControlRequiredColoring();
}
//Couldn't expose "TextChanged" by name...
////public event EventHandler TextChanged
//// {
//// add { tbMain.TextChanged += value; }
//// remove { tbMain.TextChanged -= value; }
//// }
//...so I exposed "TextChange" instead.
public event EventHandler TextChange
{
add { tbMain.TextChanged += value; }
remove { tbMain.TextChanged -= value; }
}
}
}
Any idea what this message is really telling me?
First off, understand what it means to hide. Forget about the fact that it's an event for a moment. If we have:
class B { public void M() { Console.WriteLine("B.M()"); } }
class D : B { public void M() { Console.WriteLine("D.M()"); } }
then we have two methods both called M. If you say:
D d = new D();
B b = d;
d.M(); // D.M();
b.M(); // B.M();
The compiler is warning you that you have two methods, not one, and which one you get depends on the compile-time type of the receiver, NOT the run-time type of the receiver.
Why is that probably not what you want?
Three reasons.
First, many C# programmers come to C# from Java, where methods are automatically overridden. In C# methods have to be virtual to be overridden. The compiler is telling you that you are not getting the semantics you might expect.
Second, this is to mitigate the brittle base class problem. Suppose the author of B gives the D team a DLL assembly containing B without M, and D derives from it, adding method D.M. Then the B team realizes that they could implement M, so they add it to B and give the D team a new assembly. Now the D team should be warned that B.M exists, so that they can decide whether to delete D.M or not.
Third, why are you doing this in the first place? If the base class already has an event that you want, just use it! Don't make a new one that uses the old one; just use the old one. The compiler is telling you that you're definitely doing something strange and probably wrong.
If it is your intention to have two members on two different classes where one hides the other, you tell the compiler "I have thought about this and this is intentional" by putting new on the member. That is "this is a new member, and I meant to make it a new member, not an override of an old member".
The problem is that TextBox events do not propagate to the parent user control. If you wish them to do so, there are two ways to accomplish this:
1) Have the event on the user control ferry all additionals/removals to the event handler to the UserControl's event handler. This is roughly what your question is trying to do. However, I don't recommend it.
2) Have the event on the TextBox trigger events on the parent user control.
So, just run this code in your constructor, below InitializeComponent():
tbMain.TextChanged += (sender,e)=>OnTextChanged(e);
With this approach, a TextChanged event in the TextBox will call OnTextChanged, which raises a TextChanged event. You cannot invoke base class events directly (hence why the OnTextChanged method is provided).
Edit: tbMain.TextChanged += (sender,e)=>OnTextChanged(e); is semantically equivalent to the below code:
tbMain.TextChanged += OnTbMainTextChanged;
...
} //End of Constructor
private void OnTbMainTextChanged(object sender, EventArgs e)
{
OnTextChanged(e);
}
The benefit of using a lambda function is that it is more self-contained. Among other benefits, using a self-contained lambda function makes it obvious to future code maintainers that the sender is not being propagated, without requiring the maintainer to navigate to the named method. This is what you want: from the perspective of subscribers to the user control, your use of a TextBox to implement your control is an implementation detail.
Related
Suppose I have a class say a viewmode class mvvm. Then there are some event handlers created for this vm. then it could be used by many others with different situation.
So if I have an instance of myvm, I want to detect if there is any event handler hooked up and want to release it for memory issue.
What's the generic way to do this out of myvm, for example, I may not have the source code of myvm?
Events are designed such that code outside the class that declared them cannot get access to the underlying delegate. For example, according to Section "10.8 Events" in the C# Language specification (emphasis mine):
In an operation of the form x += y or x -= y, when x is an event and
the reference takes place outside the type that contains the
declaration of x, the result of the operation has type void (as
opposed to having the type of x, with the value of x after the
assignment). This rule prohibits external code from indirectly
examining the underlying delegate of an event.
Therefore, finding out what is subscribed to the event outside the class may be, at best, a "work around".
If you have access to the source of the class containing the event and you want to keep track of delegates hooked up to an event, implement the add and remove keyword in the event definition and manually keep track of them in a Dictionary.
If I understand you correctly.
This class wraps the unknown myvm class which I use SocketAsyncEventArgs to illustrate, cos obviously we don't have the source code for SocketAsyncEventArgs class.
And I wrapped the Completed event of SocketAsyncEventArgs class. When that event is triggered, _instance_Completed will be fired, then _myvm event will be fired. So what we need to do is subscribe/unsubscribe _myvm event.
Then I leave an event for people to subscribe/unsubscribe _myvm event, as subscribing/unsubscribing, the delegates are stored into a List therefore you can clear the
by call the ClearEvents() method.
Hope it will help.
public class WrapperClass
{
private EventHandler<SocketAsyncEventArgs> _myEvent;
private SocketAsyncEventArgs _myvm;
private List<Delegate> delegates;
public WrapperClass()
{
delegates = new List<Delegate>();
}
public void SetInstance(SocketAsyncEventArgs myvm)
{
_myvm = myvm;
_myvm.Completed += new EventHandler<SocketAsyncEventArgs>(_instance_Completed);
}
private void _instance_Completed(object sender, SocketAsyncEventArgs e)
{
if (_myEvent != null)
{
_myEvent(sender, e);
}
}
public event EventHandler<SocketAsyncEventArgs> myEvent
{
add
{
delegates.Add(value);
_myEvent = (EventHandler<SocketAsyncEventArgs>)Delegate.Combine(_myEvent, value);
}
remove
{
delegates.Remove(value);
_myEvent = (EventHandler<SocketAsyncEventArgs>)Delegate.Remove(_myEvent, value);
}
}
public void ClearEvents()
{
foreach (var d in delegates)
{
_myEvent = (EventHandler<SocketAsyncEventArgs>)Delegate.Remove(_myEvent, d);
}
}
}
I have an event in a loop. I am trying to prevent the same method being added to an event more than once. I've implemented the add and remove accessors.
However, I get an error stating that:
ItemsProcessed can only appear on the left hand side of += or -=
When I try to call them, even within the same class.
ItemsProcessed(this, new EventArgs()); // Produces error
public event EventHandler ItemsProcessed
{
add
{
ItemsProcessed -= value;
ItemsProcessed += value;
}
remove
{
ItemsProcessed -= value;
}
}
With an explicit event, you need to provide your own backing store - either a delegate field or something like EventHandlerList. The current code is recursive. Try:
private EventHandler itemsProcessed;
public event EventHandler ItemsProcessed
{
add
{
itemsProcessed-= value;
itemsProcessed+= value;
}
remove
{
itemsProcessed-= value;
}
}
Then (and noting I'm being a little cautious about the "about to turn null" edge-case re threading):
var snapshot = itemsProcessed;
if(snapshot != null) snapshot(this, EventArgs.Empty);
With more recent C# versions, this can be simplified:
itemsProcessed?.Invoke(this, EventArgs.Empty);
I can't tell from your post if you are trying to raise the event from a derived class or not, but one thing I've found is that you can't define an event in a base class and then raise it (directly) in a derived class, for some reason that isn't real clear to me yet.
So I define protected functions in base classes to raise events (that are defined in those base classes), like this:
// The signature for a handler of the ProgressStarted event.
// title: The title/label for a progress dialog/bar.
// total: The max progress value.
public delegate void ProgressStartedType(string title, int total);
// Raised when progress on a potentially long running process is started.
public event ProgressStartedType ProgressStarted;
// Used from derived classes to raise ProgressStarted.
protected void RaiseProgressStarted(string title, int total) {
if (ProgressStarted != null) ProgressStarted(title, total);
}
Then in the derived class, I call RaiseProgressStarted(title, total) instead of calling ProgressStarted(title, total).
It seems like kind of the long way around. Maybe someone else knows of a better way around this problem.
It seems that if you implement the EventHandler explicitly, you can't refer to the 'Property' when firing the event. You must refer to the backing store.
What error? I guess its stack overflow error, because you are calling add and remove on yourserlf (same event). Also you cannot raise event ACCESSOR.
Valid way to do this is to create backing private event, that will be added and removed to from public accessor, and you should raise this private event.
Dang, minute late.
I'm currently developing a tiny technical Framework that is independant of any applications. Business code just refers to this Framework.
According this article : http://msdn.microsoft.com/en-us/library/5z57dxz2.aspx (exemple 2), we need to provide a delegate for the custom event.
Problem is, anyone can Invoke my handler (and then raise the event), even in my Business Code and that isn't logical for me, so what is the best way to raise a custom Event with a delegate that is only "internal" and not "public" ?
Thanks for help.
I am not sure if I get it right or not. I think that you feel like if you provide a public Delegate type for your custom event, anyone will be able to Raise that event.
Well, that is not true. Only the class that defines that custom event can raise it. If this is your issue, don't worry.
Not true. It's not allowed to invoke an event outside the class which the event belongs to. Others can only use += and -= operators to your event. Only in the class, you can invoke the event. That is a difference between an event and a normal delegate. That is:
public Data
{
public event EventHandler OnSave
public EventHandler OnLoad;
private void Load()
{
if (OnLoad!=null) OnLoad();
//other operations
}
private void Save()
{
if (OnSave!=null) OnSave();
//other operations
}
}
And outside the class:
Data data = new Data();
data.OnLoad += (s,e) => {};
data.OnSave += (s,e) => {};
data.OnLoad = (s,e)=>{};
//data.OnSave = (s,e)=>{}; //invalid
data.OnLoad();
//data.OnSave(); //invalid
The delegate is just a type declaration describing the "signature" of your event. This has to be public. To actually invoke your event you often implement a method named OnEvent (where you substitute Event with Click or Closed or whatever describes your event). This method should be private (or protected) in your class.
You cannot declare an event using a delegate that is less "visible" than the event.
Problem is, anyone can Invoke my handler (and then raise the event), even in my Business Code
That isn't true. You declare an event as follows:
public event FooEventHandler Foo;
The only thing that external code can do with the event is subscribe to it (+=), or unsubscribe from it (-=). It can't access the actual delegate, which is generated by the compiler as a private field. In other words, this code would be invalid :
SomeClass x = new SomeClass();
x.Foo(x, new FooEventArgs()); // compilation error here
Don't forget that an event is actually a pair of methods (add and remove). The compiler rewrites the event declaration to something along those lines:
private FooEventHandler _foo;
public event FooEventHandler Foo
{
add { _foo += value; }
remove { _foo -= value; }
}
(the generated code is actually a bit more complex, with some locking to ensure thread safety)
As you can see, the _foo field is private, so client code can't access it. Only the event's add and remove accessors are accessible.
One way of doing it:
Instead of public event, create a method that will manually subscribe your desired delegates, and store them in `private List _delegates' field.
Then, from the 'inside', call each of them when you desire.
public class Framework
{
public delegate void Method();
public void AttachEvent(Method M)
{
_methods.Add(M);
}
private List<Method> _methods;
private FireMethods()
{
_methods.Foreach(x=>x.Invoke());
}
}
Or, you can embrace 'by design' feature of the events that they aren't publicly Invoke()-able.
:)
I have declared a generic event handler
public delegate void EventHandler();
to which I have added the extension method 'RaiseEvent':
public static void RaiseEvent(this EventHandler self) {
if (self != null) self.Invoke();
}
When I define the event using the typical syntax
public event EventHandler TypicalEvent;
then I can call use the extension method without problems:
TypicalEvent.RaiseEvent();
But when I define the event with explicit add/remove syntax
private EventHandler _explicitEvent;
public event EventHandler ExplicitEvent {
add { _explicitEvent += value; }
remove { _explicitEvent -= value; }
}
then the extension method does not exist on the event defined with explicit add/remove syntax:
ExplicitEvent.RaiseEvent(); //RaiseEvent() does not exist on the event for some reason
And when I hover over to event to see the reason it says:
The event 'ExplicitEvent' can only
appear on the left hand side of += or
-=
Why should an event defined using the typical syntax be different from an event defined using the explicit add/remove syntax and why extension methods do not work on the latter?
EDIT: I found I can work around it by using the private event handler directly:
_explicitEvent.RaiseEvent();
But I still don't understand why I cannot use the event directly like the event defined using the typical syntax. Maybe someone can enlighten me.
When you create a "field-like" event, like this:
public event EventHandler Foo;
the compiler generates a field and an event. Within the source code of the class which declares the event, any time you refer to Foo the compiler understand that you're referring to the field. However, the field is private, so any time you refer to Foo from other classes, it refers to the event (and therefore the add/remove code).
If you declare your own explicit add/remove code, you don't get an auto-generated field. So, you've only got an event, and you can't raise an event directly in C# - you can only invoke a delegate instance. An event isn't a delegate instance, it's just an add/remove pair.
Now, your code contained this:
public EventHandler TypicalEvent;
This is slightly different still - it wasn't declaring an event at all - it was declaring a public field of the delegate type EventHandler. Anyone can invoke that, because the value is just a delegate instance. It's important to understand the difference between a field and an event. You should never write this kind of code, just as I'm sure you don't normally have public fields of other types such as string and int. Unfortunately it's an easy typo to make, and a relatively hard one to stop. You'd only spot it by noticing that the compiler was allowing you to assign or use the value from another class.
See my article on events and delegates for more information.
Because you can do this (it's non-real-world sample, but it "works"):
private EventHandler _explicitEvent_A;
private EventHandler _explicitEvent_B;
private bool flag;
public event EventHandler ExplicitEvent {
add {
if ( flag = !flag ) { _explicitEvent_A += value; /* or do anything else */ }
else { _explicitEvent_B += value; /* or do anything else */ }
}
remove {
if ( flag = !flag ) { _explicitEvent_A -= value; /* or do anything else */ }
else { _explicitEvent_B -= value; /* or do anything else */ }
}
}
How can the compiler know what it should do with "ExplicitEvent.RaiseEvent();"?
Answer: It can't.
The "ExplicitEvent.RaiseEvent();" is only syntax sugar, which can be predicated only if the event is implicitly implemented.
That's because you're not looking at it right.
The logic is the same as in Properties.
Once you've set the add/remove it's no longer an actual event, but a wrapper to expose the actual event (events can only be triggered from inside the class itself, so you always have access locally to the real event).
private EventHandler _explicitEvent;
public event EventHandler ExplicitEvent {
add { _explicitEvent += value; }
remove { _explicitEvent -= value; }
}
private double seconds;
public double Hours
{
get { return seconds / 3600; }
set { seconds = value * 3600; }
}
In both cases the member with the get/set or add/remove property doesn't really contain any data. You need a "real" private member to contain the actual data.
The properties just allow you program extra logic when exposing the members to outside world.
A good example for WHY you'd want to do it, is to stop extra computation when it's not needed (no one is listening to the event).
For example, lets say the events are triggered by a timer, and we don't want the timer to work if no-one is registered to the event:
private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
private EventHandler _explicitEvent;
public event EventHandler ExplicitEvent
{
add
{
if (_explicitEvent == null) timer.Start();
_explicitEvent += value;
}
remove
{
_explicitEvent -= value;
if (_explicitEvent == null) timer.Stop();
}
}
You'd probably want to lock the add/remove with an object (an afterthought)...
The "plain" declaration for TypicalEvent does some compiler trickery. It creates an event metadata entry, add and remove methods and a backing field. When your code refers to TypicalEvent, the compiler translates it into a reference to the backing field; when external code refers to TypicalEvent (using += and -=), the compiler translates it into a reference to the add or remove method.
The "explicit" declaration bypasses this compiler trickery. You are spelling out the add and remove methods and the backing field: indeed, as TcKs points out, there may not even be a backing field (this is a common reason for using the explicit form: see e.g. events in System.Windows.Forms.Control). Therefore the compiler can no longer quietly translate the reference to TypicalEvent into a reference to the backing field: if you want the backing field, the actual delegate object, you have to reference the backing field directly:
_explicitEvent.RaiseEvent()
I started with a question, and in typing the question, found the answer, but instead of deleting, I thought it might be helpful to A) get confirmation, and B) help others.
If I have an event, and several places in the application add listeners, what is the best way to remove all listeners at once? For example, I can ...
myPage.OnPageOpened += OpenPage;
and later in my code ...
myPage.OnPageOpened -= OpenPage;
But what if I have unknown 3rd party subscribers and I want to press a magic Reset button that clears everything and starts from scratch?
You can use += and -= operators anywhere against the EventHandler, because the operator overloads are public. The = overloaded operator is private it can only be called in the defining class.
So in the defining class I can use this to clear my EventHandler.
OnPageOpened = null;
And to expose that functionality, I could ...
public void ClearPageOpenedEvents() {
OnPageOpened = null;
}
Is that correct?
Yes, you are correct. The reason for this is that the compiler creates a private delegate object under the covers, like this:
private EventHandler pageOpened;
public EventHandler PageOpened
{
add { pageOpened += value; }
remove { pageOpened -= value; }
}
Inside your class, you have a reference to the private delegate instance, so that's why you can do the assignment. You definitely want to expose a method to clear the targets if that's functionality you need; you don't want to expose the delegate itself.
That's the way to do it, but how does something outside the class know that the class should drop all its event listeners? What if someone extending/using your code is expecting that event on an ongoing basis?
You can use the assignment operator on an event because that's how adding and removing events work. Using Reflector shines a lot of light on how events are done in C#.
Given the simple class of
public class MyClass
{
public event EventHandler MyEvent;
}
The following code is produced when compiled
public class MyClass
{
private EventHandler MyEvent;
public event EventHandler MyEvent;
}
So when you are referencing MyEvent you are referring to the private delegate variable MyEvent. The += and -= operators are "special" (because they aren't operators) and get changed into calling the add and remove methods that are created for the event (which use the assignment operator themselves).
[MethodImpl(MethodImplOptions.Synchronized)]
public void add_MyEvent(EventHandler value)
{
this.MyEvent = (EventHandler) Delegate.Combine(this.MyEvent, value);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void remove_MyEvent(EventHandler value)
{
this.MyEvent = (EventHandler) Delegate.Remove(this.MyEvent, value);
}