LoginSignup
0
0

More than 3 years have passed since last update.

C# - NumericUpDownコントロールはHexadecimal=trueで使用するときはMaximumプロパティとMinimumプロパティをそれぞれInt32.MaxValueと.Int32.MinValueにする制約事項があるが、負数の表示がなぜかlong型になっている

Last updated at Posted at 2020-10-13

まえおき

追加調査した結果タイトルを見直しました。

旧タイトル:
C# - NumericUpDownコントロールはHexadecimal=trueで使用すると0x80000000が負になる(せっかくValueがDecimal型なのに入力値がInt32でConvertされる)

概要

NumericUpDownコントロールは下記のように、数値の入力をUp/Down操作するのに使いやすいコントロールです。

image.png

経緯

マイコンのシミュレータをフルスクラッチでつくろうというクレイジーなことをやり始めたときにはまった話。。

NumericUpDownコントロールはHexadecimaltrueにすると16進法で数値を表示できるのですが、32bit以上を扱おうとすると厄介な問題が発生しました。

Maximum0xFFFFFFFFとかにし、Minimumを0にして、スピン(?)(コントロールの右端の上下の▲のボタン)をいじってるときはよかったんですが、、

コントロールに直接FFFFFFFFとかを入力すると、0になるんですよ。。。 えっ???
ってなりましたが、さすがにもうこの手の現象には慣れてきて、どうせ内部でInt32に変換しているんだろうなと思ったら案の定でした。。。

内部コード

ILSpyで確認してみた。


/// <summary>スピン ボックス (アップダウン コントロール) に表示するテキストを数値に変換して評価します。</summary>
protected void ParseEditText()
{
    try
    {
        if (!string.IsNullOrEmpty(Text) && (Text.Length != 1 || !(Text == "-")))
        {
            if (Hexadecimal)
            {
                Value = Constrain(Convert.ToDecimal(Convert.ToInt32(Text, 16)));
            }
            else
            {
                Value = Constrain(decimal.Parse(Text, CultureInfo.CurrentCulture));
            }
        }
    }
    catch
    {
    }
    finally
    {
        base.UserEdit = false;
    }
}

ヤッパリネ。。なんでInt32やねん・・・。けちくさい・・・。

追調査

コメントを頂いて、Hexadecimaltrueに設定して使用した際の振る舞いとか、
今回やりたいこと(00xFFFFFFFF1(あえて型は問わず、16進数8桁を入力・設定できるユーザインタフェースをFormに置きたい。)ができないか追加で調べてみた。

そもそもドキュメントに制約が記載されている

しっかり制約事項が書かれていました。。。※日本語サイトのほうは訳が壊れていたので英語のほうを引用しています。
https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.numericupdown.hexadecimal?view=netcore-3.1#remarks

When the Hexadecimal property is set, the UpdateEditText method is called to update the spin box's display to the new format.
When the Hexadecimal property is set to true, the Maximum property should be set to Int32.MaxValue and the Minimum property should be set to Int32.MinValue.

ドキュメントの通り使ってみたら・・・


using System;
using System.Drawing;
using System.Windows.Forms;

class NudHexTest : Form
{
    NumericUpDown nud;

    NudHexTest()
    {
        Controls.Add(nud = new NumericUpDown(){
            Width = 180,
            Hexadecimal = true,
            Maximum =  Int32.MaxValue, //  0x7FFFFFFF
            Minimum =  Int32.MinValue, // -0x80000000
            Value   =  0
        });
        ClientSize = new Size(180, 100);
    }

    [STAThread]
    static void Main(string[] args)
    {
        Application.Run(new NudHexTest());
    }
}

image.png

▼を押したらFFFFFFFFが表示される(今回の使い方が一応実現できる)と思ったら、16桁になった。。

image.png

内部コード


public decimal Value
{
    get
    {
        if (base.UserEdit)
        {
            ValidateEditText();
        }
        return currentValue;
    }
    set
    {
        if (value != currentValue)
        {
            if (!initializing && (value < minimum || value > maximum))
            {
                throw new ArgumentOutOfRangeException("Value", SR.GetString("InvalidBoundArgument", "Value", value.ToString(CultureInfo.CurrentCulture), "'Minimum'", "'Maximum'"));
            }
            currentValue = value;
            OnValueChanged(EventArgs.Empty);
            currentValueChanged = true;
            UpdateEditText();
        }
    }
}


/// <summary>スピン ボックス (アップダウン コントロール) の現在の値を適切な形式で表示します。</summary>
protected override void UpdateEditText()
{
    if (!initializing)
    {
        if (base.UserEdit)
        {
            ParseEditText();
        }
        if (currentValueChanged || (!string.IsNullOrEmpty(Text) && (Text.Length != 1 || !(Text == "-"))))
        {
            currentValueChanged = false;
            base.ChangingText = true;
            Text = GetNumberText(currentValue);
        }
    }
}


private string GetNumberText(decimal num)
{
    if (Hexadecimal)
    {
        return ((long)num).ToString("X", CultureInfo.InvariantCulture);
    }
    return num.ToString((ThousandsSeparator ? "N" : "F") + DecimalPlaces.ToString(CultureInfo.CurrentCulture), CultureInfo.CurrentCulture);
}

なぜかこっちはlong (Int64)。。

参考

Decimal構造体 - Microsoft Docs


  1. もしくは0x80000000( $= -2^{31} = $Int32.MinValue)~0x7FFFFFFF($= 2^{31}-1=$ Int32.MaxValue

0
0
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0