繁体   English   中英

c# wpf xaml using StringFormat without or with CUSTOM错误消息

[英]c# wpf xaml using StringFormat without or with CUSTOM error message

在我的文本框中,我有;

Text="{Binding Amount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat={}{0:N2}}"

绑定数据是十进制的,而文本框格式应该是1,000.00

我唯一担心的是,当 TextBox 为空时,或者如果我删除了该值,那么文本框的边框会变红,并且会在文本框下方收到Value * could not be converted convert 的错误消息,这是使用StringFormat造成的.

现在,我真的不在乎该值是否为空,因为在我的数据库中,默认值为零,我接受一个空值,而且文本框只接受数字。

我想知道的是如何禁用此验证但仍然能够使用 StringFormat? 其次,以防万一将来我想使用相同的行为,如何将默认错误消息更改为其他内容?

编辑:按照建议,我尝试使用绑定转换器和 DataTrigger 来应用 StringFormat,但我仍然收到错误消息。

使用绑定转换器

//AmountFormatter.class
public class AmountFormatter : IValueConverter{
    public object? Convert(object value, Type targetType, object parameter, CultureInfo culture){
        decimal amount = (decimal.TryParse(value.ToString(), out decimal n)) ? n : 0; // if it failed to convert into decimal, meaning wrong value, then set default value as 0.
        return (amount>0)?string.Format(culture, "{0:N2}", amount):null; //return null, empty if value is less than 1. Maybe the user wants to type new value, so leave the textbox empty.
    }

    public object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){
        return null;
    }
}

//xaml layout
<DataTemplate>
    <DockPanel LastChildFill="True">
        <TextBox x:Name="TextBoxAmount" Text="{Binding Amount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource AmountFormatter}}" />
    </DockPanel>
</DataTemplate>

//App.xaml
<converters:DecimalOnly x:Key="AmountFormatter" />

使用 DataTrigger 应用 StringFormat

//AmountFormatter.class
public class AmountFormatter : IValueConverter{
    public object? Convert(object value, Type targetType, object parameter, CultureInfo culture){
        decimal amount = (decimal.TryParse(value.ToString(), out decimal n)) ? n : 0; // if it failed to convert into decimal, meaning wrong value, then set default value as 0.
        return (amount>0) //return true or false if amount is greather than zero. Maybe the user wants to type new value, so leave the textbox empty.
    }

    public object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){
        return null;
    }
}

//xaml layout
<DataTemplate>
    <DockPanel LastChildFill="True">
        <TextBox x:Name="TextBoxAmount" />
    </DockPanel>
    <DataTemplate.Triggers>
        <!-- StringFormat when value is greather than 0 -->
        <DataTrigger Binding="{Binding Path=Amount, Converter={StaticResource AmountFormatter}}" Value="true">
            <Setter TargetName="TextBoxAmount" Property="Text" Value="{Binding Amount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat={}{0:N2}}" /> 
        </DataTrigger>
        <!-- Otherwise, no StringFormat -->
        <DataTrigger Binding="{Binding Path=Amount, Converter={StaticResource AmountFormatter}}" Value="false">
            <Setter TargetName="TextBoxAmount" Property="Text" Value="{Binding Amount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

//App.xaml
<converters:DecimalOnly x:Key="AmountFormatter" />

事实证明,验证错误消息不是由使用StringFormat引起的。

我的ViewModel中绑定到TextBoxAmount数据类型是Decimal

TextBox中没有值时会发生什么, UpdateSourceTrigger=PropertyChanged正在被触发。 但由于它是空的,它无法将值转换为我想要的格式。 结果,我的 TextBox 的边框变为红色,并在其下方显示一条错误消息value * cannot be converted 我不知道这是否是事实,但我认为这是绑定数据时的一种功能。

我的解决方案来自Mark Feldman的代码段。

首先,在我的ViewModel中,将Amount的数据类型从Decimal更改为String

/** MyViewModel Class **/
public class MyViewModel{
    ...
    public string? Amount { get; set; } //instead of decimal, I used string. This is the one that is causing the validation error/message when no value in the textbox.
}

接下来是创建一个IValueConverter类,我将其命名为AmountFormatter.class 这将是在键入时处理格式的类。

/** AmountFormatter.class **/
// (1) convert the value of the textbox which is string into decimal.
//       //a succesfull convert, meaning the value is valid and in correct format.       
// (2) format the decimal into {0:N2}
public class AmountFormatter : IValueConverter{
    public object? Convert(object value, Type targetType, object parameter, CultureInfo culture){
        decimal amount = (decimal.TryParse(value.ToString(), out decimal n)) ? n : 0; // if it failed to convert into decimal, meaning wrong value, then set default value as 0.
        return (amount>0)?string.Format(culture, "{0:N2}", amount):""; //return "" (empty string) if value is less than 1. Maybe the user wants to type new value, so leave the textbox empty.
    }

    public object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){
        if ((value==null) || (string.IsNullOrEmpty(value.ToString()))) return ""; // returning empty string will also trigger the `updatesourcetrigger`.
        return (decimal.TryParse(value.ToString(), out decimal n)) ? n : ""; 
    }
}

然后将AmountFormatter.class声明到我的App.xaml中。

<Application
    x:Class="MyApp.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:converters="clr-namespace:MyApp.Converters"
    xmlns:local="clr-namespace:MyApp"
    StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                ....
            </ResourceDictionary.MergedDictionaries>
                ...
            <converters:AmountFormatter x:Key="AmountFormatter" />
        </ResourceDictionary>
    </Application.Resources>
</Application>

之后,在包含我的 TextBox 的xaml layout中,绑定AmountAmountFormatter转换器;

/** xaml layout **/
<DataTemplate>
    <DockPanel LastChildFill="True">
        <TextBox 
            x:Name="TextBoxAmount" 
            DataObject.Pasting="TextBoxAmount_Paste"
            PreviewKeyDown="TextBoxAmount_PreviewKeyDown"
            PreviewTextInput="TextBoxAmount_PreviewTextInput"
            Text="{Binding Amount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource AmountFormatter}}" />
    </DockPanel>
</DataTemplate>

还有中提琴!

杂项;

Textbox用于货币,我想将其格式化为用户在TextBox上键入的内容。 为了确保用户输入正确的输入,我将文本框限制为仅正数,不允许有空格,一个小数点,只有两个小数位。 除非数据格式正确,否则我也不允许复制粘贴。

在我的xaml layout class中,我有以下内容;

/** xaml layout class **/
//handle the pasting event, if the copied data failed to convert into decimal, then the format is invalid and do not allow to paste it.
private void TextBoxAmount_Paste(object sender, DataObjectPastingEventArgs e){
    if (e.DataObject.GetDataPresent(typeof(String))){
        if (!decimal.TryParse((String)e.DataObject.GetData(typeof(String)), out _)) e.CancelCommand();
    } else {
        e.CancelCommand();
    }
}

//prevent from using space
private void TextBoxAmount_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e){
    e.Handled = (e.Key == Key.Space); //do not allow spacing
}

//accept only numbers, single decimal, and two decimal places.
private void TextBoxAmount_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e){
    TextBox tb = (TextBox)sender;
    char ch = e.Text[0];
    if (!Char.IsDigit(ch) && (ch!='.')) e.Handled = true;
    if ((ch == '.') && tb.Text.IndexOf('.') > -1) e.Handled = true;
}

我希望这种方法没有错误。

这能解决你的问题吗?

转换器:

using System;
using System.Globalization;
using System.Windows.Data;

internal class DecimalConverter : IValueConverter

{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
            return "";
        return ((Decimal)value).ToString("0.00");
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        try
        {
            if ((value == null) || (value.ToString() == ""))
                return Binding.DoNothing;
            return Decimal.Parse(value.ToString());
        }
        catch
        {
            return null;
        }
    }
}

用法:

<TextBox>
    <TextBox.Text>
        <Binding Path="Amount" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" StringFormat="{}{0:N2}">
            <Binding.Converter>
                <local:DecimalConverter />
            </Binding.Converter>
        </Binding>
    </TextBox.Text>
</TextBox>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM