C# click on control - c#

I'm trying to create a custom control which fires an even on click.
My control is just a panel with a couple of labels and a picturebox inside.
The click works perfectly, the only issue is that I have to click the background of the control and if I press on the picturebox, is not working.
I've added the on click event to the control, but I would like to press in every place of it to trigger the event, not just the background of the panel.
I thought about adding a transparent object that covers entirely the control. I actually don't like this idea, however, I've tried with a picturebox, but i cannot see through it. It's not transparent. I can just see the panel background but It covers the labels and the image.
Thanks for the support.

If you just have a couple of objects in your panel, you can hook the Click event of all objects it contains to the same event handler, there is nothing wrong doing this.
public class MyUserControl : UserControl
{
public event Action<MyUserControl> MyControlClick
public string ID {get; set;}
public MyUserControl()
{
InitializeComponents();
// The same event handler code will be used for the three controls
myPictureBox.Click += global_Click;
myLabel1.Click += global_Click;
myLabel2.Click += global_Click;
this.Click += global_Click;
}
void global_Click(object sender, EventArgs e)
{
if (MyControlClick != null)
MyControlClick(this);
}
}
If you have a more important amount of objects, you can rely on this answer to create a truly transparent panel that handles clicks. The drawback is that you will have to detect which object has been clicked by using HitTest based on the mouse location.
On the form side :
aControl.MyControlClick += aControl_MyControlClick;
// ...
// This code is triggered when a MyUserControl is clicked
void aControl_MyControlClick(MyUserControl ctl)
{
MessageBox.Show(ctl.ID);
}

Actually! You cannot raise any event to the element in the Usercontrol unless you have to apply own method to your usercontrol or you can disable the element in the usercontrol but it will change the color of that element but It will raise the click event when you click your control.

Related

Custom UserControl's click event does not fire

So I created a custom UserControl just out of a PictureBox and a RadioButton, something like the following:
public partial class Foo : UserControl
{
//some declared properties for the designer...
}
Now I added this object to a Form and subscribed to it's Click() event.
private void customAddedContr_Click(object sender, EventArgs e) { }
But just clicking on this red marked part fires the Click() event.
So just by clicking on the UserControl itself, so when a click is performed on the PictureBox or RadioButton this Click() event does not get fired. I thought that the Click event for this new UserControl gets fired for each click aiming to this Window Handle.
So do I need to bind the PictureBox's and RadioButton's Click() event to the UserControl's Click() event earlier on or what do I oversee?
Edit:
For understanding purpose, here is a colored picture of the CustomControl.
The top dark grey part is the PictureBox. The blue one is the UserControl itself on which I placed the other controls. The light grey bottom is the RadioButton. So just clicking on the blue part (UserControl) fires the Click() event.
I would recommend exposing the picturebox and radio buttons click events separately.
You raise your own events for the radio and picturebox at the usercontrol level and inside each click even you would raise the controls events. then you handle those click events outside the control and respond accordingly.
public partial class Foo : UserControl
{
public event EventHandler RadioButtonClicked;
public event EventHandler PictureBoxClicked:
}
then in the picturebox or button click event inside the control you raise the individual event at the control level
private void PictureBox1_Click(object sender, EventArgs e)
{
if (PictureBoxClicked != null)
PictureBoxClicked(sender, e);
}

Focus in parent even if click on child element

I have a UserControl (let's call it "PresentationCell") which contains a label, and an PictureBox.
In another control, which is using this PresentationCell, I have added an event
presentationCell.GotFocus += OnFocus;
private void OnFocus(object sender, EventArgs e)
{
if (sender is PresentationCell current)
current.BackColor = Color.Azure;
}
This will not be fired, if I click / focus on the Label or PictureBox that is within the PresentationCell.
How can I make it fire, when just something within the PresentationCell is in focus?
The problem here is, that the Label and PictureBox controls aren't selectable controls, so they aren't able to receive focus from mouse clicks.
What you could to instead, is to handle the mouse click event and check if you have hit the PresentationCell. If the PresentationCell is hit you can programatically set the focus like so:
hitPresentationCell.Focus();
This will then fire the GotFocus event.
In your OnFocus method you will have to switch the focus to another control or the event will fire endlessly.

Windows Forms - detecting button click from a panel inside the form

I have Windows Form named - Form1 and inside Form1 I have a panel named panel1. I use this panel only to add buttons in him. For now there are exactly 9 buttons but I intend to change their number dynamicly if this has something to do with my current problem. What I need is way to detect a when a button from this panel is clicked (I have other buttons too but, they are in Form1 outside the panel) and also to know exactly which button was clicked.
I tried this:
private void panel1_Click(object sender, EventArgs e)
{
MessageBox.Show("HI" + sender);
}
As you can see, it's not much, but was enough to see that I can't do that using pnael1's_click event. Using this code I get the message box when I click anywhere in the panel except the buttons. So how can I do that. Is it possible to do it from inside panel1 or I should group those buttons using another approach but it's important to be able to keep the difference between those buttons which are now in panel1 and the other buttons I may (and in in fact I do have)?
When creating the dynamic buttons, you register that button instance's Click event and attach to an event handler (a single handler can handle all buttons' click event):
var dynamicButton1 = new Button();
dynamicButton1.Click += MyButtonClickHandler;
As long as MyButtonClickHandler has a signature that's suitable for a Click event (that's any method returning void and taking an object and an EventArgs, the handler should respond to a dynamic button's click event for as long as the button instance exists.
As long as you aren't adding controls dynamically over time, and the number of buttons is fixed as soon as the form is initialized, you can use this to add a click event handler to all buttons within a panel:
foreach (var button in panel.Controls.OfType<Button>())
{
button.Click += HandleClick;
}

Enter event not firing in Panel inside a UserControl

I added a Panel inside a UserControl i design time.
Then, I added this control to a form.
I want to show a focus dashed border when the control has the focus.
Unfortunately, the Enter event from the panel never fires. I only get a fire when I click on the user control itself.
To extend this question. How can I forward events from controls inside a user control to the base user control? A comment from Hans Passant in this question says that by default events are forwarded to their direct parent. I didn't change any of the control's properties. What am I doing wrong? Is there an obvious property I need to change on each control i order to force it to forward unhandled events?
I am using DevExpress controls but this behavior is same in windows WinForms controls.
edit: I understand that panel might not be able to get focus. If this is true, how do I forward each mouse event to the parent control?
Based on your comment, from inside your UserControl, handle the panel's MouseDown event and set the focus to the parent control:
public UserControl1() {
InitializeComponent();
panel1.MouseDown += new MouseEventHandler(panel1_MouseDown);
}
void panel1_MouseDown(object sender, MouseEventArgs e) {
if (!this.Focused)
this.Focus();
}
Use panel1.Select() on MouseClick event of the panel and you will be able to trigger panel1.Enter and panel1.Leave

Is there any way to detect a mouseclick outside a user control?

I'm creating a custom dropdown box, and I want to register when the mouse is clicked outside the dropdown box, in order to hide it. Is it possible to detect a click outside a control? or should I make some mechanism on the containing form and check for mouseclick when any dropdownbox is open?
So I finally understand that you only want it to close when the user clicks outside of it. In that case, the Leave event should work just fine... For some reason, I got the impression you wanted it to close whenever they moved the mouse outside of your custom dropdown. The Leave event is raised whenever your control loses the focus, and if the user clicks on something else, it will certainly lose focus as the thing they clicked on gains the focus.
The documentation also says that this event cascades up and down the control chain as necessary:
The Enter and Leave events are hierarchical and will cascade up and down the parent chain until the appropriate control is reached. For example, assume you have a Form with two GroupBox controls, and each GroupBox control has one TextBox control. When the caret is moved from one TextBox to the other, the Leave event is raised for the TextBox and GroupBox, and the Enter event is raised for the other GroupBox and TextBox.
Overriding your UserControl's OnLeave method is the best way to handle this:
protected override void OnLeave(EventArgs e)
{
// Call the base class
base.OnLeave(e);
// When this control loses the focus, close it
this.Hide();
}
And then for testing purposes, I created a form that shows the drop-down UserControl on command:
public partial class Form1 : Form
{
private UserControl1 customDropDown;
public Form1()
{
InitializeComponent();
// Create the user control
customDropDown = new UserControl1();
// Add it to the form's Controls collection
Controls.Add(customDropDown);
customDropDown.Hide();
}
private void button1_Click(object sender, EventArgs e)
{
// Display the user control
customDropDown.Show();
customDropDown.BringToFront(); // display in front of other controls
customDropDown.Select(); // make sure it gets the focus
}
}
Everything works perfectly with the above code, except for one thing: if the user clicks on a blank area of the form, the UserControl doesn't close. Hmm, why not? Well, because the form itself doesn't want the focus. Only controls can get the focus, and we didn't click on a control. And because nothing else stole the focus, the Leave event never got raised, meaning that the UserControl didn't know it was supposed to close itself.
If you need the UserControl to close itself when the user clicks on a blank area in the form, you need some special case handling for that. Since you say that you're only concerned about clicks, you can just handle the Click event for the form, and set the focus to a different control:
protected override void OnClick(EventArgs e)
{
// Call the base class
base.OnClick(e);
// See if our custom drop-down is visible
if (customDropDown.Visible)
{
// Set the focus to a different control on the form,
// which will force the drop-down to close
this.SelectNextControl(customDropDown, true, true, true, true);
}
}
Yes, this last part feels like a hack. The better solution, as others have mentioned, is to use the SetCapture function to instruct Windows to capture the mouse over your UserControl's window. The control's Capture property provides an even simpler way to do the same thing.
Technically, you'll need to p/invoke SetCapture() in order to receive click events that happen outside of your control.
But in your case, handling the Leave event, as #Martin suggests, should be sufficient.
EDIT: While looking for an usage example for SetCapture(), I came across the Control.Capture property, of which I was not aware. Using that property means you won't have to p/invoke anything, which is always a good thing in my book.
So, you'll have to set Capture to true when showing the dropdown, then determine if the mouse pointer lies inside the control in your click event handler and, if it doesn't, set Capture to false and close the dropdown.
UPDATE:
You can also use the Control.Focused property to determine if the control has got or lost focus when using a keyboard or mouse instead of using the Capture with the same example provided in the MSDN Capture page.
Handle the Form's MouseDown event, or override the Form's OnMouseDown
method:
enter code here
And then:
protected override void OnMouseDown(MouseEventArgs e)
{
if (!theListBox.Bounds.Contains(e.Location))
{
theListBox.Visible = false;
}
}
The Contains method old System.Drawing.Rectangle can be used to indicate if
a point is contained inside a rectangle. The Bounds property of a Control is
the outer Rectangle defined by the edges of the Control. The Location
property of the MouseEventArgs is the Point relative to the Control which
received the MouseDown event. The Bounds property of a Control in a Form is
relative to the Form.
You are probably looking for the leave event:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.leave.aspx
Leave occurs when the input focus leaves the control.
I just wanted to share this. It is probably not a good way of doing it that way, but looks like it works for drop down panel that closes on fake "MouseLeave", I tried to hide it on Panel MouseLeave but it does not work because moving from panel to button leaves the panel because the button is not the panel itself. Probably there is better way of doing this but I am sharing this because I used about 7 hours figuring out how to get it to work. Thanks to #FTheGodfather
But it works only if the mouse moves on the form. If there is a panel this will not work.
private void click_to_show_Panel_button_MouseDown(object sender, MouseEventArgs e)
{
item_panel1.Visible = true; //Menu Panel
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (!item_panel1.Bounds.Contains(e.Location))
{
item_panel1.Visible = false; // Menu panel
}
}
I've done this myself, and this is how I did it.
When the drop down is opened, register a click event on the control's parent form:
this.Form.Click += new EventHandler(CloseDropDown);
But this only takes you half the way. You probably want your drop down to close also when the current window gets deactivated. The most reliable way of detecting this has for me been through a timer that checks which window is currently active:
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
and
var timer = new Timer();
timer.Interval = 100;
timer.Tick += (sender, args) =>
{
IntPtr f = GetForegroundWindow();
if (this.Form == null || f != this.Form.Handle)
{
CloseDropDown();
}
};
You should of course only let the timer run when the drop down is visible. Also, there's probably a few other events on the parent form you'd want to register when the drop down is opened:
this.Form.LocationChanged += new EventHandler(CloseDropDown);
this.Form.SizeChanged += new EventHandler(CloseDropDown);
Just don't forget to unregister all these events in the CloseDropDown method :)
EDIT:
I forgot, you should also register the Leave event on you control to see if another control gets activated/clicked:
this.Leave += new EventHandler(CloseDropDown);
I think I've got it now, this should cover all bases. Let me know if I'm missing something.
If you have Form, you can simply use Deactivate event just like this :
protected override void OnDeactivate(EventArgs e)
{
this.Dispose();
}

Categories

Resources