Event bubbling inside UserControl in C# - c#

I've created a custom UserControl, it's a button with a grid inside it.
From the Page that contains it, MainPage.xaml, I need to bind a Click event to the UserControl, and the function for the EventHandler must be written outside, in the MainPage (not inside the UserControl).
So, reading through this question, I've created an Event and a EventHandler function that triggers the event. These are inside the UserControl.
This are the classes
UserControl.xaml.cs
public class MyButton : UserControl
{
public event RoutedEventHandler ButtonClicked;
private void ButtonClickedHandler()
{
//Null check makes sure the main page is attached to the event
if (this.ButtonClicked != null)
this.ButtonClicked(this, new RoutedEventArgs());
Debug.WriteLine("ButtonClickedHandler");
}
}
MainPage.xaml.cs
private void MyButton_Click(object sender, RoutedEventArgs e)
{
Debug.WriteLine("MyButton_Click");
}
private void MyButton_Loaded(object sender, RoutedEventArgs e)
{
(sender as MyButton).ButtonClicked += MyButton_Click;
}
As you can see, I've placed a couple of Debug.WriteLine, but they don't get triggered, and I don't know what I'm doing wrong.

Just having a single method in your code that is never called by anything will not make your program work. You will first have to call the ButtonClickedHandler() method each time your button is clicked.
To do that, just register a method for the click-event of your button in your xaml file.
<Button Content="This Is Your Button" Click="YourButtonClick"/>
And then call the ButtonClickedHandler() method in there:
private void YourButtonClick(object sender, RoutedEventArgs e) {
ButtonClickedHandler();
}
A simpler way to solve the problem is using an event property:
UserControl.xaml.cs
public Event RoutedEventHandler ButtonClicked
{
add {
ButtonName.Click += value; //use the name of your button here
}
remove {
ButtonName.Click -= value;
}
}
And then you can simply register to that event in your MainWindow:
private void MyButton_Loaded(object sender, RoutedEventArgs e)
{
(sender as MyButton).ButtonClicked += MyButton_Click;
}
By the way, I think it is better to register the event in the xaml file where you also create the control:

Related

Hide Panel on parent form using a button on UserControl [duplicate]

I have a custom usercontrol and I want to do something relatively simple.
When ever a numeric up down in that usercontrol's value changes, have the main form update a display window.
This is not a problem if the NUD was not in a usercontrol but I can't seem to figure out how to have the event handled by the mainform and not the usercontrol.
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.
Try mapping it. Try placing this code in your UserControl:
public event EventHandler ValueChanged {
add { numericUpDown1.ValueChanged += value; }
remove { numericUpDown1.ValueChanged -= value; }
}
then your UserControl will have the ValueChanged event you normally see with the NumericUpDown control.
you can do like this.....the below example shows text box(user control) value changed
// Declare a delegate
public delegate void ValueChangedEventHandler(object sender, ValueChangedEventArgs e);
public partial class SampleUserControl : TextBox
{
public SampleUserControl()
{
InitializeComponent();
}
// Declare an event
public event ValueChangedEventHandler ValueChanged;
protected virtual void OnValueChanged(ValueChangedEventArgs e)
{
if (ValueChanged != null)
ValueChanged(this,e);
}
private void SampleUserControl_TextChanged(object sender, EventArgs e)
{
TextBox tb = (TextBox)sender;
int value;
if (!int.TryParse(tb.Text, out value))
value = 0;
// Raise the event
OnValueChanged( new ValueChangedEventArgs(value));
}
}
one of the easy way to do that is use landa function without any problem like
userControl_Material1.simpleButton4.Click += (s, ee) =>
{
Save_mat(mat_global);
};
For those looking to do this in VB, here's how I got mine to work with a checkbox.
Background: I was trying to make my own checkbox that is a slider/switch control. I've only included the relevant code for this question.
In User control MyCheckbox.ascx
<asp:CheckBox ID="checkbox" runat="server" AutoPostBack="true" />
In User control MyCheckbox.ascx.vb
Create an EventHandler (OnCheckChanged). When an event fires on the control (ID="checkbox") inside your usercontrol (MyCheckBox.ascx), then fire your EventHandler (OnCheckChanged).
Public Event OnCheckChanged As EventHandler
Private Sub checkbox_CheckedChanged(sender As Object, e As EventArgs) Handles checkbox.CheckedChanged
RaiseEvent OnCheckChanged(Me, e)
End Sub
In Page MyPage.aspx
<uc:MyCheckbox runat="server" ID="myCheck" OnCheckChanged="myCheck_CheckChanged" />
Note: myCheck_CheckChanged didn't fire until I added the Handles clause below
In Page MyPage.aspx.vb
Protected Sub myCheck_CheckChanged (sender As Object, e As EventArgs) Handles scTransparentVoting.OnCheckChanged
'Do some page logic here
End Sub

UWP: PointerPressed is not fired on a child element

I have an UWP App where a RelativePanel "parent" contains another RelativePanel "child".
Both of them should be able to handle the PointerPressed event, in different ways.
When I click on the parent, the PointerPressed event handler of the parent is correctly fired, but when I click on the child, again only the PointerPressed event handler of the parent is fired, so that the PointerPressed event handler of the child is never invoked.
How can I configure the child so that its PointerPressed event handler is invoked?
Here's an excerpt of the code to create these elements (everything is done in the code behind, since those elements should be created at runtime):
public class ChildView
{
public RelativePanel View { get; set; }
public ChildView()
{
View.Width = 18;
View.Height = 18;
View.SetValue(Canvas.ZIndexProperty, 30); // we want the child always on top of the parent
View.Background = new SolidColorBrush(Colors.Transparent);
// Add the gesture recognizers:
View.Holding += HandleLongPressGesture;
View.PointerPressed += HandleTapGesture;
View.PointerReleased += HandlePointerReleased;
View.DoubleTapped += HandleDoubleTapGesture;
}
public void HandleLongPressGesture(object sender, HoldingRoutedEventArgs e)
{
// my logic
}
private void HandlePointerReleased(object sender, PointerRoutedEventArgs e)
{
// my logic
}
private void HandleDoubleTapGesture(object sender, DoubleTappedRoutedEventArgs e)
{
// my logic
}
private void HandleTapGesture(object sender, PointerRoutedEventArgs e)
{
// my logic
}
}
public class ParentView
{
private ChildView child;
public RelativePanel View { get; set; }
public ParentView()
{
child = new ChildView();
View.Children.Add(child.View);
View.PointerPressed += HandleTapGesture;
View.PointerReleased += HandlePointerReleased;
}
private void HandlePointerReleased(object sender, PointerRoutedEventArgs e)
{
// my logic
}
private void HandleDoubleTapGesture(object sender, DoubleTappedRoutedEventArgs e)
{
// my logic
}
}
set the background of your child panel to transparent.
when the event fires, make sure you do the .Handled=true;
on the incoming handler args to prevent propagation to the parent control.
I'm aware this isn't exactly an answer to your question, but maybe it will help you to debug in some way.
Okay so I set up a simple project (before you added your code to the question) and was unable to replicate your issue.
Basically, the Child click event was getting fired correctly, then the Parent click event was getting fired immediately after, which seems correct to me in this instance.
XAML
<Grid>
<RelativePanel Name="Parent" HorizontalAlignment="Left" Height="460" Margin="437,162,0,0" VerticalAlignment="Top" Width="458" Background="#FFFF5C5C" PointerPressed="Parent_PointerPressed">
<RelativePanel Name="Child" HorizontalAlignment="Left" Height="360" Margin="62,50,0,0" VerticalAlignment="Top" Width="334" Background="#FF3B9C9C" PointerPressed="Child_PointerPressed"/>
</RelativePanel>
</Grid>
C#
private void Parent_PointerPressed(object sender, PointerRoutedEventArgs e)
{
// Breaks here when Parent is pressed
// Also breaks here after breaking on Child_PointerPressed
}
private void Child_PointerPressed(object sender, PointerRoutedEventArgs e)
{
// Breaks here when Child is pressed
}

Click event is not firing when I click a control in dynamic usercontrol

I have different controls in my usercontrols. And load usercontrols dynamically in my form
UserControl2 usercontrol = new UserControl2();
usercontrol.Tag = i;
usercontrol.Click += usercontrol_Click;
flowLayoutPanel1.Controls.Add(usercontrol);
private void usercontrol_Click(object sender, EventArgs e)
{
// handle event
}
The click event is not firing when I click a control in usercontrol. It only fires when I click on empty area of usercontrol.
Recurse through all the controls and wire up the Click() event of each to the same handler. From there call InvokeOnClick(). Now clicking on anything will fire the Click() event of the main UserControl:
public partial class UserControl2 : UserControl
{
public UserControl2()
{
InitializeComponent();
WireAllControls(this);
}
private void WireAllControls(Control cont)
{
foreach (Control ctl in cont.Controls)
{
ctl.Click += ctl_Click;
if (ctl.HasChildren)
{
WireAllControls(ctl);
}
}
}
private void ctl_Click(object sender, EventArgs e)
{
this.InvokeOnClick(this, EventArgs.Empty);
}
}
This should solve your problem.
//Event Handler for dynamic controls
usercontrol.Click += new EventHandler(usercontrol_Click);
Take this:
this.btnApply.Click += new System.EventHandler(this.btnApply_Click);
Because events from ChildControls are not propagated to parents. So you have to handle Click event on every child control added to UserControl.
1-define a delegate at nameapace
public delegate void NavigationClick(int Code, string Title);
2-define a event from your delegate in UserControl class:
public event NavigationClick navigationClick;
3-write this code for your control event in UserControl:
private void btn_first_Click(object sender, EventArgs e)
{
navigationClick(101, "First");
}
4-in your Windows Form than use from your UserControl at Event add:
private void dataBaseNavigation1_navigationClick(int Code, string Title)
{
MessageBox.Show(Code + " " + Title);
}

how to set a custom control button's job after adding it to some form?

Im making a userControl named [File_Manager] and i was wondering if i can add a button to this custom control that i can set its job later after adding this custom control to another form .. something like
File_Manager fManager = new File_Manager();
fManager.SetFreeButtonJob( MessageBox.Show("Hello") ); // something like this.
then whenever user press that button .. the messageBox shows up.
So.. Is it possible to do that?
thanks in advance.
Sure you can. Just attach the buttons click handler to the action you pass in.
fManager.SetFreeButtonJob(() => MessageBox.Show("Hello"));
private void SetFreeButtonJob(Action action)
{
button1.Click += (s,e) => action();
}
Just note that passing in the Action breaks the encapsulation of user control though. You should probably do something like SetFreeButtonJob(Jobs.SayHello); and put the knowledge of what to do inside the control.
Create a custom event for your UserControl and fire it when your Button is clicked. You can then attach an event handler to the custom event in your Form. Or you can just raise the UserControl's Click Event when your Button is clicked.
public delegate void CustomClickEventHandler(object sender, EventArgs e);
public partial class buttonTest : UserControl
{
public event CustomClickEventHandler CustomClick;
public buttonTest()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
CustomClick(sender, e);
}
}
and in your Form
public Form1()
{
InitializeComponent();
buttonTest1.CustomClick +=new CustomClickEventHandler(userControl1_ButtonClick);
}
private void userControl1_ButtonClick(object sender, EventArgs e)
{
MessageBox.Show("Hello");
}
Or as my second option try.
private void button2_Click(object sender, EventArgs e)
{
OnClick(e);
}
and in your Form subscribe to the UserControl's Click event.
buttonTest1.Click +=new EventHandler(buttonTest1_Click);
private void buttonTest1_Click(object sender, EventArgs e)
{
MessageBox.Show("Hello Again");
}

Get event from dynamically added button in UserControl

I want to get the clicked event of a Button which is in my UserControl and I am adding that UserControl dynamically in my form. I want the event to be raised in the Form in which i am adding the UserControl. Please if anyone could suggest me proper way then it will be really very helpful.
You need to expose the event in your user control, then subscribe it when you add the user control to the form. e.g.:
public partial MyUserControl:Control
{
public event EventHandler ButtonClicked;
private void myButtonClick(object sender, EventArgs e)
{
if (this.ButtonClicked != null)
this.ButtonClicked(this, EventArgs.Empty);
}
}
public partial MyForm:Form
{
private void MethodWhereYouAddTheUserControl()
{
var myUC = new MyUserControl();
myUC += myUC_ButtonClicked;
// code where you add myUC to the form...
}
void myUC_ButtonClicked(object sender, EventArgs e)
{
// called when the button is clicked
}
}
I guess you're using Winforms referring to your title.
What you can do it to forward your Click event.
So in the ctor of your UserControl
public class MyUserControl
{
public event EventHandler MyClick;
private void OnMyClick()
{
if (this.MyClick != null)
this.MyClick(this, EventArgs.Empty);
}
public MyUserControl()
{
this.Click += (sender, e) => this.OnMyClick();
}
}
Add your own event to your custom user control.
Inside your customer user control, once you add the button, also attach your (internal) event handler that will then raise your own public event with some way to tell the event handler which button has been clicked (you'll most likely need your own delegate here).
Once that's done, your form can add its own event handler just like you add one to the standard controls.
Rereading your question, this might not be the exact structure (the button is fixed, but the user control is dynamically added?). In any way, it should be almost the same, it just differs where/when you add the event handler upon creation.
With one static button it's a lot easier to be done - assuming you're using Windows Forms:
In your custom user control:
public event EventHandler ButtonClicked; // this could be named differently obviously
...
public void Button_OnClick(object sender, EventArgs e) // this is the standard "on button click" event handler created using the form editor
{
if (ButtonClicked != null)
ButtonClicked(this, EventArgs.Empty);
}
In your form:
// create a new user control and add the event
MyControl ctl = new MyControl();
Controls.Add(ctl);
ctl.ButtonClicked += new EventHandler(Form_OnUserControlButtonClicked); // name of the event handler in your form that's called once you click the button
...
private void Form_OnUserControlbuttonClicked(object sender EventArgs e)
{
// do whatever should happen once you click the button
}
when you are adding your usercontrol to your form, register the click event (if it is public) usercontrol.button.Click += new EventHandler(usercontrolButton_Click);
register the button's Click event within your usercontrol

Categories