[英]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
中绑定到TextBox
的Amount
数据类型是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
中,绑定Amount
和AmountFormatter
转换器;
/** 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.