午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

WPFで数字とハイフンとピリオドだけ入力できるテキストボックス、-0.0に意味はある?

f:id:gogowaten:20200619131529g:plain
数字入力用テキストボックス

入力できるのは0から9までの数字とハイフン"-"とピリオド"."
ハイフンが入力できる場所は先頭だけ

github.com

MainWindow.xaml

<Window x:Class="_20200618_数値入力用TextBox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:_20200618_数値入力用TextBox"
        mc:Ignorable="d"
        Title="MainWindow" Height="150" Width="400"
        Name="MyWindow">
  <Grid>
    <Viewbox Margin="10">
      <StackPanel Width="200">
        <TextBox x:Name="MyTextBox" TextAlignment="Center" Margin="5"
                 InputMethod.IsInputMethodSuspended="True"
                 PreviewKeyDown="MyTextBox_PreviewKeyDown"
                 PreviewTextInput="MyTextBox_PreviewTextInput"
                 LostFocus="MyTextBox_LostFocus"
                 CommandManager.PreviewExecuted="MyTextBox_PreviewExecuted"/>
        <TextBox TextAlignment="Center" Margin="5"/>
      </StackPanel>
    </Viewbox>
  </Grid>
</Window>


MainWindow.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

//        Visual Studio / WPF > link > TextBoxに数値しか入力できなくする > PreviewTextInput使用 | e.Handled = true; - Qiita
//https://qiita.com/7of9/items/04793406f94d229a6c4d
//          C# WPF 数値のみ入力できるTextBoxを作る - 備忘録
//https://kagasu.hatenablog.com/entry/2017/02/14/155824
//            TextBoxに数値のみを入力する[C# WPF]
//https://vdlz.xyz/Csharp/WPF/Control/EditableControl/TextBox/TextBoxNumberOnly.html
//            [Tips][TextBox] キャレットの位置を取得する | HIROs.NET Blog
//https://blog.hiros-dot.net/?p=1594
//          テキストボックスのIME制御 - WPF覚え書き
//https://sites.google.com/site/wpfjueeshuki/tekisutobokkusunoime-zhi-yu
//          正規表現を使って文字列を置換するには?[C#/VB]:.NET TIPS - @IT
//https://www.atmarkit.co.jp/ait/articles/1702/08/news023.html



namespace _20200618_数値入力用TextBox
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }


        private void MyTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            var textbox = (TextBox)sender;
            string str = textbox.Text;//文字列
            var inputStr = e.Text;//入力された文字

            //正規表現で入力文字の判定、数字とピリオド、ハイフンならtrue
            bool neko = new System.Text.RegularExpressions.Regex("[0-9.-]").IsMatch(inputStr);

            //入力文字が数値とピリオド、ハイフン以外だったら無効
            if (neko == false)
            {
                e.Handled = true;//無効
                return;//終了
            }

            //キャレット(カーソル)位置が先頭(0)じゃないときの、ハイフン入力は無効
            if (textbox.CaretIndex != 0 && inputStr == "-") { e.Handled = true; return; }

            //2つ目のハイフン入力は無効(全選択時なら許可)
            if (textbox.SelectedText != str)
            {
                if (str.Contains("-") && inputStr == "-") { e.Handled = true; return; }
            }

            //2つ目のピリオド入力は無効
            if (str.Contains(".") && inputStr == ".") { e.Handled = true; return; }
        }

        private void MyTextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            //ピリオドの削除
            //先頭か末尾にあった場合は削除
            var tb = (TextBox)sender;
            string text = tb.Text;
            if (text.StartsWith('.') || text.EndsWith('.'))
            {
                text = text.Replace(".", "");
            }

            // -. も変なのでピリオドだけ削除
            text = text.Replace("-.", "-");

            //数値がないのにハイフンやピリオドがあった場合は削除
            if (text == "-" || text == ".")
                text = "";

            tb.Text = text;
        }

        private void MyTextBox_PreviewExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            //貼り付け無効
            if (e.Command == ApplicationCommands.Paste)
            {
                e.Handled = true;
            }
        }

        //スペースキーが押されたときは、それを無効にする
        private void MyTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Space) e.Handled = true;
        }
    }
}


        <TextBox x:Name="MyTextBox" TextAlignment="Center" Margin="5"
                 InputMethod.IsInputMethodSuspended="True"
                 PreviewKeyDown="MyTextBox_PreviewKeyDown"
                 PreviewTextInput="MyTextBox_PreviewTextInput"
                 LostFocus="MyTextBox_LostFocus"
                 CommandManager.PreviewExecuted="MyTextBox_PreviewExecuted"/>

IMEを休止状態にする
InputMethod.IsInputMethodSuspended="True"
Trueを指定したテキストボックスではIMEの状態に関わらず、半角英数字だけの入力になる

スペースキーが押されたときは無効にする
PreviewKeyDown="MyTextBox_PreviewKeyDown"
f:id:gogowaten:20200619214650p:plain
PreviewKeyDownイベント時に阻止
本当はこのあとのPreviewTextInputイベントで、入力された文字で検出したかったけど、スペースだけは方法がわからなかったのでキー入力で対処した

キー入力のPreviewTextInputイベントのときに入力文字の制限
PreviewTextInput="MyTextBox_PreviewTextInput"
f:id:gogowaten:20200619134739p:plain
入力文字の制限とハイフンの入力位置、2つ目のハイフンとピリオドの制限をしている
制限に引っかかったらイベントのHandledにtrueを指定してイベントをスルー
ここまでだと
.123
123.
-.123
-
.
とかの不自然なのも入力できてしまうので、これは
フォーカスを失ったときのLostFocusイベントで対処

LostFocus="MyTextBox_LostFocus"
f:id:gogowaten:20200619135935p:plain
StringのReplaceメソッドで地道に削除している

貼り付け無効
CommandManager.PreviewExecutedイベント時に対処
CommandManager.PreviewExecuted="MyTextBox_PreviewExecuted"
f:id:gogowaten:20200619140437p:plain

これで完成

0の表示
0埋め
000987
これはいい

小数点以下の連続0
3.000
これも正確さを表すから、これもわかる

負数を0埋め
-00987
多少不自然な気もするけど、気のせいだと思う

負の0
-0
-00.00
これらも入力できるんだけど意味あるのかなあってググったら

ja.wikipedia.org
難しいこと書いてあるけど、場合によっては意味があるみたい

じゃあC#の場合はどうなのか
f:id:gogowaten:20200619143406p:plain
0.0と-0.0
==やEqualsでの判定だとtrueになるけど
1.0 / 0.0 = infinity
1.0 / -0.0 = -infinity
割り算だと違う結果になった
それよりも0.0での割り算でエラーにならないのに驚いたわ、0だと赤波線でのエラー表示になる
-0.0をdouble.Parseで数値に変換すると0になるけど、内部的には-0.0のままみたい(36と44行目)
ってことで意味はあるけど、普通に使う分には変わんないかな



参照したところ

Visual Studio / WPF > link > TextBoxに数値しか入力できなくする > PreviewTextInput使用 | e.Handled = true; - Qiita

qiita.com

C# WPF 数値のみ入力できるTextBoxを作る - 備忘録 kagasu.hatenablog.com

TextBoxに数値のみを入力する[C# WPF] vdlz.xyz

[Tips][TextBox] キャレットの位置を取得する | HIROs.NET Blog blog.hiros-dot.net

テキストボックスのIME制御 - WPF覚え書き sites.google.com

正規表現を使って文字列を置換するには?[C#VB]:.NET TIPS - @IT www.atmarkit.co.jp




関連記事
次のWPF記事は翌日

gogowaten.hatenablog.com

前回のWPF記事は20日
gogowaten.hatenablog.com

今回のを利用したのが明後日
gogowaten.hatenablog.com