【发布时间】:2015-07-14 18:39:46
【问题描述】:
我在表单上有一个 WPF 文本框,允许输入 URI。
我尝试使用数据转换器来做到这一点。问题是当文本框绑定更新并且文本框不包含有效的 URI 时,
- 数据转换器返回空值;
- 将我的模型属性设置为 null ;
- 这会导致属性更改事件触发;
- 将文本框的值设置为空字符串,清除用户的无效输入
我是 WPF 新手,我找不到使用不会导致这种行为的数据转换器的简单模式。我想必须有一个标准模式可以使用,如果我是一位经验丰富的 WPF 程序员,我会知道的。
查看 Prism 4 中包含的示例,似乎使用了两种不同的方法。我都不喜欢他们俩。
第一种方法是在我的模型属性设置为 null 时引发异常,这会被捕获并显示为验证错误。问题是我希望该属性能够设置为 null - 每次打开表单时,这些字段都设置为它们以前的值。如果应用程序以前从未运行过,则 URI 将设置为 null - 这不应引发异常。此外,使用异常进行验证也很丑陋。
第二种方法是当属性设置为 null 时,将模型的验证状态设置为包含属性无效,但不实际更新属性。我认为这很糟糕。导致模型内部不一致,声称DCSUri无效,但包含DCSUri之前的有效值。
我用来避免这些问题的方法是在我的 ViewModel 中有一个字符串 DCSUri,如果它是一个有效的 URI,它只会更新我的模型的 Uri 类型 DCSUri 属性。但我更喜欢一种允许使用转换器并将我的文本框直接绑定到我的模型的方法。
我的转换器代码:
/// <summary>
/// Converter from Uri to a string and vice versa.
/// </summary>
public class StringToUriConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
Uri uri = null;
string stringValue = value as string;
if (stringValue != null)
Uri.TryCreate(stringValue, UriKind.Absolute, out uri);
return uri;
}
}
文本框的 XAML:
<TextBox Grid.Row="1" Grid.Column="1" Name="DCSUriTextBox"
Text="{Binding Path=DCSLoadSettings.DCSUri, Mode=TwoWay, UpdateSourceTrigger=LostFocus, ValidatesOnExceptions=True, NotifyOnValidationError=True, ValidatesOnDataErrors=True, Converter={StaticResource StringToUriConverter} }"
HorizontalAlignment="Stretch" Height="Auto" VerticalAlignment="Center" Margin="5,0,20,0" IsReadOnly="{Binding Path=IsNotReady}" Grid.ColumnSpan="2" />
以及我模型中 DCSUri 属性的代码:
/// <summary>
/// The Uri of the DCS instance being provided configuration
/// </summary>
public Uri DCSUri
{
get
{
return mDCSUri;
}
set
{
if (!Equals(value, mDCSUri))
{
mDCSUri = value;
this["DCSUri"] = value == null
? "Must provide a Uri for the DCS instance being provided configuration"
: string.Empty;
RaisePropertyChanged(() => DCSUri);
}
}
}
【问题讨论】: