65.9K
CodeProject 正在变化。 阅读更多。
Home

移动数字增减控件

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.80/5 (4投票s)

2008 年 5 月 19 日

CPOL

4分钟阅读

viewsIcon

29283

downloadIcon

300

一个简单、可重用、支持小数位以及最大/最小值限制的移动数字增减控件。

引言

如果您之前开发过移动 .NET 应用程序,您很可能已经注意到,标准的数字增减控件并没有提供您在桌面版 .NET 中习以为常的所有功能。如果您需要其中一些缺失的功能,您有多种选择,但它们通常涉及付费、臃肿的控件库,或者有时就是不如您期望的那样工作。

使用代码

使用该控件并没有多少复杂之处……只需将其拖到您的表单上,然后设置几个控件属性,如下所示(抱歉,编辑质量是 MS-Paint 级别)

designer.PNG

图 1 - 设计器属性

设置 DecimalPlaces 属性将按您预期的方式工作——它将更新显示的位数,正如您在此处看到的

no_validation.PNG

图 2 - DecimalPlaces 使用示例

使用此控件时需要考虑的一个属性是 EnforceMinMax。如果将其设置为 true,则用户无法将值修改到超出设定的范围。在下面的截图中,您会注意到用户已达到最大值。因此,“向上”按钮已被禁用,如果用户按下键盘/SIP(软输入面板)上的“向上”或“向下”键,他们将无法超出设定的限制。

max.PNG

图 3 - 控件处于最大值示例

此外,如果用户尝试输入一个高于 100 或低于 0 的新值,该值将被重置为最接近的限制——例如,在本例中,如果用户输入 -5,该值将被重置为 0。

如果您想自行进行验证,请将 EnforceMinMax 的值设置为 false,然后监听控件的 Validating 事件,并按您想要的方式处理它。这是一个示例

private void numericUpDown1_Validating(object sender, CancelEventArgs e)
{
    if ((numericUpDown1.Value > numericUpDown1.Maximum)
        || (numericUpDown1.Value < numericUpDown1.Minimum))
    {
        MessageBox.Show(string.Format(&quot;Value must be between '{0}' and '{1}'.&quot;, 
                        numericUpDown1.Minimum, numericUpDown1.Maximum));
        e.Cancel = true;
    }
}

关注点

如果您查看代码,您会注意到我必须处理来自文本框以及向上和向下按钮的多个事件

private void btnDown_GotFocus(object sender, EventArgs e)
{
    OnGotFocus(EventArgs.Empty);
}
private void btnDown_LostFocus(object sender, EventArgs e)
{
    OnLostFocus(EventArgs.Empty);
}

在 .NET CF 2.0 中,这是必需的,因为存在一个 bug,即自定义用户控件不会调用 OnGotFocusOnLoseFocusOnValidatingOnValidation 方法。我不知道为什么会这样,我也不在乎——我只想让它能工作 :) 因此,为此,我只需监听所有子控件的相应事件,并使用它们来调用父控件的适当方法。

我添加的一个让我感到自豪(而且后来发现有点棘手)的功能是处理向上和向下键的按下事件。根据文本框中的焦点位置,向上和向下键(以及向上和向下按钮)将按适当的顺序增加底层值。您在桌面框架中无法获得此功能,因为您必须提前指定增量。这是通过查找文本框中的选择开始位置,然后确定用于增加/减少底层值的应使用哪种类型的值来实现的。

private decimal GetFactor()
{
    int order = 0;
    string strValue = txt.Text;
    if (!string.IsNullOrEmpty(strValue)
        && (txt.SelectionStart > -1)
        /*&& (txt.SelectionLength > 0)*/)
    {
        int decimalIndex = strValue.IndexOf('.');
        if (decimalIndex == -1)
            decimalIndex = strValue.Length;

        if (decimalIndex > txt.SelectionStart)
            order = (decimalIndex - txt.SelectionStart) - 1;
        else
        {
            order = (decimalIndex - txt.SelectionStart);

            //should not be lower than the # of decimal places
            if ((-1 * order) > _decimalPlaces)
                order = (-1 * _decimalPlaces);
        }
    }

    return (decimal)Math.Pow(10.0, (double)order);
}

我用来保持底层值和可见值同步的机制是通过监听当前值的变化并更新视图来实现的,如下所示

string formatString = &quot;{0:F&quot; + _decimalPlaces + &quot;}&quot;;
txt.Text = String.Format(formatString, _value);

然后,通过这种方式解析输入的文本

decimal? value = null;

try
{
    value = decimal.Parse(txt.Text);
}
catch (Exception)
{ }

if (value.HasValue)
{
    Value = value.Value;
}
else
{
    //overright value
    OnPropertyChanged(NumericUpDownProperties.Value);
}

也就是说,输入的文本只有在有效时才会更新底层值,否则,我们只会刷新之前的值。

最后,我想提一下,数字控件实现了 INotifyPropertyChanged 接口——因此您可以像使用任何内置的 MSFT Forms 控件一样,将其用于数据绑定。

未来

我目前不打算对这个控件做太多进一步的工作(例如,如果您要求更新,或者提供 VS2008 的特殊版本等,我可能无法及时完成——至少不会很快)。我写这篇文章的主要动机是把这个控件放到网上,或许有人能从中获益。如果您对这个贡献有任何建设性的意见(例如,关于要添加的功能的建议,或者改进代码可读性的方法等),我将洗耳恭听。

首先,有一个方面可以改进,那就是找到一种方法让向上和向下按钮看起来更好。标准的 .NET CF 按钮无法显示图像,所以我们只能使用能输入的字符。如果您试用演示版,您会看到,目前,向上和向下按钮分别由“/\”和“\/”字符串表示——在我的浏览器中看起来不算太糟,但在我的设备上看起来有点业余。总之,我对此持开放态度,欢迎提出建议。

历史

  • 5-20-2008
    • 添加了屏幕截图
    • 添加了更多代码片段
    • 添加了更多背景信息
    • 澄清了我对本文的未来参与度,以回应早期评论者的一些误解
  • 5-19-2008
    • 原文
© . All rights reserved.