WPF 数字格式

本文关键字:格式 数字 WPF | 更新日期: 2023-09-27 18:33:08

我有这个 XAML 用于列到 DataGrid 中

<DataGridTemplateColumn Header="% Deduccion Anticipo">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding NumPorcentajeAnticipo, Mode=TwoWay, StringFormat={}{0:00.}%}" Visibility="{Binding Merlin_ConceptosFacturacion.BitOtrosItms_Anticipos,Converter={StaticResource boolToVisibility}}"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <TextBox Text="{Binding NumPorcentajeAnticipo, Mode=TwoWay,StringFormat={}{0:00.}%}" Visibility="{Binding Merlin_ConceptosFacturacion.BitOtrosItms_Anticipos,Converter={StaticResource boolToVisibility}}"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

字符串格式如我预期的那样适用,但 muy 问题是用户可以用任何字符阿尔法、数字符号填充它,我该怎么做才能防止它,可以设置一个输入掩码?

我正在尝试使用另一种字符串格式,但其中任何一个都按我的预期工作。

更新:该列当前绑定到我的视图模型的 Numeric 属性。

WPF 数字格式

可以使用 TextBox 的 KeyDown 事件来截获和筛选出无效值。您甚至可以创建自己的派生TextBox并覆盖OnKeyDown以获得更好的封装解决方案。

所有内置控件都无法指定输入掩码。 但是,互联网上有用于 WPF 的屏蔽输入控件。 我们正在使用 WPF 包的 Telerik Rad 控件,它有这样的控件。 我在我的应用程序中使用它,它运行良好。

您可以使用以下方法实现您的要求。

  1. 将蒙版文本框放在单元格编辑模板中,并在该蒙版文本框中设置蒙版。
  2. 根据您的要求创建自定义渲染并绑定到单元格编辑模板。

经过一些研究,在另一个问题上发现了这一点:

WPF 中的数字数据输入 和 @Brian 欣奇的答案符合我的一些需求。

只需自己添加一些十进制数字的文化验证以及一些编辑和验证工具即可。希望这对其他人有所帮助。

要使用它:

<DataGridTemplateColumn.CellEditingTemplate>
   <DataTemplate>
      <controls:NumericTextBox DecimalPlaces="2" DecimalSeparator="."/>
   </DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>

如果没有提供小数位或分隔符,则需要CultureInfo.CurrentCulture

这是最终代码:

public class NumericTextBox : TextBox
{
    #region Formato
    private string previousText = "";
    private bool ApplyingFormat = false;
    private CultureInfo _CI = new CultureInfo(CultureInfo.CurrentCulture.LCID,true);
    public CultureInfo CI
    {
        get { return _CI; }
        set { _CI = value; }
    }
    private int _DecimalPlaces = 0;
    /// <summary>
    /// Numero de plazas decimales 
    /// </summary>
    public int DecimalPlaces
    {
        get { return _DecimalPlaces; }
        set { _DecimalPlaces = value; _CI.NumberFormat.NumberDecimalDigits = value; }
    }
    public Decimal DecimalValue = 0;
    private string _DecimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
    public string DecimalSeparator
    {
        get { return _DecimalSeparator; }
        set { _DecimalSeparator = value; _CI.NumberFormat.NumberDecimalSeparator = _DecimalSeparator; }
    }
    //public string DecimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
    #endregion 

    public NumericTextBox()
    {
        HorizontalContentAlignment = HorizontalAlignment.Right;
        DataObject.AddPastingHandler(this, OnPaste);
    }
    private void OnPaste(object sender, DataObjectPastingEventArgs dataObjectPastingEventArgs)
    {
        var isText = dataObjectPastingEventArgs.SourceDataObject.GetDataPresent(System.Windows.DataFormats.Text, true);
        if (isText)
        {
            var text = dataObjectPastingEventArgs.SourceDataObject.GetData(DataFormats.Text) as string;
            if (IsTextValid(text))
            {
                return;
            }
        }
        dataObjectPastingEventArgs.CancelCommand();
    }
    private bool IsTextValid(string enteredText)
    {
        //  If keyboard insert key is in toggled mode, and the actual insert point is Decimalseparator, we must avoid to overwrite it
        if (SelectionStart == this.Text.IndexOf(DecimalSeparator)
            & System.Windows.Input.Keyboard.GetKeyStates(System.Windows.Input.Key.Insert) == System.Windows.Input.KeyStates.Toggled)
        {
            SelectionStart += 1;
        }
        if (!enteredText.All(c => Char.IsNumber(c) || c == DecimalSeparator.ToCharArray()[0] || c == '-'))
        {
            return false;
        }
        //We only validation against unselected text since the selected text will be replaced by the entered text
        var unselectedText = this.Text.Remove(SelectionStart, SelectionLength);
        if ( enteredText == DecimalSeparator && unselectedText.Contains(DecimalSeparator))
        {
            //  Before return false, must move cursor beside Decimal separator
            SelectionStart = this.Text.IndexOf(DecimalSeparator) + 1;
            return false;
        }
        if (enteredText == "-" && unselectedText.Length > 0)
        {
            return false;
        }
        return true;
    }
    private bool ApplyFormat(TextChangedEventArgs e)
    {
        if (!ApplyingFormat)
        {
            ApplyingFormat = true;
            int SelectionStartActual = SelectionStart;
            string FinallText = this.Text;
            if (!FinallText.Contains(DecimalSeparator) & DecimalPlaces > 0)
            {
                FinallText = String.Format("{0}{1}{2}", this.Text, DecimalSeparator, new string('0', DecimalPlaces));
            }
            bool state = Decimal.TryParse(FinallText, NumberStyles.AllowCurrencySymbol | NumberStyles.AllowDecimalPoint | NumberStyles.AllowTrailingSign, _CI, out DecimalValue);
            DecimalValue = Math.Round(DecimalValue, DecimalPlaces);
            if (DecimalValue == 0)
            {
                FinallText = "";
            }
            else
            {
                if (FinallText != DecimalValue.ToString(_CI))
                {
                    FinallText = DecimalValue.ToString(_CI);
                }
            }
            if (FinallText != this.Text)
            {
                this.Text = FinallText;
                SelectionStart = SelectionStartActual;
            }
            previousText = this.Text;
            ApplyingFormat = false;
            return state;
        }
        else
        {
            return true;
        }
    }
    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        e.Handled = !ApplyFormat(e);
        base.OnTextChanged(e);
    }
    protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)
    {
        e.Handled = !IsTextValid(e.Text);
        base.OnPreviewTextInput(e);
    }
}