C# delegate and event in UserControl - c#

I have UserControl similar to ListView. I want to create event machining delete item from ListView.
I doing so. But I do not know how to go on.
public partial class ImagesSetEditor : UserControl
{
public delegate void ImageRemovedEventHandler(object sender, ImagesSetEditor e);
public event ImageRemovedEventHandler ImageRemovedEvent;

You do not need to create a new delegate for conforming with the event based pattern. Create a simple event in your control as such:
public event EventHandler ImageRemoved;
if you need any custom arugments passed on, create a class that derives from EventArgs as such:
public class ImageRemovedEventArgs : EventArgs
{
public int Index; //for example
}
and then declare the event as such:
public event EventHandler<ImageRemovedEventArgs> ImageRemoved;
You would then fire the event as such:
if (ImageRemoved != null) ImageRemoved(this, new ImageRemovedEventArgs() { Index = yourValue });
It is important to check that ImageRemoved != null, because it will throw an exception if the event has no subscribers.

Related

For which purpose the events pattern declares the event firerer method as virtual?

I am trying to understand for which purpose the events pattern decided that the method that fires the event should be declared virtual.
From C#6 in a Nutshell, from Joseph and Ben Albahari, O'Reilley:
Finally, the pattern requires that you write a protected virtual method that fires the
event. The name must match the name of the event, prefixed with the word On, and
then accept a single EventArgs argument:
Below a snippet I created to try to investigate.
I had the impression that the idea was to allow inheriting classes to completely overwrite how the event is handled, out of the box (original class). But the snippet below shows this is not possible, because deriving classes will never be able to invoke the event objects themselves (by the one one of the goals of the constraints imposed by the keyword event on delegates). The event can be invoked only in the containing class.
Now, since the pattern also asks that the method that fires the event simply check if the the event is not null and then call the delegate, with whatever every subscriber asked to do, what is left to be achieved by having the method that fires the event as virtual ? Inheriting classes are obliged to invoke the event the way it is in the broadcaster class, so all that is left for them is to add functionality. But this is exactly what they can achieve by subscribing to the event, in other words, by adding a call to an external function the time the event is fired.
I hope my wording is clear enough.
namespace eventsPatternVirtualEventFirerer
{
internal class Program
{
private static void Main(string[] args)
{
var obj = new X();
obj.ev += Obj_ev;
obj.Start();
}
private static void Obj_ev(object sender, EventArgs e)
{
Console.WriteLine("subscriber code...");
}
}
public class X
{
public event EventHandler<EventArgs> ev;
protected virtual void OnEvent(EventArgs e)
{
Console.WriteLine("original implementation...");
ev?.Invoke(this, e);
}
public void Start()
{
OnEvent(EventArgs.Empty);
}
}
public class X2 : X
{
public X2()
{
}
protected override void OnEvent(EventArgs e)
{
Console.WriteLine("inheriting class implementation overwrite...");
//compilation error - "the event 'X.ev' can only appear on the left hand side of += or -= (except when used from within the type 'X')"
ev?.Invoke(this, e);
}
}
}
I think the purpose is to allow derived classes to do something before/after the event is fired
public class X2 : X
{
public X2()
{
}
protected override void OnEvent(EventArgs e)
{
// Do something before the event
base.OnEvent(e);
// Do something after the event
}
}
There are a few things you can add/change in a derived class
Add a OnBeforeEvent / OnAfterEvent addition.
Choose not to broadcast the event (by conditionally not calling base.OnEvent(e)).
Vary the event args in some way.
Additionally, If you think about the way something like a page model works, it typically fires a Load event to notify when the page is loaded. Without a protected OnLoad method, derived classes would have to subscribe to it's own Load event to perform some action on load
public class MyPage : Page
{
protected override void OnLoad(EventArgs e)
{
// do something when the page is loaded
base.OnLoad(e);
}
}
versus:
public class MyPage : Page
{
public MyPage() : base()
{
this.Load += (sender,e) => {
// bleugh - subscribing to my own events
}
}
}
A good example might be the Paint event in Windows Forms.
// in MyButton : BaseButton : Control
void override OnPaint(object s, PaintEveargs e)
{
base.OnPaint(s, e); // Control: Draw background, BaseButton: draw border
// draw my own stuff
}
A button has several layers of base class, each drawing on top of each other.

Calling public event to trigger method in another class in C#

I wanted to ask if this is Event possible in C#. I have not much worked with Events till now.
Say I have a class A which subscribed to a FormClosing Event of a form:
public class A
{
private void f_FormClosed(object sender, FormClosedEventArgs e)
{
//Now here a public Event should be called
}
}
Now there I want a public Event to be called. Let's say now I have another class B which has a certain method.
public class B
{
public void DoSomething()
{
}
}
Now what I want to do:
A Form gets closed so class A is getting notified. There, a public Event gets triggered (which is somewhere in a public class). I want to subscribe my method in class B to this Event so it gets called when that happens. Is this possible? And how is the syntax? I haven't found something useful till now.
Edit: I can't create an instance of class B directly from class A.
Its possible .
Create a new event in A.
Raise the event within the eventhandler f_FormClosed
Subscribe to this event in B.
Within the eventhandler in B call the method DoSomething
For the syntax part you could check MSDN
// A delegate type for hooking up change notifications.
public delegate void ChangedEventHandler(object sender, EventArgs e);
// A class that works just like ArrayList, but sends event
// notifications whenever the list changes.
public class ListWithChangedEvent: ArrayList
{
// An event that clients can use to be notified whenever the
// elements of the list change.
public event ChangedEventHandler Changed;
// Invoke the Changed event; called whenever list changes
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
//you raise the event here.
Changed(this, e);
}
}
Now in your other class do something like this
class EventListener
{
private ListWithChangedEvent List;
public EventListener(ListWithChangedEvent list)
{
List = list;
// Add "ListChanged" to the Changed event on "List".
//This is how we subscribe to the event created in ListWithChangedEvent class
List.Changed += new ChangedEventHandler(ListChanged);
}
// This will be called whenever the list changes.
private void ListChanged(object sender, EventArgs e)
{
Console.WriteLine("This is called when the event fires.");
}
}

Events - Publish & Subscribe

Lets say I have a class which has a static event in it. This event is subscribe by three or more different classes. [Lets say 4]
Now when something noteworthy happen the event in class got raised.
As 4 different classes subscribe to the event, the corresponding handler in them execute their respective code.
Now if i don't want the handler code of my class no 3 & 4 to execute. What should i need to do?
Please help.
Thanks in Advance!
Under what conditions do you want your handlers to fire?
You can have the following pattern which will provide a mechanism to prevent the handlers firing based on a unique identifier.
In this example, I create some simple event args which the event will use to tell the handler a unique identifier (Guid):
public class MyEventArgs : EventArgs { public Guid Identifier { get; set; } }
Then, create a simple class to raise the event:
public class EventGenerator
{
public EventHandler<MyEventArgs> TheEvent;
public void RaiseEvent(Guid identifier)
{
if (TheEvent != null)
TheEvent(this, new MyEventArgs(){Identifier = identifier});
}
}
Finally, you can have a class (any number of these) which will all subscribe to the event but will only run it when the event args supplies a different identifier:
public class TheClass
{
private readonly Guid _identifier;
private EventGenerator _eventGenerator;
// The constructor is given the event generator class instance
public TheClass(EventGenerator evGen)
{
// create a unique identifier for the class
_identifier = Guid.NewGuid();
// subscribe to the event
_eventGenerator = evGen;
_eventGenerator.TheEvent += TheEvent;
}
private void TheEvent(object sender, MyEventArgs e)
{
// when the event fires, check the Guid and if it isn't a match, don't continue ...
if (e.Identifier == _identifier) return;
// rest of the handler goes here ...
}
}
This is just an example, however - you may need something different which might be achievable by simply unsubscribing to the event at choice times. It depends on the answer to my initial question.

C# event from a class in a custom usercontrol never fires

I have a class that has an event that's suppose to fire everytime one of it's property changes.
public event EventHandler StructureChanged;
protected virtual void NotifyStructureChanged(EventArgs e)
{
if (StructureChanged != null)
{
StructureChanged(this, e);
}
}
I include NotifyStructureChanged(new EventArgs()); in my set statement in my properties.
whenever it calls the method the StructureChangedis always null. My class is a private member in a custom usercontrol and the class event is registered in the constructor of the usercontrol like so
_pt.StructureChanged += _pt_StructureChanged;
and handled here
void _pt_StructureChanged(object sender, EventArgs e)
{
UpdateControl();
}
What I have so far is a custom class with an event that's a private member of a custom user control. I register my class event in the custom usercontrol. Whenever the class property changes, I update my control to reflect the changes in the class.
What am I doing wrong here? I have a button on my usercontrol and am able to register that event, why can't I register my class event?
If StructureChanged is null than you attach event handler after event was fired (or you are detaching handler somewhere).
Also don't pass EventArgs - its just useless dummy parameter.
public event EventHandler StructureChanged;
protected virtual void OnStructureChanged()
{
if (StructureChanged != null)
StructureChanged(this, EventArgs.Empty);
}
And call this method in setter:
public Foo Bar
{
get { return _bar; }
set {
if (_bar == value)
return;
_bar = value;
OnStructureChanged();
}
}

C# User Control - How to tell containing object the control needs data

I am creating a C# WinForms user control. There will be times when the user control will need data from the form it's contained in. How do I go about having the user control tell the form containing it that it needs some data?
Thanks!
You can subscribe the form to an event raised on the UserControl.
Your archiecture dictates where and when you need to subscribe to the data event. We can't answer that without knowing a little more about how your whether you are adding the control at runtime or design time. Each case will require a little derivation. From the perspective of adding your control at runtime, you could do something similar to the following:
// Your sample control
public class MyUserControl : Control
{
public event EventHandler<EventArgs> INeedData;
public Data Data {get; set;}
private class DoSomething()
{
if(INeedData!=null) INeedData(this,null);
}
}
...
// Your Form, in the case that the control isn't already added.
var _myUserControl = new MyUserControl();
private void Form1_Load(object sender, EventArgs e)
{
_myUserControl.INeedData += new EventHandler<EventArgs>(MyUserControl_INeedData);
this.Controls.Add(myUserControl);
}
void MyUserControl_INeedData(object sender, EventArgs e)
{
_myUserControl.Data = SomeData;
}
Create a custom event in the user control and have the form hook into it. If you need custom event arguments, you can create those too.
In user control:
//Define your Custom Event argument
public class MyEventArgs : EventArgs
{
//Define some fields of your custom event argument
private int m_SomeValue = 0;
//Define some properties of your custom event argument
public int SomeValue
{
get { return m_SomeValue; }
set { m_SomeValue = value; }
}
}
//Define the event handler data type
public delegate void MyEventHandler(object sender, MyEventArgs e);
//Define the object which holds the outside event handlers
public event MyEventHandler SomeEvent;
//Define the function which will generate the event
public virtual void OnSomeEvent(MyEventArgs e)
{
if (SomeEvent != null)
SomeEvent(this, e);
}
.
. //Then later in the control
.
{
//We need new data
//Create the event arguments
MyEventArgs newEvent = new MyEventArgs();
//Set the values
newEvent.SomeValue = 17;
//Call the event generating function
OnSomeEvent(newEvent);
}
In your form just use something like:
myControl.SomeEvent += new MyEventHandler(handlerName);
Since your event is public, you should see it in the Properties window of your control as well.
You can fancy up the event using Metadata attributes, but I leave it up to you to discover these.
Create an event on the user control where the event args are editable. Let the form attach a handler to that event, which updates those fields. Use those fields in the OnEvent method.
[untested]
eg.
public delegate void NeedsUserDataEventHandler(object sender, NeedsUserDataEventArgs args);
public class NeedsUserDataEventArgs : EventArgs
{
public UserData UserData { get; set; }
}
// In Control
public event NeedsUserDataEventHandler NeedsUserData;
public void OnNeedsUserData(NeedsUserDataEventArgs args)
{
NeedsUserDataEventHandler handler = NeedsUserData;
if (handler != null) handler(this, args);
// store your data somewhere here
}
// In Form
public override void OnLoad(object sender, EventArgs args)
{
control.NeedsUserData += ControlNeedsUserData;
}
public override void OnClosed(object sender, EventArgs args)
{
control.NeedsUserData -= ControlNeedsUserData;
}
public void ControlNeedsUserData (object sender, NeedsUserDataEventArgs args)
{
args.UserData = // set whatever here
}
Seems a bit vague to me, but:
Make it an event in the containing WinForm, so that every time some data is ready all the subscribers can be notified in a one-to-many model; or make it an event in the subscribed control, in a one-to-one model, in which it calls the container's method that retrieves such data?
It's dependent on when that data needs to be pushed to the UserControl. Are there events taking place on the Form that will drive the need to move data within the UserControl? If so...simply grab your instance at that point and push the data down to the UserControl via a public property.
If this is a case where events are not being used or the Form in some fashion or another "receives the data" then exposing an event on the Form such as...
public event DataHandler ReceivedData;
...and allow the UserControl or any other container to register for the event and receive the data via your custom event args. Pushing the event into the UserControl and forcing the Form to latch onto the UserControl seems backwards since the Form is the initiator of the data.

Categories