WPFヘルパー: NumericInput.cs – TextBoxを数値入力用にするAttached Property を提供するクラス

コンピュータ

NumericInput.cs

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

namespace Maywork.WPF.Helpers;

public static class NumericInput
{
    public static readonly DependencyProperty AllowDecimalProperty =
        DependencyProperty.RegisterAttached(
            "AllowDecimal",
            typeof(bool),
            typeof(NumericInput),
            new PropertyMetadata(false, OnChanged));

    public static readonly DependencyProperty AllowNegativeProperty =
        DependencyProperty.RegisterAttached(
            "AllowNegative",
            typeof(bool),
            typeof(NumericInput),
            new PropertyMetadata(false, OnChanged));

    public static void SetAllowDecimal(DependencyObject obj, bool value)
        => obj.SetValue(AllowDecimalProperty, value);

    public static bool GetAllowDecimal(DependencyObject obj)
        => (bool)obj.GetValue(AllowDecimalProperty);

    public static void SetAllowNegative(DependencyObject obj, bool value)
        => obj.SetValue(AllowNegativeProperty, value);

    public static bool GetAllowNegative(DependencyObject obj)
        => (bool)obj.GetValue(AllowNegativeProperty);

    static void OnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is not TextBox tb) return;

        tb.PreviewTextInput -= OnPreviewTextInput;
        tb.PreviewTextInput += OnPreviewTextInput;

        DataObject.RemovePastingHandler(tb, OnPaste);
        DataObject.AddPastingHandler(tb, OnPaste);
    }

    static void OnPreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        if (sender is not TextBox tb) return;

        bool allowDecimal = GetAllowDecimal(tb);
        bool allowNegative = GetAllowNegative(tb);

        string text = e.Text;

        if (char.IsDigit(text, 0))
            return;

        if (text == "." && allowDecimal && !tb.Text.Contains("."))
            return;

        if (text == "-" && allowNegative && tb.SelectionStart == 0 && !tb.Text.Contains("-"))
            return;

        e.Handled = true;
    }

    static void OnPaste(object sender, DataObjectPastingEventArgs e)
    {
        if (sender is not TextBox tb) return;

        if (!e.DataObject.GetDataPresent(typeof(string)))
        {
            e.CancelCommand();
            return;
        }

        string text = (string)e.DataObject.GetData(typeof(string));

        bool allowDecimal = GetAllowDecimal(tb);
        bool allowNegative = GetAllowNegative(tb);

        string pattern =
            allowDecimal
            ? (allowNegative ? @"^-?\d*(\.\d*)?$" : @"^\d*(\.\d*)?$")
            : (allowNegative ? @"^-?\d*$" : @"^\d*$");

        if (!System.Text.RegularExpressions.Regex.IsMatch(text, pattern))
            e.CancelCommand();
    }
}

/*
# 使い方

xmlns:h="clr-namespace:Maywork.WPF.Helpers"

XAML 整数
<TextBox
    TextAlignment="Right"
    h:NumericInput.AllowNegative="True"
    Height="32" Width="100" />

XAML 小数
<TextBox h:NumericInput.AllowDecimal="True"
         h:NumericInput.AllowNegative="True"/>
*/
Download

コメント