I have created a Windows Forms application, but I get strange behaviour from the Capture property of a control.
On a blank form, with a single label called "label1" and the code
public Form1()
{
InitializeComponent();
label1.MouseDown += pictureBox1_MouseDown;
}
void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
Debug.WriteLine(label1.Capture);
label1.Capture = !label1.Capture;
Debug.WriteLine(label1.Capture);
}
I observed, that the first WriteLine always says "True", the second one always says "False" when the button is clicked. Even when clicked multiple times.
The label never reacts to clicks outside its border, not even when I use label1.Capture = true instead.
Am I misunderstanding the expected behaviour of the "Capture" property? I expected the initial value to be false, and the label not to react to clicks outside, after the first click I expect the value to be true, and the label to react to all mouse clicks, even outside its borders.
In a MouseDown event, the Capture for the control always set to true initially. So normally if you perform a MouseDown and then without releasing mouse button move your mouse out of the control and then release mouse button, the MouseUp event of the control will be fired.
If you set Capture to false in MouseDown, then the mouse up event of your control will only fire if your mouse is over the control and if you move the mouse out of your control and then release mouse button, the MouseUp event of your control will not raise.
Also in MouseUp the capture will be released automatically.
For more information take a look at these resources:
WmMouseDown method source code
WmMouseUp method source code
CaptureInternal proprty source code
SetCapture documentations
ReleaseCapture documentations
Related
In WPF I have a Window_KeyDown event which changes the mouse cursor shape when the user presses shift. It works as expected except if I have clicked on another app. So I added a Window_MouseEnter event like this to grab keyboard focus when the mouse reenters my app:
private void Window_MouseEnter(object sender, MouseEventArgs e)
{
IInputElement b = Keyboard.Focus(this);
this.Focus();
Debug.WriteLine(b + DateTime.Now.ToLongTimeString());
}
I can see the MouseEnter event firing (with the debug line) when the mouse enters the app but my app still doesn't get keyboard events until I click in the app.
It's irritating because the mouse cursor changes properly when the mouse enters controls within my app so one would expect things to work but the shift-mouse functions don't work until after a click.
What am I missing?
I found that the secret is the Activate() method. I put it in the MouseEnter function which has a side-effect of forcing the entire app to show if some of it was hidden by other apps.
With Activate(), the Focus() method is not needed.
I have a ListView control on my form. I have set its display mode to LargeImageList. I need to handle the items inside this control. So I have written code for its click event. But I see now that this event is not triggered when I click in an empty area inside it.
How can I make my ListView aware of the clicks on its area regardless.
To capture mouse clicks on the "white space" around the ListView items, you will need to use the MouseDown/MouseUp events.
This will also capture clicks to the items as well.
I've used the Global Mouse Hook for similar issues. You can use it to detect Mouse Clicks anywhere on the screen, then just check the click was within the listview control bounds.
Grab the code from Global Mouse Key Hook
IKeyboardMouseEvents m_GolbalHook = Hook.GlobalEvents();
m_GolbalHook.MouseClick += m_GolbalHook_MouseClick;
private void m_GolbalHook_MouseClick(object sender, MouseEventArgs e)
{
if (listView.Bounds.Contains(e.Location)) && (e.Button == System.Windows.Forms.MouseButtons.Left))
{
//Do Stuff
}
}
I have a user control that I'm trying to make draggable. The whole control should be draggable except when you click on buttons or text boxes. I'm handling the mousedown, mouseup and mousemove events on the usercontrol itself and I can drag by clicking anywhere. The only issue is now I can't click any buttons on the user control. Any clue what's going on?
Code is something like this:
<UserControl PreviewMouseLeftButtonDown="Popup_PreviewMouseLeftButtonDown" ....STUFF...>
<!-- CAN'T CLICK THIS -->
<Button />
<UserControl>
Code Behind:
public void Popup_PreviewMouseLeftButtonDown(object sender, MouseEventArgs e)
{
mouseDown = true;
oldMousePosition = this.PointToScreen(e.GetPosition(this));
this.Popup.Child.CaptureMouse();
}
The issue arises when you use CaptureMouse() - this permanently captures all your mouse input on the window, and makes it so that you're unable to click on anything within the Window. I don't know if it's different for you, or if you checked, but it's not (just) that the Button is unclickable - it's that literally everything on the Window is unclickable.
You have to actually do something with the mouse after you've captured it, and then once you finish that, you have to return normal control by calling Mouse.Capture(null). For you, this would probably be best to do in your MouseUp() method.
However, this still leaves the child problem. I can't really think of any way you're going to be able to both capture all mouse click events on a parent control and allow them to get to the child control. I suppose you could check the mouse position against the button position, both relative to the UserControl, then route the click event to the Button every time, but this seems a little overelaborate. Is there a reason you can't just add a full-sized Grid to the UserControl with a lower ZIndex than the Button, and just use that to detect if a click was made inside the UserControl but not on the Button?
I am working on a C# piano. I have already built the music keyboard and the staff. Everytime a user presses a key, it is displayed on the staff in its relevant position.
The music note displayed on the staff is stored in an array of pictureboxes, as shown below.
public void addPictureBox(int x, int y, Image image)
{
picBox[cnt] = new PictureBox();
picBox[cnt].Image = image;
picBox[cnt].Location = new Point(x, y);
picBox[cnt].BackColor = Color.Transparent;
panel3.Controls.Add(picBox[cnt]);
picBox[cnt].BringToFront();
picBox[cnt].MouseDown += new MouseEventHandler(Pic_MouseDown);
picBox[cnt].MouseUp += new MouseEventHandler(Pic_MouseUp);
cnt++;
}
The Pic_MouseDown and Pic_MouseUp events allow the user to play the note by clicking on it from the staff.
What I want to do now is to create an event on picBox[cnt] for dragging. However, picBox[cnt].MouseDown and picBox[cnt].MouseUp have already been registered to Pic_MouseDown and Pic_MouseUp event handlers.
How can I do an event to handle dragging since MouseDown and MouseUp have already been registered to other event handlers?
Thanks :)
The great thing about event handlers is that you can have as many attached handlers as you want. The += (operator overload) means you are attaching a new event handler to the existing handlers. You can add as many event handlers as you desire.
Event Handler Overview
If you create a isDragging boolean instance field, which you set to true in the mouse down and false in mouse up, then you can use the mouse move event to detect whether the object should be moved or not.
You'll need to use a combination of MouseDown, MouseMove and MouseUp events. In MouseDown, you do little more than set a flag to indicate that the mouse was pressed, and record where it was pressed. In MouseMove, you check to see if the button is still down and the cursor has moved further than SystemInformation.DragSize, which indicates that the user is dragging rather than clicking, and start the drag operation if needed. In MouseUp, you either complete the drag or perform the click action.
I believe the conventional wisdom for Drag-n-drop is
Call DoDragDrop in the (source control's) MouseDown handler
set AllowDrop = true in the targe control's AllowDrop property
There's a whole series of drag events to fine tune behavior
One does not seem to have to worry about any latent MouseUp or MouseClick events. I'm assuming this is because the physical actions of button press and release are done over different controls and/or the mouse physically moved "far enough".
I'm having a Picture box in a user control window(Windows custom control library). and some functionality in the Form's Enter event and leave event.
Now my sample application is having two instances of the control. So when i run my sample application the fist control got selected and the enter event is triggered, and when i select the second control the first's leave and second's enter events are getting triggered.
Now, problem is that when i select(click) the second control's picturebox, the events are not triggering, i.e the control form is not getting the event.
So if i click whereever in the control(in the picturebox or in the control) the enter event should be triggered.
How to do this?
A picture box can't get focus. So clicking on it won't take the focus away from the previous control thus not triggering the events.
You need to add a click handler on the picture box in which you manually give focus to the associated focusable control.
private void PictureBox_Click(object sender, EventArgs e)
{
focusableControl.Focus();
}