I have a winform winform1 and 2 user controls control1 and control2 on this form
Now I want to define a custom event, which is raised/fired in control1 and received in control2. The event should be global and not directly defined in control1. control2 should not know about the existence of control1.
The event should also be raised by other controls. How is the C# code for that? Do I need something like a publisher class?
What you describe looks like the Mediator pattern, in which objects communicate through messages. These messages can be implemented as events, callbacks, or any other mechanism.
You could use an implementation like MVVM Light's Messenger class (this framework is intended for use with WPF and Silverlight, but you can get the code for this particular class and use it in WinForms)
// Register for a specific message type
Messenger.Default.Register<TypeOfTheMessage>(this, DoSomething);
...
// Called when someone sends a message of type TypeOfTheMessage
private void DoSomething(TypeOfTheMessage message)
{
// ...
}
// Send a message to all objects registered for this type of message
Messenger.Default.Send(new TypeOfTheMessage(...));
A big advantage of the Messenger class over a static event is that it uses weak references, so it doesn't prevent garbage collection of subscribed objects, which reduces the risk of memory leaks.
See this link for details about the Messenger class
You can use a static event:
public static class MyGlobalEvent {
public static event EventHandler MyEvent;
public static void FireMyEvent(EventArgs args)
{
var evt = MyEvent;
if (evt != null)
evt(args);
}
}
Subscribe in the usual way:
MyGlobalEvent.MyEvent += args => Console.WriteLine("Event Was Fired.");
Fire as you see fit:
MyGlobalEvent.FireMyEvent(new EventArgs());
So you can make your form publisher(and a mediator between controls), and all of your controls will be subscribers that will be notified on event.
An event occurred in a control, form will be notified and event handler on form will notify other controls that subscribed to this event.
Related
This question already has answers here:
Understanding events and event handlers in C#
(13 answers)
Closed 2 years ago.
i have a question,
regarding event delegates. I had a a look, but i am not sure i still quite get it.
For example i have seen event delegates in constructor and it was the only place where the method was called..
Player.Finished+= new FinishedEventHandler(Finished);
and when i have called the method there directly it had completely different impact as just calling Player.Finished+= new FinishedEventHandler(Finished); seemed to be doing nothing. Maybe you can point me to some website where i can find this explained in better way?
This can help you to understand events and delegates:
Events in .NET are based on the delegate model. The delegate model follows the observer design pattern, which enables a subscriber to register with and receive notifications from a provider. An event sender pushes a notification that an event has happened, and an event receiver receives that notification and defines a response to it. This article describes the major components of the delegate model, how to consume events in applications, and how to implement events in your code.
An event is a message sent by an object to signal the occurrence of an action. The action can be caused by user interaction, such as a button click, or it can result from some other program logic, such as changing a property’s value. The object that raises the event is called the event sender. The event sender doesn't know which object or method will receive (handle) the events it raises. The event is typically a member of the event sender; for example, the Click event is a member of the Button class, and the PropertyChanged event is a member of the class that implements the INotifyPropertyChanged interface.
To define an event, you use the C# event or the Visual Basic Event keyword in the signature of your event class, and specify the type of delegate for the event. Delegates are described in the next section.
Typically, to raise an event, you add a method that is marked as protected and virtual (in C#) or Protected and Overridable (in Visual Basic). Name this method OnEventName; for example, OnDataReceived. The method should take one parameter that specifies an event data object, which is an object of type EventArgs or a derived type. You provide this method to enable derived classes to override the logic for raising the event. A derived class should always call the OnEventName method of the base class to ensure that registered delegates receive the event.
A simple example is the Button control: when you click on it, the event OnClick is raised and the control call all delegates that have suscribed to it using:
Click += SomeMethod;
Or (it is the same):
Click += new EventHandler(SomeMethod);
If fact, it adds a reference to the method in the event handler list.
An event is just a list of methods to call in case of the event is raised, like with the button click.
A delegate is just a signature of a method without a body implementation, also called a prototype, to be used as a type, to have strong typing when adding events to an event handler like the button click. So when you assign a method implemented, by its name, it must match the delegate signature (return type and parameters, the name of the delegate itself is not pertinent except for humans).
We also can use lambda:
myButton1.Click += (sender, e) => Close();
myButton2.Click += (sender, e) => { MessageBox.Show("Closing"); Close() };
Handling and raising events (MS Docs)
C# - Events(TutorialsPoint)
C# - Events (TutorialsTeacher)
What are C# Events? (YouTube)
C# Tutorial: Events/Event Handlers (YouTube)
I have a winform winform1 and 2 user controls control1 and control2 on this form
Now I want to define a custom event, which is raised/fired in control1 and received in control2. The event should be global and not directly defined in control1. control2 should not know about the existence of control1.
The event should also be raised by other controls. How is the C# code for that? Do I need something like a publisher class?
What you describe looks like the Mediator pattern, in which objects communicate through messages. These messages can be implemented as events, callbacks, or any other mechanism.
You could use an implementation like MVVM Light's Messenger class (this framework is intended for use with WPF and Silverlight, but you can get the code for this particular class and use it in WinForms)
// Register for a specific message type
Messenger.Default.Register<TypeOfTheMessage>(this, DoSomething);
...
// Called when someone sends a message of type TypeOfTheMessage
private void DoSomething(TypeOfTheMessage message)
{
// ...
}
// Send a message to all objects registered for this type of message
Messenger.Default.Send(new TypeOfTheMessage(...));
A big advantage of the Messenger class over a static event is that it uses weak references, so it doesn't prevent garbage collection of subscribed objects, which reduces the risk of memory leaks.
See this link for details about the Messenger class
You can use a static event:
public static class MyGlobalEvent {
public static event EventHandler MyEvent;
public static void FireMyEvent(EventArgs args)
{
var evt = MyEvent;
if (evt != null)
evt(args);
}
}
Subscribe in the usual way:
MyGlobalEvent.MyEvent += args => Console.WriteLine("Event Was Fired.");
Fire as you see fit:
MyGlobalEvent.FireMyEvent(new EventArgs());
So you can make your form publisher(and a mediator between controls), and all of your controls will be subscribers that will be notified on event.
An event occurred in a control, form will be notified and event handler on form will notify other controls that subscribed to this event.
I have the following scenario that I am hoping to find a resolution for, I have a custom Window class and I have created an event as below (i have remove some of the code for brevity)
public class AeroWindow : Window
{
public delegate void SystemMenuEventHandler(object sender);
public event SystemMenuEventHandler Exit;
...
public override void OnApplyTemplate()
{
...
var exitButton = this.GetTemplateChild("SM_ExitButton") as Button;
if (exitButton != null)
{
exitButton.Click += (sender, args) => { this.OnExit(); };
}
}
protected virtual void OnExit()
{
if (this.Exit != null)
{
this.Exit(this);
}
}
}
I am using MVVM with Calibutn.Micro and i have a ShellViewModel and ShellView (the ShellView inherits from AeroWindow)
What I would like to know is the following:
How should I correctly create custom events, is the above correct?
How do i then bind to said "event" in the view model
Can the same method of event be used to bubble the events from one view model to another (for example I have the ShellViewModel which initially loads a LoginViewMode (UserControl) and that in turn loads a MainViewModel (UserControl), if I have an event on the Window called Exit can the ShellViewModel subscribe to that and bubble it to the loaded view or should the loaded view subscribe to the window events)
I know that is a number of questions but they are all related to the same thing and I am hoping that someone can provide an answer.
Let me try to answer each of your questions
How should I correctly create custom events, is the above correct?
I think what you did above is correct or you can add an event handler like the usual.
If you're talking about custom events where you will create your own event aside from the built in events of a class, you can actually do that just create a delegate and an event within your class.
How do i then bind to said "event" in the view model
I don't think you want to bind events, what you want to do is to bind commands. You can try to read about ICommand, Relaycommand,
DelegateCommand. You can create an ICommand property in your
viewmodel then bind it to the Command property of the button. There
are also some tools that allows you to bind to events, try to look
for some libraries that offers EventToCommand
Can the same method of event be used to bubble the events from one view model to another (for example I have the ShellViewModel which initially loads a LoginViewMode (UserControl) and that in turn loads a MainViewModel (UserControl), if I have an event on the Window called Exit can the ShellViewModel subscribe to that and bubble it to the loaded view or should the loaded view subscribe to the window events)
In this scenario, where two viewmodel is involved, since you're using caliburn.micro, you might want to check on the
EventAggregator. This will allow you to publish an event from
one viewmodel and subscribe on another viewmodel. Then once the
publish is invoked, all the subscriber will be notified.
Question:
How can I create a function that attaches multiple event handlers to multiple controls?
Intent:
I am using C# to develop a windows forms application. I want to create a function that takes a collection of controls and a collection of event handlers. This function will attach the event handlers to the controls. What would be the most elegant, and reusable way to do this. I have a pretty ugly way to do this with delegates, but it is a but it is less work for me to just throw this into a loop, and abandoning the function.
Behavior I basically want:
foreach(Control control in controlCollection)
foreach(EventHandler handler in eventHandlerCollection)
control.Event += handler;
Function:
attachHandlers(? controlCollection, ? eventHandlers)
Edit:
I am just going to subscribe all the handlers to the same event on all the controls. I didn't explicitly say that in my description, so I believe that is the reason for all of confusion.
If the controls in question inherit from the same base class or interface (or they are the same class), you can do something like:
void AttachClickEventHandlers(List<IClickableControl> controls, List<MyClickHandler> eventHandlers)
{
foreach (var control in controls)
foreach (MyClickHandler handler in eventHandlers)
control.Click += handler;
}
This assumes an interface like:
public interface IClickableControl
{
event MyClickHandler Click;
}
I'm writing a control which inherits from a DataGridView. One of the things I would like to do is to handle the bug whereby a column's format provider is not used without handling the CellFormatting event (and doing the formatting myself).
I thought I would write an "OnCellFormatting" method which says "if there's a column format provider, and there's no CellFormatting event handler(s), do the formatting".
The important bit (I thought) was "...and there's no CellFormatting event handler".
Now, in the past when I've written controls with events, I've done something like this:
public event EventHandler SomethingHappened;
protected void OnSomethingHappened(EventArgs e)
{
EventHandler handler = this.SomethingHappened;
if (handler != null) handler(this, e);
}
This works fine and my understanding is that this pattern determines if handlers are attached to the event and, if so, invoke those handlers. Fair enough, but why can't I do this:
protected void OnCellFormatting(EventArgs e)
{
EventHandler handler = this.CellFormatting;
if (handler == null) DoSomething();
}
The error is "The event 'System.Windows.Forms.DataGridView.CellFormatting' can only appear on the left hand side of += or -="
What's different about this (type of) event ?
If I go to the definition of the event, and create my own, ie.
public event DataGridViewCellFormattingEventHandler CellFormatting2
...the compiler is quite happy to assign this to my "handler" variable, so my question is - what's different with the CellFormatting event (and, one presumes, many others) that I cannot determine if there are any event handlers for it ?
Thanks,
Ross
Only the class that declares the event has full access to it.
For instance, you cannot invoke an event from other classes - even derived ones.
You are in this situation, because you are deriving from DataGridView.
You may be able to use reflection:
How do I raise an event via reflection in .NET (c#)?
MSDN: Type.GetEvent Method
That shows the assignment can't be performed because it's read only. May be you can try declaring the handler private?