Событие numericupdown mousewheel увеличивает десятичное число более чем на один шаг
Я пытаюсь переопределить элемент управления mousewheel, чтобы при перемещении колеса мыши вверх или вниз оно только увеличивало значение в поле numericupdown на 1. Я считаю, что в настоящее время он использует то, что хранится в панели управления, и каждый раз увеличивает/уменьшает значение на 3.
Я использую следующий код. Даже когда numberOfTextLinesToMove только 1, и я вижу, что txtPrice.Значение заполняется, как ожидалось, что-то еще перезаписывает его, потому что значение Я установил не то, что отображается в поле numericupdown
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);
}
}
7 ответов
Это ошибка, описанная здесь: NumericUpDown-использование колеса мыши может привести к различному приращению
в ответе Microsoft в феврале 2007 говорится, что они не могут обратиться к этой Visual Studio 2008.
есть два опубликованных обходных пути, оба из которых подкласса NumericUpDown
. Проверьте вкладку обходной путь по ссылке.
тот, который я пробовал, работал для меня (опубликовано '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
}
недавно у меня была эта проблема, и я обошел ее, изменив приращение.
numericUpDown1.Increment = 1m / SystemInformation.MouseWheelScrollLines;
Edit: это только хорошее решение, если вы собираетесь использовать только колесико мыши для изменения значения. Чтобы исправить это для всех ситуаций, необходимо переопределить класс. Вот простая версия.
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;
}
}
Я принял совет Ганса Пассанта и подкласс NumericUpDown
чтобы добавить эту функцию. Он использует модифицированную версию кода Reflector для метода OnMouseWheel. Вот то, что я получил для всех, кто заинтересован.
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));
}
}
}
}
}
}
ответ user3610013 работает очень хорошо. Это небольшая модификация и может кому-то пригодиться.
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));
}
после просмотра подобных вопросов я обнаружил, что вы также можете обойти это без создания подкласса - например, этот код даст вам numericUpDown, который будет прокручиваться только на один (и только когда элемент управления имеет фокус).
настройте делегат в конструкторе контейнера:
numericUpDown1.MouseWheel += new MouseEventHandler(this.ScrollHandlerFunction);
... затем определите функцию в другом месте класса:
private void ScrollHandlerFunction(object sender, MouseEventArgs e)
{
HandledMouseEventArgs handledArgs = e as HandledMouseEventArgs;
handledArgs.Handled = true;
numericUpDown1.Value += (handledArgs.Delta > 0) ? 1 : -1;
}
вы должны также проверить, чтобы убедиться, что вы не пытаетесь прокрутить вне пределов досягаемости управления, потому что он разобьется.
основываясь на ответе Джея Риггса, вот более чистая версия (на мой взгляд):
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;
}
}
}
следующий код будет идти вниз по всей форме и исправить каждый decendent Numericupdown управления.
переписан на основе этой и этой
добавьте следующий код в свой класс (или какой-либо класс утилиты):
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);
}
затем в контрукторе формы, после InitializeComponent()
вставить строку:
FixNumericUpDownMouseWheel(this);