How to Make an Event in the Usercontrol and Have It Handled in the Main Form

How do I make an Event in the Usercontrol and have it handled in the Main Form?

You need to create an event handler for the user control that is raised when an event from within the user control is fired. This will allow you to bubble the event up the chain so you can handle the event from the form.

When clicking Button1 on the UserControl, i'll fire Button1_Click which triggers UserControl_ButtonClick on the form:

User control:

[Browsable(true)] [Category("Action")] 
[Description("Invoked when user clicks button")]
public event EventHandler ButtonClick;

protected void Button1_Click(object sender, EventArgs e)
{
//bubble the event up to the parent
if (this.ButtonClick!= null)
this.ButtonClick(this, e);
}

Form:

UserControl1.ButtonClick += new EventHandler(UserControl_ButtonClick);

protected void UserControl_ButtonClick(object sender, EventArgs e)
{
//handle the event
}

Notes:

  • Newer Visual Studio versions suggest that instead of if (this.ButtonClick!= null) this.ButtonClick(this, e); you can use ButtonClick?.Invoke(this, e);, which does essentially the same, but is shorter.

  • The Browsable attribute makes the event visible in Visual Studio's designer (events view), Category shows it in the "Action" category, and Description provides a description for it. You can omit these attributes completely, but making it available to the designer it is much more comfortable, since VS handles it for you.

Handling event from main form in UserControl

The way this runs is that MainForm is created first and then creates an instance of your UserControl inside the MainForm. So, MainForm knows about UserControl but UserControl does not know about MainForm. So when you tell UserControl to use MainForm it doesn't know what MainForm is (no instance). Instead you'll want the MainForm to trigger a method inside the UserControl and pass it the needed information.

In your user control create a method that the MainForm can call:

public class UserControl1
{
public void doSomethingWhenSelectedIndexChanges(int selectedIndex){
// do stuff inside user control...
}
}

Then in your MainForm call the UserControl method.

public class MainForm 
{
private void ListBox1_SelectedIndexChanged(object sender, eventargs e)
{
UserControl1.doSomethingWhenSelectedIndexChanges(ListBox1.SelectedIndex);
}
}

This way the MainForm is telling the UserControl that the ListBox selected index has changed and is passing the selected index to the UserControl.

How do I raise an event in a usercontrol and catch it in mainpage?

Check out Event Bubbling -- http://msdn.microsoft.com/en-us/library/aa719644%28vs.71%29.aspx

Example:

User Control

public event EventHandler StatusUpdated;

private void FunctionThatRaisesEvent()
{
//Null check makes sure the main page is attached to the event
if (this.StatusUpdated != null)
this.StatusUpdated(this, new EventArgs());
}

Main Page/Form

public void MyApp()
{
//USERCONTROL = your control with the StatusUpdated event
this.USERCONTROL.StatusUpdated += new EventHandler(MyEventHandlerFunction_StatusUpdated);
}

public void MyEventHandlerFunction_StatusUpdated(object sender, EventArgs e)
{
//your code here
}

How to add an event to a UserControl in C#?

First, you need to declare the event within your class (alongside your methods and constructors):

public event EventHandler LabelsTextChanged;

Then you need to create a method to handle the individual labels' TextChanged events.

private void HandleLabelTextChanged(object sender, EventArgs e)
{
// we'll explain this in a minute
this.OnLabelsTextChanged(EventArgs.Empty);
}

Somewhere, probably in your control's constructor, you need to subscribe to the label's TextChanged events.

myLabel1.TextChanged += this.HandleLabelTextChanged;
myLabel2.TextChanged += this.HandleLabelTextChanged;
myLabel3.TextChanged += this.HandleLabelTextChanged;

Now for the HandleLabelsTextChanged method. We could raise LabelsTextChanged directly; however, the .NET framework design guidelines say that is it a best practice to create an OnEventName protected virtual method to raise the event for us. That way, inheriting classes can "handle" the event by overriding the OnEventName method, which turns out to have a little better performance than subscribing to the event. Even if you think you will never override the OnEventName method, it is a good idea to get in the habit of doing it anyway, as it simplifies the event raising process.

Here's our OnLabelsTextChanged:

protected virtual void OnLabelsTextChanged(EventArgs e)
{
EventHandler handler = this.LabelsTextChanged;
if (handler != null)
{
handler(this, e);
}
}

We have to check for null because an event without subscribers is null. If we attempted to raise a null event, we would get a NullReferenceException. Note that we copy the event's EventHandler to a local variable before checking it for null and raising the event. If we had instead done it like this:

if (this.LabelsTextChanged != null)
{
this.LabelsTextChanged(this, e);
}

We would have a race condition between the nullity check and the event raising. If it just so happened that the subscribers to the event unsubscribed themselves just before we raised the event but after we checked for null, an exception would be thrown. You won't normally encounter this issue, but it is best to get in the habit of writing it the safe way.

Edit: Here is how the public event EventHandler LabelsTextChanged; line should be placed:

namespace YourNamespace
{
class MyUserControl : UserControl
{
// it needs to be here:
public event EventHandler LabelsTextChanged;

...
}
}

Here are the framework design guidelines on event design for further reading.

How to have the main form listen out for a button click in a control

Inside your UserControl you need to create a custom event. This is triggered when you perform your action in the user control.
Then the main form subscribes to this and is informed every time this action occurs.

Your user control

//Declare a delegate and Event.  Here called StatusUpdate
public delegate void StatusUpdateHandler(object sender, EventArgs e);
public event StatusUpdateHandler OnUpdateStatus;

//When button is clicked, this is trigged
private void Button1_Click(object sender, EventArgs e)
{
//In here, you now trigger your custom event
UpdateStatus();
}


private void UpdateStatus()
{
//Create arguments. You should also have custom one, or else return EventArgs.Empty();
EventArgs args = new EventArgs();

//Call any listeners
OnUpdateStatus?.Invoke(this, args);

}

Then in your main form subscribe to this event

yourUserControl.OnUpdateStatus += customControl_OnUpdateStatus;
...

private void customControl_OnUpdateStatus(object sender, EventArgs e)
{
///Handle your event here
}

C# changing UI of the main form from an UserControl

There are a few ways you could do it, but I'll list one

The Event-Driven Model

The crux of it is that any particular subview should have an event. Let's say that the event is of the form

event EventHandler<BookModel> RemoveClicked;

Which would mean that the main form would need some form of event handler in the following form:

private void HandleThatEvent(object sender, BookModel model)
{
// do the thing
// handle the event
}

Finally, after initialization, the main form should subscribe to the event. This can be done through the designer (the event will be listed under misc.), or directly through code like so:

public void AddView(YourUserControl someView)
{
InitializeComponent();
someView.RemoveClicked += HandleThatEvent;
}

If you're managing a flow layout it might have some different remove methods.. you might, for example, need to pass it a reference to the control you'd like to remove. So you might have to get clever with matching up against the removed item if you don't want to rerender. It could be just as fast to rerender the whole flow control every time that list changes, though. I would test that first and see if you experience any noticeable lag in your UI if you rerender it from a list.

Handle event of a User Control's control in a form

Create your event on the UserControl:

Public Class UserControl1

Public Event UC_Button1Click()

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
RaiseEvent UC_Button1Click()
End Sub

End Class

And then use the new event:

AddHandler userControl1.UC_Button1Click, AddressOf Button1_Click

Or you can simply define it like this on the UserControl and access to it from outside (not recommended):

Public WithEvents Button1 As System.Windows.Forms.Button

And then:

AddHandler uc.Button1.Click, AddressOf Button1_Click

Expose all event handlers of UserControl

So, if I understand correct, I think there are 2 ways you can proceed:

Approach 1

In the UserControl, set the Modifiers property of each textbox (or the ones you are interested in) to public:

Sample Image

Then in the Form that uses this UserControl you can access all these textboxes and hence their events:

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();

myUserControl1.textBox1.KeyDown += new KeyEventHandler(textBox1_KeyDown);
}
}

Approach 2
(Taken from this post)

You can create new events for your UserControl that simply pass forward the event of an underlying textbox. The underlying textboxes can then remain private to the UserControl.

In the UserControl add this event:

public event KeyEventHandler TextBox1KeyDown
{
add { textBox1.KeyDown += value; }
remove { textBox1.KeyDown -= value; }
}

Or you can create a single event that deals with all textboxes:

public event KeyEventHandler AnyTextBoxKeyDown
{
add
{
textBox1.KeyDown += value;
textBox2.KeyDown += value;
textBox3.KeyDown += value;
...
}
remove
{
textBox1.KeyDown -= value;
textBox2.KeyDown -= value;
textBox3.KeyDown -= value;
...
}
}

Now your UserControl has a event of its own that the code in the Form can use:

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();

myUserControl1.TextBox1KeyDown += new KeyEventHandler(myUserControl1_TextBox1KeyDown);
myUserControl1.AnyTextBoxKeyDown += new KeyEventHandler(myUserControl1_AnyTextBoxKeyDown );
}

private void myUserControl1_TextBox1KeyDown(object sender, KeyEventArgs e)
{
/* We already know that TextBox1 was pressed but if
* we want access to it then we can use the sender
* object: */
TextBox textBox1 = (TextBox)sender;

/* Add code here for handling when a key is pressed
* in TextBox1 (inside the user control). */
}

private void myUserControl1_AnyTextBoxKeyDown(object sender, KeyEventArgs e)
{
/* This event handler may be triggered by different
* textboxes. To get the actual textbox that caused
* this event use the following: */
TextBox textBox = (TextBox)sender;

/* Add code here for handling when a key is pressed
* in the user control. */
}
}

Note that while this approach keeps the textboxes private within the UserControl, they can still be accessed from the event handler by the sender argument.

switch usercontrols in mainform within a usercontrol click event

There are several solutions for interaction between controls. Controls are classes and like any other class they can interact with each other using their public properties and methods or using some mediator.

In this case, your controls don't need to know each other and don't need to interact to each other directly:

  • They can ask another object which knows both controls, to do the job for them.
  • Or they can raise their request notification and the one who subscribed to that notification, will serve it.

To ask another object to do the job for them you have multiple solutions. As an example you can implement a specific interface in the parent form and in the child controls, cast the parent to that specific interface and call a specific method which do the job for you.

For raising the request notification, an easy solution is relying on events. You can create an event in the child control and raise it when you need the parent do something for you. Then in the parent subscribe to that event and do the job.

Example - Using event

I assume you have UserControl1 having Button1 inside and you have handled Click event of Button1. Then you can create Button1Clicked event and raise it when Button1 clicked:

public event EventHandler Button1Clicked;
private void Button1_Click(object sender, EventArgs e)
{
Button1Clicked?.Invoke(this, e);
}

Then in the parent form, subscribe for the event and do whatever you want:

private void userControl11_Button1Clicked(object sender, EventArgs e)
{
//Hide userControl11 and show userControl21
}

Example - Using interface

I assume, you have an interface having a few standard methods:

public interface IDoSomething
{
void DoSomething();
void DoSomethingElse();
}

And you have implemented the interface in your parent form:

public class Form1: Form, IDoSomething
{
// ...

public void DoSomething()
{
//Hide userControl11 and show userControl21
}
public void DoSomethingElse()
{
// ...
}
}

Then in you user control:

private void Button1_Click(object sender, EventArgs e)
{
var f = FindForm() as IDoSomething;
if(f!=null)
f.DoSomething();
}


Related Topics



Leave a reply



Submit