WPF GridSplitter - How to disable mouse drag and keyboard resize - c#

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.

Related

Disable Windows 10 "scroll inactive windows" in C# Winforms

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.

Resizable Textbox in Winforms

I want to know how to let a user resize a textbox themselves at runtime. Preferably the little tabs on the borders of the textbox would popup and they can drag to resize as per most apps.
Is it possible to do this natively using winforms? if not is there a library to help do it?
I would rather use native components if possible. All my google searches turn up false positives.
The simpliest solution by using the native components would be implementing you own custom-control using the textbox and adding MouseEvents. Here is a sample that lets you drag the TextBox's bottom area, in vertical direction. Of course you should implement something more like changing the cursor's handle and repainting some areas if you would like to make a pop-up.
Here is a working concept:
bool isDrag = false;
int lastY = 0;
private void textBox1_MouseEnter(object sender, EventArgs e)
{
//Change cursor to dragging handle or implement a pop-up
}
private void textBox1_MouseDown(object sender, MouseEventArgs e)
{
//Just add 5px padding
if (e.Y >= (textBox1.ClientRectangle.Bottom - 5) &&
e.Y <= (textBox1.ClientRectangle.Bottom + 5))
{
isDrag = true;
lastY = e.Y;
}
}
private void textBox1_MouseMove(object sender, MouseEventArgs e)
{
if( isDrag)
{
textBox1.Height += (e.Y - lastY);
lastY = e.Y;
}
}
private void textBox1_MouseUp(object sender, MouseEventArgs e)
{
if (isDrag)
{
isDrag = false;
}
}
To try the code, on a new form, create a TextBox named textBox1 and wire all the MouseEvents. Try to bring your mouse on the bottom of the TextBox and drag either going top or bottom.
And do not forget to set TextBox.Multiline to true.
Better approach is to use the Anchor and Dock properties to scale controls based on their parent controls. Have a read Manage WinForm controls using the Anchor and Dock properties
Other options are TableLayoutPanel and FlowLayoutPanel base on your requirement.
TableLayoutPanel
The TableLayoutPanel control arranges its contents in a grid. Because
the layout is performed both at design time and run time, it can
change dynamically as the application environment changes. This gives
the controls in the panel the ability to proportionally resize, so it
can respond to changes such as the parent control resizing or text
length changing due to localization.
Any Windows Forms control can be a child of the TableLayoutPanel
control, including other instances of TableLayoutPanel. This allows
you to construct sophisticated layouts that adapt to changes at
runtime.
FlowLayoutPanel
The FlowLayoutPanel control arranges its contents in a horizontal or
vertical flow direction. Its contents can be wrapped from one row to
the next, or from one column to the next. Alternatively, its contents
can be clipped instead of wrapped.
You can specify the flow direction by setting the value of the
FlowDirection property. The FlowLayoutPanel control correctly reverses
its flow direction in right-to-left (RTL) layouts. You can also
specify whether the contents of the FlowLayoutPanel control are
wrapped or clipped by setting the value of the WrapContents property.

Stop scrolling with current offset in windows phone

Am having a problem in scrollviewer.
Scenario:
am having a stack panel inside which having a content, from mouse move of that content am showing a popup to rearrange those content.
issue: when am trying to handle mouse move of that content popup shows and also scrolling happening.
expected behavior: scrolling should not happen while handling mouse move.
i have tried "HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled" it works fine but it sets the scrollviewer to its initial position, means horizontal offset sets to Zero("0")
thanks in advance.
As per our discussion, I think the best route would be to store a class level boolean which will determine whether or not to enable scrolling. You'd have to set this according to your needs (Probably the same place you were modifying the visibility before).
The next step would be to set up some events and properties on your scrollviewer so that you can control whether it scrolls or not. You really only need to modify the constructor of the page holding the scrollviewer, and create a handler for the ManipulationStarted event. The following assumes your control is named Scroll, and that the variable locked is set to true when the control should not scroll:
public MainWindow()
{
InitializeComponent();
Scroller.ManipulationStarted += new EventHandler<ManipulationStartedEventArgs>(scroller_ManipulationStarted);
Scroller.ManipulationMode = ManipulationMode.Control; // Required
}
void scroller_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
{
if (locked)
{
e.Handled = true;
e.Complete();
}
}

MouseLeave doesn't fire when moving from child control to parent's parent

I have a UserControl that listens to it's own MouseLeave in order to change it's background color and some of it's children visibility.
The children that should lose visibility, also listen their own MouseLeave in order to change their background color.
A scenario in which everything works is this:
Move mouse into UserControl.
Move mouse into Child.
Move mouse out of Child into UserControl.
The problematic scenario is this:
Move mouse into UserControl.
Move mouse into Child.
Move mouse out of Child, not into the UserControl, but directly outside of it.
This scenario happens all the time since the Child is located at the very edge of the UserControl.
Note that not only the UserControl's MouseLeave doesn't fire, but neither does the Child's MouseLeave.
In order to find out whether the mouse has actually left the area in this case, I must listen to MouseEnter of other controls, and then notify the UserControl and Child, but I really want to avoid this solution, since it is ugly and not OOPish.
Also, the Child MUST be located at the very edge of the UserControl, and cannot move.
Can anyone think of a neat solution to the problem?
My tests show this as a working solution. Just requires a custom user control.
public class MyPanel : Panel
{
protected override void OnControlAdded(ControlEventArgs e)
{
e.Control.MouseLeave += DidMouseReallyLeave;
base.OnControlAdded(e);
}
protected override void OnMouseLeave(EventArgs e)
{
DidMouseReallyLeave(this, e);
}
private void DidMouseReallyLeave(object sender, EventArgs e)
{
if (this.ClientRectangle.Contains(this.PointToClient(Control.MousePosition)))
return;
base.OnMouseLeave(e);
}
}
I've seen the same behavior before. Is your .NET version up-to-date? Be sure you're on the latest service packs.
Have you seen the event Application.AddMessageFilter? I used that in an answer here to catch mouse messages and handle them more intelligently. It might come in handy here.
This isn't how MouseLeave is supposed to behave. You should get the MouseLeave event even if the mouse cursor moves our of your application window entirely.
I'm guessing you're not calling the base method in your MouseLeave handler.
Anyway, on MouseEnter you can set a timer that fires every 0.25 second, and in it check if the mouse is still over the control. If it isn't, kill the timer and change the control's color.

Can I make a window not resize itself until the user lets go of the mouse button?

I have some screens with a lot of stuff on them, and the redrawing performance is pretty poor. It is possible to set a form into a resizing mode where a rectangle is shown on the screen that denotes the new window dimensions as the user resizes it, but the actual form doesn't resize until they let go of the mouse button?
Thanks!
Yes; this behavior is defined by one of the window styles, which you can turn on/off using the Control.SetStyles method. In particular, I think you want this:
myForm.SetStyle(ControlStyles.ResizeRedraw, false);
You could then hook the mousedown/resize/mouseup events and force the redraw to happen when you wanted.
You can also try turning on the double buffering style:
myForm.SetStyle(ControlStyles.DoubleBuffer, true);
See this article for details: http://msdn.microsoft.com/en-us/library/fkf25009(v=vs.100).aspx
Completely suppressing all drawing is not practical, the window frame painting is out of your direct control. Nor is it necessary, all you have to do is make your drawing fast when the form is being resized. Like this:
private bool fastRender;
protected override void OnResizeBegin(EventArgs e) {
fastRender = true;
base.OnResizeBegin(e);
}
protected override void OnResizeEnd(EventArgs e) {
base.OnResizeEnd(e);
fastRender = false;
this.Invalidate();
}
And check the fastRender variable in your Paint event handler, drawing only the minimum. Or nothing at all. If the actual delay is caused by a large number of controls then tackle that by making them invisible in ResizeBegin and visible again in ResizeEnd. Easy to do with a Panel. If it is caused by a controls that are docked or have the Anchor set so that they'll resize or move whenever the user resizes the window then you'll find Suspend/ResumeLayout useful.
Have you tried using the DoubleBuffer feature of a winform/control?
How about using ResizeEnd instead of Resize.
Open the window that is abnormally sized; then hold down the control key, hit the + key until you return to your required size. Good luck.

Categories