WPF值转换器 - 无法转换的值的标准返回结果

47

在过去的一年左右时间里,我看到了许多不同的值转换器,用于许多不同的目的,来自许多不同的作者。有一件事情让我印象深刻,那就是它们返回的“默认”值的差异非常大。例如:

  public class MyConverter: IValueConverter
  {
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      // OK, we test for some undesirable, unconvertable situation, typically null...
      if (value == null)
      {
        // And here are a variety of 'defaults' that I have seen, these begin the most typical.
        return null;
        return DependencyProperty.UnsetValue;
        return Binding.DoNothing;
      }
        //...... other code.. whatever...
}}

那么我的问题是,是否有一种“标准”方法来指示输入值无法转换?

6个回答

37
根据MSDN - IValueConverter的介绍:

数据绑定引擎不会捕获由用户提供的转换器抛出的异常。任何由Convert方法抛出的异常,或由Convert方法调用的方法抛出的未捕获异常,都将被视为运行时错误。通过返回DependencyProperty.UnsetValue来处理预期问题。

关键的一句话是通过返回DependencyProperty.UnsetValue来处理预期问题。

4
DependencyProperty.UnsetValueBinding.DoNothing 之间的实际差别是什么?文档在这里并不是非常清楚。在这两种情况下,绑定引擎的行为有何不同? - bitbonk
8
请看这个回答:https://dev59.com/SWPVa4cB1Zd3GeqP4Uob#10385121 ... 基本上,Binding.DoNothing 会使绑定引擎立即停止,而 DependencyProperty.UnsetValue 则告诉绑定引擎使用 FallbackValue。 - myermian

25

当你查询这些值时,你会发现它们的含义。然后选择正确的值在你的转换器中返回。

主要问题是 null 可能是属性的有效值。

DependencyProperty.UnsetValue 表示属性存在但未被属性系统设置其值。

Binding.DoNothing 指示绑定引擎不将值传输到绑定目标,不移动到 PriorityBinding 中的下一个 Binding,也不使用 FallBackValue 或默认值。

编辑

如果你不能转换该值,应该简单地返回给定的值来指示此情况。这是最好的做法,因为它将问题返回给绑定的作者。如果你操纵了值,那么很难找出发生了什么。


好的,这很有道理。我猜在许多情况下,这将成为一个例外。你认为在转换器本身内部抛出异常会是一个更好的方法吗? - A.R.
不要打破绑定。请参见:https://dev59.com/l0zSa4cB1Zd3GeqPn5it和https://dev59.com/3lTTa4cB1Zd3GeqPpyl5。 - Emond
好的,看起来共识是返回DependencyProperty.UnsetValue。 - A.R.
这确实是UnsetValue的一个缺点,但返回它将允许在绑定上使用'FallbackValue',使最终用户决定“默认值”应该是什么。此外,还有一些特殊情况下该值是有用的:http://msdn.microsoft.com/en-us/library/ms745795.aspx#Advanced。归根结底,我正在努力为我的组织制定一个合理且灵活的标准。 - A.R.
2
如果返回 DependencyProperty.UnsetValue,可以将+1分配给您。这样做,WPF会显示验证错误,并显示错误消息“无法转换值'...'”。这正是我要寻找的。尽管当您仅返回未转换的值时,WPF的行为相同。 - jeyk

5
经过深思熟虑和搜索,似乎DependencyProperty.UnsetValue是合适的选择。我已经成功地将所有内部内容移至此模式。此外,在此页面的“备注”部分中的文本表明,这可能是最佳选择。
还有一些关于在无法转换绑定时返回输入值的讨论,但这很容易“破坏”绑定系统。想象一种情况,绑定输入是“string”,输出是“brush”。返回字符串是行不通的!

+1。根据文档,返回DependencyProperty.UnsetValue是正确的选择。 - jeyk

2

默认情况下返回的内容取决于具体情况。例如,你不希望在将int转换为bool时返回int作为默认值,也不希望在将可见性枚举转换器中返回bool。


0

通常情况下,如果一个值无法转换,我会抛出一个 异常

这是因为如果我正在使用无效的转换器尝试转换一个值,我希望被警告,以便我可以修改我的代码。

在一些罕见的情况下,一个值可能是有效的,即使它无法转换,在这种情况下,我通常返回传递给转换器的相同值。只有当我希望在可能的情况下转换值或不转换时才使用此选项。

另一种我偶尔会采用的罕见情况是硬编码默认值。这通常是在我知道转换器可能与无效参数一起使用,并且我希望无论结果如何都返回有效值时执行的。我的硬编码默认转换器几乎总是返回布尔值。

我不认为我曾经返回过你指定的这3个值之一(nullDependencyProperty.UnsetValueBinding.DoNothing),因为这些值经常是意外的,并且除非你专门查找它们,否则很难注意到。


2
是的,也许吧,但我认为大多数社群都同意打破绑定系统(通过抛出异常)是错误的做法。当我采用这种方法时,我的设计师已经崩溃了大约一千次,或者直接运行时崩溃,这更糟糕... - A.R.

-4

你也可以使用这个函数返回一个真正的targetType默认对象:

public static object GetDefault(Type type)
{
   if(type.IsValueType)
   {
      return Activator.CreateInstance(type);
   }
   return null;
}

来源:C# - 编程等效于 default(Type)


5
这很糟糕:它会掩盖问题。 - Emond

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接