Label of UserControl is hiding MouseEnter event - c#

I can't active the event mouse enter because label's on top. I try assign the same event, but when I call MyUserControl myUserControl = (MyUserControl)sender; results in error. Here's my code:
foreach (Control ctrl in MyUserControl.Controls)
{
ctrl.MouseEnter += MyUserControl_MouseEnter;
}
private void MyUserControl_MouseEnter(object sender, EventArgs e)
{
MyUserControl myUC = (MyUserControl)sender;
int test = myUC .Codigo;
}
the event (Form_MouseEnter) works when it occurs in the form, but in the components it returns an error like 'System.InvalidCastException'
public partial class MyUserControl : UserControl
{
int g_intCodEquip;
public int Codigo
{
set { g_intCodEquip = value; }
get { return g_intCodEquip; }
}
}

To ensure that any and all child controls of MyUserControl will be correctly handled, we can iterate the control tree of MyUserControl and subscribe to the MouseEnter event.
We route all of these events to a centralized Any_MouseEnter handler which in turn fires a new custom event that the Form1 subscribes to:
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
IterateControlTree();
}
void IterateControlTree(Control control = null)
{
if (control == null)
{
control = this;
}
control.MouseEnter += Any_MouseEnter;
foreach (Control child in control.Controls)
{
IterateControlTree(child);
}
}
private void Any_MouseEnter(object sender, EventArgs e)
{
// Before calling Invoke we need to make sure that
// MyUserControlMouseEnter is not null as would be
// the case if there are no subscribers to the event.
// The '?' syntax performs this important check.
MyUserControlMouseEnter?.Invoke(this, EventArgs.Empty);
}
// A custom event that this custom control can fire.
public event EventHandler MyUserControlMouseEnter;
public int Codigo
{
set
{
test = value;
}
get
{
return test;
}
}
int test = 0;
}
Note: This is a follow-up question to your previous post so I copied over the 'Codigo' property.
OK, so now in the main Form1, we subscribe to the new event fired by MyUserControl. Now the sender is type MyUserControl, the cast succeeds, and the notification works no matter which control the mouse enters.
private void MyUserControl_MouseEnter(object sender, EventArgs e)
{
MyUserControl myUserControl = (MyUserControl)sender;
Debug.WriteLine(
"MouseEnter Detected: " + myUserControl.Name +
" - Value of Codigo is: " + myUserControl.Codigo);
}
As a test runner, we can set up a 4 x 3 array of MyUserControl (the working example MyUserControl contains both a Label and a Button).
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
TableLayoutPanel tableLayoutPanel1 = new TableLayoutPanel() { ColumnCount = 4, RowCount = 4, Dock = DockStyle.Fill };
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
Controls.Add(tableLayoutPanel1);
int row, column;
for (int count = 0; count < 12; count++)
{
row = count / 4; column = count % 4;
MyUserControl myUserControl = new MyUserControl();
myUserControl.Name = "MyUserControl_" + count.ToString("D2"); // Name it! (Default is "")
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// Subscribe to custom event fired by MyUserControl
myUserControl.MyUserControlMouseEnter += MyUserControl_MouseEnter;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
myUserControl.Codigo = 1000 + count; // Example to set Codigo
tableLayoutPanel1.Controls.Add(myUserControl, column, row);
}
}
}
The behavior follows this 10-second clip.

Change your code to a safe cast.
private void Form_MouseEnter(object sender, EventArgs e)
{
if (sender is MyUserControl myUC)
{
int test = myUC.Codigo;
}
}
Here you can find the documentation: https://learn.microsoft.com/en-us/dotnet/csharp/how-to/safely-cast-using-pattern-matching-is-and-as-operators
Side note:
You have showed us the registration of the event handler MyUserControl_MouseEnter but provided the code for Form_MouseEnter.

The error occurs here at this line:
MyUserControl myUC = (MyUserControl)sender;
...since you wired up the Labels to also run that code, but in those cases the sender variable will be a Label which cannot be cast to MyUserControl.
You could simply grab the .Parent property which should be the usercontrol since you only went one level deep when you originally wired them up. Just check to see if sender is not the MyUserControl type first:
MyUserControl myUC;
if (sender is MyUserControl)
{
myUC = (MyUserControl)sender;
}
else
{
myUC = (MyUserControl)((Control)sender.Parent);
}

Related

C# How to have a form subscribe to an event which is within a user control within a floy layour panel?

So I have a form on a WinForms app.
On that form is a FlowLayoutPanel.
On the FlowLayout panel is a bunch of user controls each representing rows from a table from a database.
On each control is a button.
How do I have the form subscribe to a button click on one of the controls passing back that rows database info?
This is the control code:
public partial class ctrlLeague : UserControl
{
public League activeLeague = new League();
public event EventHandler<MyEventArgs> ViewLeagueClicked;
public ctrlLeague(League lg)
{
InitializeComponent();
lblLeagueName.Text = lg.leagueName;
activeLeague = lg;
}
private void btnViewLeague_Click(object sender, EventArgs e)
{
ViewLeagueClicked(this, new MyEventArgs(activeLeague));
}
public class MyEventArgs : EventArgs
{
public MyEventArgs(League activeLeague)
{
ActiveLeague = activeLeague;
}
public League ActiveLeague { get; }
}
}
if I put the following into the form constructor it tells me "
You can define your favorite event with delegate and call it wherever you want, here it is called inside btnView_Click.
This means that whenever btnView_Click called, your event is
actually called.
public partial class ctrlLeague : UserControl
{
public League activeLeague = new League();
public event EventViewLeagueClicked ViewLeagueClicked;
public delegate void EventViewLeagueClicked(object Sender);
public ctrlLeague(League lg)
{
InitializeComponent();
lblLeagueName.Text = lg.leagueName;
activeLeague = lg;
}
private void btnViewLeague_Click(object sender, EventArgs e)
{
if (ViewLeagueClicked != null)
ViewLeagueClicked(activeLeague);
}
}
now use
public Form1()
{
InitializeComponent();
League league = new League();
league.leagueName = "Seri A";
//
//These lines are best added in Form1.Designer.cs
//
ctrlLeague control = new ctrlLeague(league);
control.Location = new System.Drawing.Point(350, 50);
control.Name = "ctrlLeague";
control.Size = new System.Drawing.Size(150, 100);
control.ViewLeagueClicked += Control_ViewLeagueClicked;
this.Controls.Add(control);
}
private void Control_ViewLeagueClicked(object Sender)
{
League l = Sender as League;
MessageBox.Show(l.leagueName);
}

How can I get the index/event of a class when I have multiple instances of that class?

I have a class that creates a Label and display text.
I also have a Click event that when it fires, the Label text changes.
I have another class, that passes a method to the first one that shows a MessageBox.
In the main Form I'm running a for loop that creates 2 instances of the class at random locations.
The problem is, when I click a Label, the text doesn't change on the Label that I want. It changes to the first Label (class) created.
How can I change that?
class J1
{
public Label texto;
public static int a = 0;
//Calls the Method that Creates the Label
public void Spawn(Form form, int _X, int _Y)
{
LL(form, _X, _Y);
}
//Creates the label
public void LL(Form form, int _X, int _Y)
{
texto = new Label()
{
Size = new System.Drawing.Size(35, 50),
Left = _X,
Top = _Y,
Text = "nova label"
};
texto.Click += new EventHandler(Label_Clicada);
form.Controls.Add(texto);
}
void Label_Clicada(object sender, EventArgs e) //Click event when fires
{
J2.M(); //2nd Class that shows a MessageBox
//Changes Text, but doenst change the one that was clicked on
texto.Text = texto.GetType().ToString();
}
}
2nd Class(J2):
class J2
{
public static void M()//Method that I pass to 1nd class(J1)
{
J1.a++;
MessageBox.Show(J1.a.ToString());
}
}
As i posted in comment solution for this was using (sender as Label).Text in click event.
sender is type of object which contains object which fired event.
If we take a look at how events are fired with this code:
EventHandler<ThresholdReachedEventArgs> handler = ThresholdReached;
if (handler != null)
{
handler(this, e);
}
We can see that hanlder(this, e); is passing this object which fires it and e as some parameters (event args).
Now this / object that passed event could be any object if you bind multiple objects to same event.
For example if you do yourButton.Click += ClickEvent; and yourLabel.Click += ClickEvent both buttons inside have code above but both of them will pass different this (themselves) and e (events if there are any)
so inside our event we can do this:
private void ClickEvent(object sender, EventArgs e)
{
if(sender is Label)
{
Label l = sender as Label;
//Do anything with label
}
else if(sender is Button)
{
Button b = sender as Button;
//Do anything with button
}
else
{
MessageBox.Show("Unknown component");
//Or
throw new Exception("Unknown component");
}
}

How to handle Click event on a Control when a child control has been clicked?

I have a UserControl that has someother controls:
I need to enable click on any item I click of the user control so I can set the UserControl borderstyle.
This works if I don't have any control added, but If I have for example a panel and I try to click on the panel my UserControl's click event doesn't get fired.
This is my code:
public partial class TestControl : UserControl
{
public TestControl()
{
InitializeComponent();
this.Click += Item_Click;
IsSelected = false;
}
public bool IsSelected { get; set; }
void Item_Click(object sender, EventArgs e)
{
if (!IsSelected)
{
IsSelected = true;
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
}
else
{
IsSelected = false;
this.BorderStyle = System.Windows.Forms.BorderStyle.None;
}
}
}
Any clue on how to fire my UserControl click's event even if I click over other elements?
Actually it's really simple to achieve this, you can iterate through all the controls contained in your UserControl and register the Item_Click to their EventHandler which will invoke it when the Click event is fired:
public partial class TestControl : UserControl {
public TestControl( ) {
//...
for ( int i = 0; i < Controls.Count; i++ ) {
Controls[ i ].Click += Item_Click;
}
}
//...
}

How to get Usercontrol object 'X' from X's Button(i.e. Button inside the X) onclick event

Hello guys i am working on a Windows Form application in .Net C#.
Now i have a User control with a button inside it.
however i had to write the on-click handler in the main form rather than inside the user-control itself.
Now i want to know if there is anyway i can get the User-control object in the Button's on-click Handler. Since i had to make use of them few more times in the same form. I want to know which User-control's Button was click.
User Control
Button
Thank You :)
Here's an example of the UserControl raising a Custom Event that passes out the source UserControl that the Button was clicked on:
SomeUserControl:
public partial class SomeUserControl : UserControl
{
public event ButtonPressedDelegate ButtonPressed;
public delegate void ButtonPressedDelegate(SomeUserControl sender);
public SomeUserControl()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (ButtonPressed != null)
{
ButtonPressed(this); // pass the UserControl out as the parameter
}
}
}
Form1:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
someUserControl1.ButtonPressed += new SomeUserControl.ButtonPressedDelegate(SomeUserControl_ButtonPressed);
someUserControl2.ButtonPressed += new SomeUserControl.ButtonPressedDelegate(SomeUserControl_ButtonPressed);
someUserControl3.ButtonPressed += new SomeUserControl.ButtonPressedDelegate(SomeUserControl_ButtonPressed);
}
void SomeUserControl_ButtonPressed(SomeUserControl sender)
{
// do something with "sender":
sender.BackColor = Color.Red;
}
}
You can use event:
public delegate void ButtonClicked();
public ButtonClicked OnButtonClicked;
You can then subscribe the event anywhere, for instance, in your MainForm, you have a user control called demo;
demo.OnButtonClicked +=()
{
// put your actions here.
}
Just walk the .Parent() chain until you find a Control that is the same Type as your UserControl. In the example below, the UserControl is of Type SomeUserControl:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
someUserControl1.button1.Click += new EventHandler(button1_Click);
someUserControl2.button1.Click += new EventHandler(button1_Click);
someUserControl3.button1.Click += new EventHandler(button1_Click);
}
void button1_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
Control uc = btn.Parent;
while (uc != null && !(uc is SomeUserControl))
{
uc = uc.Parent;
}
uc.BackColor = Color.Red;
MessageBox.Show(uc.Name);
}
}

Get selected List Box item in user control from Window

I have a User control with a list box.
This User control located on my window.
how can I detect and get selected item from list box in user control?
I previously tried this but when i select an item from list box e.OriginalSource return TextBlock type.
private void searchdialog_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
//This return TextBlock type
var conrol= e.OriginalSource;
//I Want something like this
if (e.OriginalSource is ListBoxItem)
{
ListBoxItem Selected = e.OriginalSource as ListBoxItem;
//Do somting
}
}
Or there is any better way that I detect list box SelectionChanged in From My form?
I think the best soution would be to declare an event on your user control, that is fired whenever the SelectedValueChanged event is fired on the listbox.
public class MyUserControl : UserControl
{
public event EventHandler MyListBoxSelectedValueChanged;
public object MyListBoxSelectedValue
{
get { return MyListBox.SelectedValue; }
}
public MyUserControl()
{
MyListBox.SelectedValueChanged += MyListBox_SelectedValueChanged;
}
private void MyListBox_SelectedValueChanged(object sender, EventArgs eventArgs)
{
EventHandler handler = MyListBoxSelectedValueChanged;
if(handler != null)
handler(sender, eventArgs);
}
}
In your window, you listen to the event and use the exposed property in the user control.
public class MyForm : Form
{
public MyForm()
{
MyUserControl.MyListBoxSelectedValueChanged += MyUserControl_MyListBoxSelectedValueChanged;
}
private void MyUserControl_MyListBoxSelectedValueChanged(object sender, EventArgs eventArgs)
{
object selected = MyUserControl.MyListBoxSelectedValue;
}
}
there are a few ways to handle this:
Implement the SelectionChanged event in your usercontrol, and raise a custom event that you handle in your window:
//in your usercontrol
private void OnListBoxSelectionChanged(object s, EventArgs e){
if (e.AddedItems != null && e.AddedItems.Any() && NewItemSelectedEvent != null){
NewItemsSelectedEvent(this, new CustomEventArgs(e.AddedItems[0]))
}
}
//in your window
myUserControl.NewItemsSelected += (s,e) => HandleOnNewItemSelected();
If you use binding or any form of MVVM, you can use a DependencyProperty to bind the selected item to an object in your viewmodel
//in your usercontrol:
public static readonly DependencyProperty CurrentItemProperty =
DependencyProperty.Register("CurrentItem", typeof(MyListBoxItemObject),
typeof(MyUserControl), new PropertyMetadata(default(MyListBoxItemObject)));
public LiveTextBox CurrentItem
{
get { return (MyListBoxItemObject)GetValue(CurrentItemProperty ); }
set { SetValue(CurrentItemProperty , value); }
}
//in your window xaml
<MyUserControl CurrentItem={Binding MyCurrentItem} ... />

Categories

Resources