I have a question regarding C#, Winforms and "Scroll inactive windows when I hover over them" in Windows 10.
I have a flow layout panel, which i dynamically fill with custom controls.
The controls have a zoom in zoom out feature that is controlled by the mouse wheel.
When the number of controls exceed the flow layout panel size i got AutoScroll = true, so the panel gets a vertical scroll bar. I do not want to scroll the panel with the mouse wheel, i want the user to manually do it.
Everything works fine in Windows 7, but in Windows 10, if the user has the "Scroll inactive windows when I hover over them" turned on, when the mouse is over a control and the user uses the mouse wheel, the control zooms in or out, but the panel also scrolls.
I debugged, and i found that Win10 scrolls the panel even before the form/panel's MouseWheel event.
How can I disable the "Scroll inactive.." temporarily in my code ? or at least disable its behavior?
Thanks !
The only thing comes to my mind to disable the behavior is to check whether the window is TopMost or lost focus.
This can be done by using the form.TopMost property or the Activated and Deactivate events.
Using the events:
public Form1()
{
InitializeComponent();
this.Deactivate += Form1_Deactivate;
this.Activated += Form1_Activated;
}
private void Form1_Activated(object sender, EventArgs e)//The form gained focus
{
panel1.Enabled = true;
}
private void Form1_Deactivate(object sender, EventArgs e)// The form lost focus
{
panel1.Enabled = false;
}
These will work just fine but using some controls it will make them change appearance on some OS.
If you don't mind that, great.
If you do, you should go for the same concept using the events only disabling the scroll itself once the form lost focus and enabling it when its regained.
Cheers.
Related
I have written a custom Control, based on other code, which includes a call to SetStyle(ControlStyles.Selectable, false);
This prevents the following code from being called (which works if I remove the above line and click on the Control first to 'focus' it):
protected override void OnMouseWheel(MouseEventArgs e)
{
ScrollBar.Value = Math.Min(ScrollBar.Value - e.Delta, ScrollBar.Maximum - ScrollBar.LargeChange);
LayoutChanged();
}
My control does not need focus so Selectable=false is correct.
What do I need to do so that I can run this code whenever the mouse is over my control and the MouseWheel is moved regardless of where the focus is?
Thanks for the comments. A additional info:-
I am running Windows 7 but any solution must work on any OS.
The Control is inherited via Control/ControlBase/BaseControl/BaseStyleControl where the latter 3 are DevExpress controls.
The real focus should not be changed just because the cursor hovers over my control
There are no child controls other than a scrollbar (an inherited DevExpress one) which is normally invisible and shows itself when the mouse hovers over where it would be when visible.
The control does nothing but draw itself (imagine a number of bookshelves one under the other with book covers drawn on them - the number of shelves increases to accommodate all the books and the scrollbar allows all to be scrolled into view.
Since this is a use-anywhere Control, getting MouseWheel events from a Parent that knows about its requirements isn't a good idea.
Maybe there is a way of registering for a first-look (is that a MessagePreview?) to pinch MouseWheel events before normal processing happens.
I am currently using MSCharts in one of my windows forms. One of the quirky things about MSCharts is that you cannot trigger a MouseWheel event in the chart unless the chart has focus. To combat this, most people are saying that one should add a MouseEnter event to the chart and then Focus() the chart to allow one's MouseWheel events to fire (see here: Enabling mouse wheel zooming in a Microsoft Chart Control).
Let's say that I pull up a completely different window (call it Window A) that just so happens to be partially in front of my chart (call it window is Window B). If I accidentally move the mouse over the chart in Window B for even 10 milliseconds, Window B will take focus and Window A will be placed behind it, which is incredibly frustrating.
I've explored different options.
Setting Window B's TopMost property to true. The problem with this is that the user has to either close the window or minimize it to hide it. If there are a lot of windows up, it seems to be just as frustrating as the initial issue.
Instead of giving the MouseEnter event the ability to Focus(), let the MouseClick or MouseHover event to Focus(). The problem with MouseClick is that the user will always have to click on the chart first to zoom, which isn't bad, but can be annoying. MouseHover is okay, but the time that the event considers to be a hover is really short.
In the end, I want it so that I can put my mouse over the chart and scroll in without having to do anything (mouse clicks, or anything else). In addition to this, I don't want the form that contains the chart to jack the focus back to it if I accidentally move my mouse over it for just a second.
EDIT:
It seems that according to #TaW, the chart doesn't need focus to trigger MouseWheel events in Window 10. This is not the case in Windows 7, unfortunately.
This may seem slightly hacky, but it works in this case:
This works through the use of the FindForm method. I never knew it was a thing until now. You can read more about it here: https://msdn.microsoft.com/en-us/library/system.windows.forms.control.findform(v=vs.110).aspx
myChart.MouseEnter+= delegate(object sender, EventArgs args) //add a mouse enter event to your chart
{
if (!chart.Focused) //if chart isn't focused
{
if (chart.FindForm().ContainsFocus) //check if the form the chart is in contains focus
chart.Focus(); //if the chart isn't focused, but the form is focused, focus on the chart
}
};
This will still give the chart focus when you move your mouse into it and it will not allow the form that contains the chart to jack the focus from the form you're in.
I've made a WPF application and one of my windows is required to go fullscreen, however I'm trying to get it so that if the user drags the window to another monitor it will automatically resize to suit that monitor.
I've tried the previewmouse up down events, mouse up down events to set a bool that the window is being dragged to prevent the code from executing, however this does not appear to work and the window is still trying to resize itself as its being dragged and the mouse is down (as if mousedown is being set to false)
The code that resizes the window is in the window located changed event
Is there any other ways that can effectively detect that the mouse is down and dragging the window to another monitor before executing the code to resize it to suit?
Whilst the user is dragging the window I dont want the code to resize it to be executed, once the user has finished dragging the window, the code to resize the window to the new screen should be executed.
Currently I cant get the code to run after the window has finished moving.
Upon further investigation, no mouse up events are fired after the mouse is released on the title border.
You can override OnPreviewMouseMove for any UI element.
protected override void OnPreviewMouseMove(MouseEventArgs e)
Then using the event args of that handler (of type MouseEventArgs) - you check if the left mouse button is pressed (indicating a drag).
e.LeftButton == MouseButtonState.Pressed
When you start dragging a maximized Window, the size changes. This is how Windows behaves and is natural to a user. On end of drag you can just set the state back to maximized.
Application.Current.MainWindow.WindowState = WindowState.Maximized;
Did you checked this event ? Sounds like what you need.
https://msdn.microsoft.com/en-us/library/system.windows.window.locationchanged%28v=vs.110%29.aspx
I've implemented a grid splitter based on a few blog sources that basically allows expand/collapse based on a double click event.
The splitter is in between two columns of a grid that represent a screen layout with a NavigationPanel on the left and a MainContentPanel on the right, with the splitter allowing the NavigationPanel to be collapsed to a minimum width where only icons are displayed.
Is there a way to disable the default behaviour of the grid splitter when it comes to allowing dragging of the splitter and keyboard adjustments?
My current workaround is as follows
Disable keyboard adjustments by setting Focusable to False
Prevent the user "grabbing" the splitter by placing a ToggleButton control overtop of the same as the GridSplitter, thereby having the button intercepting all mouse clicks.
I've got a version where I don't use a ToggleButton at all and just handle the double click event on the GridSplitter but the problem with that is I can't find a way to disable the mouse dragging functionality.
Honestly don't understand why you'd want to do this, but if you really want to disable mouse AND keyboard input, just set IsEnabled to false. As you already discovered, if you only want to disable keyboard input, set Focusable to false- this is what brought me here, trying to figure that out :)
One alternative I've found is to add a handler for the DragDeltaEvent and then mark it as handled.
public class ExtendedGridSplitter : GridSplitter
{
...
public ExtendedGridSplitter()
{
EventManager.RegisterClassHandler(typeof(ExtendedGridSplitter), Thumb.DragDeltaEvent,
new DragDeltaEventHandler(OnDragDelta));
}
...
private void OnDragDelta(object sender, DragDeltaEventArgs e)
{
e.Handled = true;
}
}
And for the keyboard events overriding the handler works similarly
protected override void OnKeyDown(KeyEventArgs e)
{
e.Handled = true;
}
A simple solution which works for me (though not very pretty) is setting the MaxWidth and MinWidth to the same value. In my case I wanted to turn off the use of the splitter when the user selected to close the window and show a "re-appear" icon it in the sidebar.
Unfortunately the MouseWE grippers still light up but they can do nothing.
My Form has a Panel which has an inner panel. I have a VScrollBar inside the parent panel, which scrolls the inner panel. Everything works fine. But if I keep on clicking the up/down zip of VSCrollBar, the scrollbar seems to get crashed.
From some investigation, I got to know that, it keeps sending WM_LBUTTONDOWN message to the Form and it routed back to the Panel again, which triggers the UpdateBounds() of my outer Panel. This makes my panel spread across the form and I am not able to see any other controls on the entire form.
Has anybody come across this issue? Is there any workaround or any fix for it?
Here there are some more details about this scrollbar freezing issue.
private void vsBar_ValueChanged(object sender, EventArgs e)
{
UpdatePicTops();
}
private void UpdatePicTops()
{
pnlNames.Top = (int)VB6.TwipsToPixelsY(-vsBar.Value);
pnlValues.Top = (int)VB6.TwipsToPixelsY(-vsBar.Value);
}
I have a pnlContainer which holds the pnlNames and pnlValues.
pnlContainer has vsBar (vertical scroll bar), This scrolls perfectly based on my pnlNames/pnlValues height when its exceeding.
I am setting the vsBar properties during my form load based on the child panel height.
When I keep on clicking Up and Down zip button on my vsBar suddenly makes the scroll bar behaves unexpected way. All of sudden up and down zip button disappears and then each click on my vsBar sends a WM_LBUTTONDOWN button the parent form and that again triggers UpdateBounds() without any argument to my pnlContainer , this makes my pnlContainer height and width equivalent to my form height and width.
Please feel free to ask if you have any questions.