在开发Silverlight应用程序时,经常会遇到需要根据多个输入来获取单个结果的情况。在WPF中,这可以通过MultiValueConverter实现,但在Silverlight中,这个特性是缺失的。本文将介绍三种解决方案,从快速脏办法到类似WPF的实现。
在将WPF应用程序移植到Silverlight时,遇到了这个“缺失特性”的问题,因为Silverlight只是WPF的一个子集。像其他软件开发者一样,首先在Google上搜索了这个问题。在考察了建议的方法后,得出了以下结论:
一些解决方案过于复杂,不符合“口味”。这些解决方案并不像希望的那样健壮。例如:
因此,决定尝试用自己的方式解决这个问题。一些“提示”引导找到了解决方案:
认为对于遇到的任何算法问题,都有一个简单、优雅、快速的解决方案,只需要找到它...所以把第二个原因当作“真正的”原因。
思考多绑定的核心功能应该会让人想到:
Silverlight 5.0中引入的新特性:
有了这些“提示”,提出了三种解决方案:
如果只关心多绑定功能,可以采用这种方法:
作为最佳实践,最好将多绑定分离到单独的任务中:
考虑到这一点,可以创建一个基于AttachedProperty的类(称为MultiBindingUtil),它将有任意数量的Attached Properties用于输入绑定(称为Binding1到Binding(n)),AttachedProperty用于Converter,最后,一个AttachedProperty用于结果(在示例中称为MBResult)。现在在XAML中所要做的就是将输入绑定AttachedProperties绑定到喜欢的任何东西上,提供一个转换器,并将MBResult绑定回希望被多绑定改变的属性。
在多绑定“引擎”内部,就像前一个示例一样,将任何输入绑定变化转发到一个单一的'Any...Changed'子程序中;只是在那里,将使用类绑定作为输入,更新MBResult属性与提供的转换器的转换结果。
一切都很好,除了在Silverlight中绑定元素属性到其自己的附加属性时,会出现一个众所周知的设计时错误。这个错误以非常微妙和有信息量的方式表现出来:
这种解决方案在移植时可能很有帮助,因为它非常接近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)
将执行以下操作:
解决方案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}" />