我的WPF应用程序有一个对话框,用户可以在其中输入纬度&一个经度。我已经编写了一个IValueConverter
,它可以处理以十进制度或度-分-秒格式输入的值:
[ValueConversion( typeof( double? ), typeof( string ) )]
public class CoordinateConverter : IValueConverter {
#region IValueConverter Members
public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) {
double angle = 0.0;
if ( value is string ) {
if ( !double.TryParse( value as string, NumberStyles.Float, CultureInfo.InvariantCulture, out angle ) ) {
return value;
}
} else if ( value is double || value is double? ) {
angle = (double) value;
} else {
return value.ToString();
}
bool isNegative = angle < 0;
if ( isNegative ) angle = -angle;
double degrees = Math.Truncate( angle );
double remainder = ( angle - degrees ) * 60.0;
double minutes = Math.Truncate( remainder );
double seconds = ( remainder - minutes ) * 60.0;
string result = degrees.ToString( "##0", culture.NumberFormat ) + "° " +
minutes.ToString( "#0", culture.NumberFormat ) + "' " +
seconds.ToString( "#0.00", culture.NumberFormat ) + "" ";
// The parameter contains "NS" for Latitudes and "EW" for Longitudes.
if ( parameter != null ) {
result += ( (string) parameter ).Substring( ( isNegative ? 1 : 0 ), 1 );
} else {
result = ( isNegative ? "-" : string.Empty ) + result;
}
return result;
}
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) {
string strValue = value as string;
if ( string.IsNullOrEmpty( strValue ) ) {
return null;
}
double adjustForSign = 1.0;
if ( strValue.IndexOf( "-" ) >= 0 ) {
adjustForSign = -1.0;
strValue = strValue.Substring( strValue.IndexOf( "-" ) + 1 );
}
// Parse the value in the field. It's in three parts: Degrees, minutes & seconds
int degreeSymbol = strValue.IndexOf( "°" );
int minuteSymbol = strValue.IndexOf( "'" );
int secondSymbol = strValue.IndexOf( '"' );
string degrees = null, minutes = null, seconds = null;
double angle, d, m, s;
if ( degreeSymbol < 0 ) {
if ( double.TryParse( strValue, NumberStyles.Number, culture.NumberFormat, out angle ) ) {
return angle;
} else {
return value;
}
} else {
degrees = strValue.Substring( 0, degreeSymbol );
if ( minuteSymbol >= 0 ) {
minutes = strValue.Substring( degreeSymbol + 2, minuteSymbol - degreeSymbol - 2 );
}
if ( secondSymbol < 0 ) {
seconds = "0" + culture.NumberFormat.NumberDecimalSeparator + "0";
} else {
seconds = strValue.Substring( minuteSymbol + 2, secondSymbol - minuteSymbol - 2 );
}
}
if ( !double.TryParse( degrees, NumberStyles.Integer, culture.NumberFormat, out d ) ) return value;
if ( !double.TryParse( minutes, NumberStyles.Integer, culture.NumberFormat, out m ) ) return value;
if ( !double.TryParse( seconds, NumberStyles.Float , culture.NumberFormat, out s ) ) return value;
angle = d + m / 60.0 + s / 3600.0;
if ( parameter != null ) {
if ( strValue.Contains( ( (string) parameter ).Substring( 1, 1 ) ) ) {
angle = -angle;
}
} else {
angle *= adjustForSign;
}
return angle;
}
在对话框中,我使用这个ControlTemplate
来显示错误:
<ControlTemplate x:Key="InputErrorTemplate">
<DockPanel LastChildFill="True">
<Image DockPanel.Dock="Right"
Height="20"
Margin="-30,0,0,0"
Source="{StaticResource ErrorImage}"
ToolTip="{x:Static res:Car.Common_InvalidData}"
VerticalAlignment="Center"
Width="20" />
<Border BorderBrush="Red"
BorderThickness="5"
Margin="5,0,30,0">
<AdornedElementPlaceholder />
</Border>
</DockPanel>
</ControlTemplate>
如果其中一个TextBoxes
中有一个字符串,它不会解析,不会抛出异常,并且显示我的对话框的错误模板。当我将鼠标悬停在TextBox
上时,显示的错误信息是"输入字符串格式不正确"
我有几个问题:
- 错误信息来自哪里?它不在我的代码中,如果转换器抛出异常,程序就会因为未处理而死亡。
- 最后,如果无法解析
TextBox
中的值,我想显示一个错误。对话框的视图模型对象确实实现了IDataErrorInfo
,但从字符串到双精度的转换不是由该对象完成的。我该怎么做呢?
由于文本框可能在代码隐藏中绑定到双属性,我认为有一些聪明的预转换验证,它给出了您看到的验证错误。要控制验证过程,我认为有几种方法:
- 您可以创建自己的验证规则
- 你可以从转换器返回一个验证结果(尽管在IMO验证和转换似乎并不属于一起)
- 你可以利用IDataError接口和MVVM
这里有几个链接,提供了一些很好的信息:
- 使用ViewModel提供有意义的验证错误消息
- WPF中的数据验证 在WPF中使用自定义验证规则
还有一件事,当将输入转换为double类型时,是否有特殊的原因使用不变区域性而不是作为参数传递的区域性?它可能在非英语文化(例如丹麦语)中失败,其中小数分隔符是逗号(相当于英语文化中的千位分隔符)。
在玩了一段时间后,我发现绑定似乎试图根据数据流动的方向将Convert
或ConvertBack
方法返回的任何值转换为正确的类型。如果不能将值转换为该类型,则会将"输入字符串格式不正确"消息添加到该控件的错误集合中。如果我的代码只返回原始值不变如果有问题,我最终会得到那个消息。
这个消息已经足够好了,至少现在是这样。如果我想要一个不同的消息,我将不得不研究创建一个验证规则或一些其他机制。