Silverlight多值绑定解决方案

在开发Silverlight应用程序时,经常会遇到需要根据多个输入来获取单个结果的情况。在WPF中,这可以通过MultiValueConverter实现,但在Silverlight中,这个特性是缺失的。本文将介绍三种解决方案,从快速脏办法到类似WPF的实现。

在将WPF应用程序移植到Silverlight时,遇到了这个“缺失特性”的问题,因为Silverlight只是WPF的一个子集。像其他软件开发者一样,首先在Google上搜索了这个问题。在考察了建议的方法后,得出了以下结论:

一些解决方案过于复杂,不符合“口味”。这些解决方案并不像希望的那样健壮。例如:

  • 缺乏对DependencyObject多绑定的支持(只有FrameworkElement)
  • 在Binding中缺乏RelativeSource
  • 实现方式与WPF的基础方式相去甚远(在某些情况下显得笨拙),这使得移植到Silverlight变得混乱。

因此,决定尝试用自己的方式解决这个问题。一些“提示”引导找到了解决方案:

  • MS在所有Silverlight版本中都排除了这个特性,可能有两个原因:
  • MS对开发者的需求漠不关心...
  • MS“认为”这个特性使用标准可用工具相对容易实现。

认为对于遇到的任何算法问题,都有一个简单、优雅、快速的解决方案,只需要找到它...所以把第二个原因当作“真正的”原因。

思考多绑定的核心功能应该会让人想到:

  • 哪个标准Silverlight特性具有监控和响应属性变化的“能力”?是的,DependencyProperty!以及它的变体AttachedProperty。

Silverlight 5.0中引入的新特性:

  • RelativeSource with AncestorType MarkupExtension(简称-'auto'实例化对象(在XAML中)具有返回值)。

有了这些“提示”,提出了三种解决方案:

快速脏办法

如果只关心多绑定功能,可以采用这种方法:

  • 构建一个具有与输入绑定相匹配的AttachedProperties的“专业化”类(甚至可以给这些属性有意义的名称)。
  • 将任何这些AttachedProperties的变化转发到一个单一的'Any...Changed'子程序上,将做两件事:
  • 执行期望的多绑定逻辑。
  • 更新“结果属性”。

部分优雅

作为最佳实践,最好将多绑定分离到单独的任务中:

  • 多输入绑定通用“引擎”(用于XAML)
  • 多值合一逻辑(通常作为IMultiValueConverter的实现)。

考虑到这一点,可以创建一个基于AttachedProperty的类(称为MultiBindingUtil),它将有任意数量的Attached Properties用于输入绑定(称为Binding1到Binding(n)),AttachedProperty用于Converter,最后,一个AttachedProperty用于结果(在示例中称为MBResult)。现在在XAML中所要做的就是将输入绑定AttachedProperties绑定到喜欢的任何东西上,提供一个转换器,并将MBResult绑定回希望被多绑定改变的属性。

在多绑定“引擎”内部,就像前一个示例一样,将任何输入绑定变化转发到一个单一的'Any...Changed'子程序中;只是在那里,将使用类绑定作为输入,更新MBResult属性与提供的转换器的转换结果。

一切都很好,除了在Silverlight中绑定元素属性到其自己的附加属性时,会出现一个众所周知的设计时错误。这个错误以非常微妙和有信息量的方式表现出来:

  • 找不到任何解决方案来修复这个“本地路径”问题。如果知道如何修复它,请分享。

类似WPF的解决方案

这种解决方案在移植时可能很有帮助,因为它非常接近WPF的XAML外观。此外,它利用了Silverlight 5.0的新MarkupExtension支持和前一个解决方案的MultiBindingUtil类。在这里,使用了一个名为MyMultiBinding(Extension)的新类型MarkupExtension类,它有一个名为Bindings的Content属性List<Binding>(奇怪地称为Bindings),以及一个名为Converter的IMultiValueConverter类型的Converter属性(奇怪地称为Converter)。

设置这个属性作为内容是通过这个属性完成的:

C# [ContentProperty("Bindings")]

实际的技巧是在MarkupExtension的最重要的覆盖方法中完成的:

C# override object ProvideValue(IServiceProvider serviceProvider)

将执行以下操作:

  • 获取“目标”FrameworkElement:
  • 将MultiBindingUtil的绑定属性与Bindings列表的匹配值“附加”起来。
  • 将MultiBindingUtil的Converter属性与Converter的值“附加”起来。
  • 将返回值设置为Binding(而不是一个简单的值)。这个绑定将绑定到MBResult MultiBindingUtil的附加属性上。

解决方案1和2应该与Silverlight4.0兼容。

解决方案3不适用于样式设置器多绑定。

快速脏办法(#1)可以在这种情况下提供帮助:

XML <Setter Property="mb:MultiBindingReplacement.EpisodeLength" Value="{Binding Path=RangeMilSec}" /> <Setter Property="mb:MultiBindingReplacement.Scale" Value="{Binding Path=VM.ScaleTransScaleX}" />
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485