Reputation: 2436
I'm trying to override the mousewheel control so that when the mouse wheel is moved up or down it only increases the value in the numericupdown field by 1. I believe it is currently using what is stored in the control panel and increasing/decreasing the value by 3 each time.
I'm using the following code. Even when numberOfTextLinesToMove is only 1 and I see that txtPrice.Value is getting populated as expected, something else is overwriting it because the value I set is not what is displayed in the numericupdown box
void txtPrice_MouseWheel(object sender, MouseEventArgs e)
{
int numberOfTextLinesToMove = e.Delta / 120;
if (numberOfTextLinesToMove > 0)
{
txtPrice.Value = txtPrice.Value + (txtPrice.Increment * numberOfTextLinesToMove);
}
else
{
txtPrice.Value = txtPrice.Value - (txtPrice.Increment * numberOfTextLinesToMove);
}
}
Upvotes: 14
Views: 12005
Reputation: 515
The following code will walk down your entire Form and fix every decendent NumericUpDown Control.
Rewritten based on this and this
add the following code to your class (or some utility class):
static void FixNumericUpDownMouseWheel(Control c) {
foreach (var num in c.Controls.OfType<NumericUpDown>())
num.MouseWheel += FixNumericUpDownMouseWheelHandler;
foreach (var child in c.Controls.OfType<Control>())
FixNumericUpDownMouseWheel(child);
}
static private void FixNumericUpDownMouseWheelHandler(object sender, MouseEventArgs e) {
((HandledMouseEventArgs)e).Handled = true;
var self = ((NumericUpDown)sender);
self.Value = Math.Max(Math.Min(
self.Value + ((e.Delta > 0) ? self.Increment : -self.Increment), self.Maximum), self.Minimum);
}
then in contructor of the form, after InitializeComponent()
, insert line:
FixNumericUpDownMouseWheel(this);
Upvotes: 1
Reputation: 51
After looking around at similar questions, I discovered that you can also work around this without creating a subclass - for example, this code will give you a numericUpDown that will only scroll by one (and only when the control has focus).
Set up the delegate in the container's constructor:
numericUpDown1.MouseWheel += new MouseEventHandler(this.ScrollHandlerFunction);
... then define the function elsewhere in the class:
private void ScrollHandlerFunction(object sender, MouseEventArgs e)
{
HandledMouseEventArgs handledArgs = e as HandledMouseEventArgs;
handledArgs.Handled = true;
numericUpDown1.Value += (handledArgs.Delta > 0) ? 1 : -1;
}
You should also check to make sure that you're not trying to scroll out of the control's range, because that will crash.
Upvotes: 5
Reputation: 322
Based on Jay Riggs answer, here is a cleaner version (for my opinion):
namespace MyControls
{
public partial class NumericUpDown : System.Windows.Forms.NumericUpDown
{
public Decimal MouseWheelIncrement { get; set; }
public NumericUpDown()
{
MouseWheelIncrement = 1;
InitializeComponent();
}
protected override void OnMouseWheel(MouseEventArgs e)
{
decimal newValue = Value;
if (e.Delta > 0)
newValue += MouseWheelIncrement;
else
newValue -= MouseWheelIncrement;
if (newValue > Maximum)
newValue = Maximum;
else
if (newValue < Minimum)
newValue = Minimum;
Value = newValue;
}
}
}
Upvotes: 1
Reputation: 103
The user3610013's answer is working very well. This is a slight modification and may be handy to someone.
private void ScrollHandlerFunction(object sender, MouseEventArgs e)
{
NumericUpDown control = (NumericUpDown)sender;
((HandledMouseEventArgs)e).Handled = true;
decimal value = control.Value + ((e.Delta > 0) ? control.Increment : -control.Increment);
control.Value = Math.Max(control.Minimum, Math.Min(value, control.Maximum));
}
Upvotes: 8
Reputation: 141
I recently had this problem, and got around it by changing the increment.
numericUpDown1.Increment = 1m / SystemInformation.MouseWheelScrollLines;
Edit: This is only a good solution if you intend to only use the mousewheel to change the value. To fix this for all situations, you have to override the class. Here's a simple version.
public class NumericUpDownFix : System.Windows.Forms.NumericUpDown
{
protected override void OnMouseWheel(MouseEventArgs e)
{
HandledMouseEventArgs hme = e as HandledMouseEventArgs;
if (hme != null)
hme.Handled = true;
if (e.Delta > 0)
this.Value += this.Increment;
else if (e.Delta < 0)
this.Value -= this.Increment;
}
}
Upvotes: 14
Reputation: 1211
I took Hans Passant's advice and subclassed NumericUpDown
to add this functionality. It uses a modified version of Reflector's code for the OnMouseWheel method. Here's what I ended up with for anyone who's interested.
using System;
using System.ComponentModel;
using System.Windows.Forms;
/// <summary>
/// Extends the NumericUpDown control by providing a property to
/// set the number of steps that are added to or subtracted from
/// the value when the mouse wheel is scrolled.
/// </summary>
public class NumericUpDownExt : NumericUpDown
{
private int wheelDelta = 0;
private int mouseWheelScrollLines = 1;
/// <summary>
/// Gets or sets the number of step sizes to increment or
/// decrement from the value when the mouse wheel is scrolled.
/// Set this value to -1 to use the system default.
/// </summary>
[DefaultValue(1)]
[Description("Gets or sets the number of step sizes to increment or decrement from the value when the mouse wheel is scrolled. Set this value to -1 to use the system default.")]
public Int32 MouseWheelScrollLines {
get { return mouseWheelScrollLines; }
set {
if (value < -1)
throw new ArgumentOutOfRangeException("value must be greater than or equal to -1.");
if (value == -1)
mouseWheelScrollLines = SystemInformation.MouseWheelScrollLines;
else
mouseWheelScrollLines = value;
}
}
protected override void OnMouseWheel(MouseEventArgs e) {
HandledMouseEventArgs args = e as HandledMouseEventArgs;
if (args != null) {
if (args.Handled) {
base.OnMouseWheel(e);
return;
}
args.Handled = true;
}
base.OnMouseWheel(e);
if ((Control.ModifierKeys & (Keys.Alt | Keys.Shift)) == Keys.None && Control.MouseButtons == MouseButtons.None) {
if (mouseWheelScrollLines != 0) {
this.wheelDelta += e.Delta;
float num2 = (float)this.wheelDelta / 120f;
if (mouseWheelScrollLines == -1)
mouseWheelScrollLines = 1;
int num3 = (int)(mouseWheelScrollLines * num2);
if (num3 != 0) {
int num4;
if (num3 > 0) {
for (num4 = num3; num4 > 0; num4--)
this.UpButton();
this.wheelDelta -= (int)(num3 * (120f / (float)mouseWheelScrollLines));
} else {
for (num4 = -num3; num4 > 0; num4--)
this.DownButton();
this.wheelDelta -= (int)(num3 * (120f / (float)mouseWheelScrollLines));
}
}
}
}
}
}
Upvotes: 5
Reputation: 53593
This is a bug reported here: NumericUpDown - use of mouse wheel may result in different increment
Microsoft's response in Feb 2007 states they cannot address this Visual Studio 2008.
There are two posted workarounds, both of which subclass NumericUpDown
. Check the Workaround tab on the link.
The one I tried worked for me (posted by 'NanoWizard'):
using System;
using System.Windows.Forms;
internal class NumericUpDownControl : NumericUpDown
{
#region Constants
protected const String UpKey = "{UP}";
protected const String DownKey = "{DOWN}";
#endregion Constants
#region Base Class Overrides
protected override void OnMouseWheel(MouseEventArgs e_)
{
String key = GetKey(e_.Delta);
SendKeys.Send(key);
}
#endregion Base Class Overrides
#region Protected Methods
protected static String GetKey(int delta_)
{
String key = (delta_ < 0) ? DownKey : UpKey;
return key;
}
#endregion Protected Methods
}
Upvotes: 0