I created a movable panel in WinForms. I use a ToolStrip as a titlebar in the panel. I'll use the ToolStrip to move the panel as well as indicating the panel is "active" or not. So when the panel is active, I want to change the ToolStrip's BackColor to Red.
UPDATE: The panel will host other controls, such as a listview. I want the panel being shown as "active" when the hosted control get focus, kind like the behavior of a normal window, whereas the window becomes the panel, and the titlebar becomes the ToolStrip.
When the panel is considered as "active"
hosted control get focus
ToolStrip being MouseDown/MouseClick
ToolStrip being dragged by mouse
The idea is capturing ToolStrip's Enter/Leave event to change the color, but it seems those events are never fired.
Are those events truly never fired? Should I capture other events?
mmmm there are a few ways to do this I guess.
You could use hook into the IMessageFilter message and see if its over your toolstrip/panel and then act accordingly (WM_LBUTTONDOWN, WM_MOUSEMOVE, WM_LBUTTONUP etc - see windows documentation on WIndows Messages for hex message codes for all windows messages). There are many examples about - for example: How to detect if the mouse is inside the whole form and child controls?
Setting a boolen based on whether active or not, an override in the paint can allow the colour settings - or simply flip them along with/instead of the boolean. Same for moving, set a boolean for move active/or not - and then allow WM_MOUSEMOVE to move the form/panel (or not) as needed.
Related
I am creating an image browser that uses a FlowLayoutPanel to display thumbnails of images. See animated GIF that shows how I scroll down the panel, switch to another window, and then back to the form which causes the FlowLayoutPanel to scroll back to the top. I can't imagine any reason why it would do this.
Also, I seem to be able set the scroll location by clicking on the panel. When the form loses and regains focus, it scrolls back to the last Y position that I clicked.
Why is it exhibiting this behavior and how can I prevent it from occurring?
The effect described is quite common: when a FlowLayoutPanel contains Controls that can be activated and one of these child Controls is selected at some point (in this case a UserControl, which has the WS_EX_CONTROLPARENT extended style, so SetStyle(ControlStyles.Selectable, false) won't do much) and the FlowLayoutPanel is then scrolled to hide this Control, when the Form is deactivated and then activated again, the ActiveControl is scrolled into view.
This causes the FlowLayoutPanel to scroll to a position where the child ActiveControl is visible.
▶ This doesn't happen when the child Controls are not selectable, as the PictureBox Control, for example. If this Control were used to present the thumbnails (as shown in the question), the FlowLayoutPanel would not scroll.
I think the simplest way to prevent the FlowLayoutPanel from scrolling to the ActiveControl is to set the FlowLayoutPanel itself as the ActiveControl when the Form is deactivated, handling the Deactivate event.
private void form1_Deactivate(object sender, EventArgs e)
{
this.ActiveControl = this.flowLayoutPanel1;
}
This has no meaningful side affects, except the Control that previously was the ActiveControl will raise the Leave event.
It may be also used to suspend some other activity, since the User is now focusing on another Window.
▶ To set the ActiveControl to the default one instead (the Control that is activated when the Form is first shown), set this.ActiveControl = null;. It will be reset when the Form is activated again.
I've seen sometimes the Activated and Deactivate events used to disable and enable back a ContainerControl: this also prevents the scrolling, of course, but may cause unwanted cascading effects when child Controls are disabled.
But it may also be something expected and possibly desired. It depends on what happens behind the scene (implementation details).
The solution proposed by #Loathing in comments can also work, deriving a Custom Control from FlowLayoutPanel. It depends on the use case.
Stop form from scrolling when moving controls
I have a System.Windows.Forms.VScrollBar control on my form and select it programmatically by calling scrollBar.Select() so that mouse-wheel and keyboard scrolling just works (without the user having to explicitly select the scrollbar beforehand). However, this causes the scrollbar cursor to constantly flash every half a second or so. Is there any way to stop this behaviour? I have looked around but I can't find any property to control this behaviour?
I even tried creating a custom scrollbar inherting from VScrollBar and overriding OnPaint, but that's not even getting called, so I guess its not used by VScrollBar at all.
I don't know that keyboard scrolling can be easily implemented on a WinForms AutoScroll control (see this answer). I do know that so long as the AutoScroll control has focus in the form, mouse-wheel scrolling should work without the user selecting the scrollbar itself. I suggest that rather than calling scrollBar.Select() to accomplish what you need, you instead call scrollBarParent.Focus(). This should take care of the flashing issue.
I've created a form that's maximized over the entire screen.
Within that form, and sized to fill the entire form, I've placed a panel with background color set to Red. The form's TransparencyKey is set to Red.
Therefore, the Panel is like a "keyhole" - you can see the desktop that's directly underneath it.
When the user clicks on the panel, OR, presses a key on the keyboard, I want to take action.
But, because the panel is completely transparent, when it is clicked or a key is pressed, nothing happens. If I make the panel non-transparent (setting it's background color to Blue, for example), it does respond to clicks.
What's the best way to get the panel to respond to clicks and keypresses?
Do I have to hook all mouse an keyboard events on the entire system or is there a simpler way?
The panel does not take in text input, you can set your main form to handle the keypress event.
this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.form_KeyPress);
http://screensnapr.com/v/VovWAi.png
As for getting the mouse location on your panel, you can use the mouseclick event
this.panel1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseClick);
http://screensnapr.com/v/DB3kCQ.png
I have tested it, and it works on a fullsize transparent panel
I've discovered that I can use GetAsyncKeyState to respond to both keypresses and mouse clicks.
[DllImport("user32.dll")]
public static extern int GetAsyncKeyState(System.Windows.Forms.Keys vKey);
Then, I can call GetAsyncKeyState(Keys.LButton) and GetAsyncKeyState(Keys.Escape), for example. Much simpler than hooking all keyboard and mouse events.
I have a large user drawn control that fills most of the screen area in an application.
I would like to simulate some "onMouseHover" behaviour, I cant really use the userControl event as the mouse is almost always on that control so it fires all of the time.
How can I detect the mouse "hovering" over part of my user drawn control?
(If it helps an image of the app can be found at : http://www.benbun.co.uk/st3/ayv the control is the large "year calendar")
You could handle MouseMove events instead of MouseHover. Then you could calculate based on the X,Y location of the mouse whether or not the cursor is in the part of your control you are interested in creating "hover" behavior for.
I have a custom Canvas control (inherited from Canvas) overlaid over a large area of User Controls. The idea is to draw paths between user controls (i.e. connector lines).
To capture mouse movement, I call Mouse.Capture(theCanvas) on MouseDown. This works beautifully, but the user controls under the canvas obviously no longer receive mouse events. Mouse.DirectlyOver always shows the canvas, so I can't really fake it by peeking at the current position and seeing which user control it's over.
So, I still need the Canvas for drawing paths, but how can I solve this one of the following ways:
Peek under the Canvas and see what the topmost control is right under it?
Get this MouseDown -> Track MouseMoves -> MouseUp workflow to work on the canvas without mouse captures?
Any other ideas welcome...
I'd agree that those are your two options. If you want to only forward some clicks to your usercontrols, then go with option 1, and hit test the controls under the canvas.
If you need your usercontrols to behave as though there is nothing covering them (textboxes, buttons etc), then i'd recommend using the PreviewMouseMove event on the user control's parent, as this can pick up and optionally "handle" events before the controls get at the event, but it won't block the event if you don't set handled to true