65.9K
CodeProject 正在变化。 阅读更多。
Home

Silverlight 多重绑定

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2011 年 11 月 16 日

CPOL

4分钟阅读

viewsIcon

31639

downloadIcon

456

在 Silverlight 中执行多重绑定。

Screen.GIF

引言

Multi-binding 是 WPF 中一个非常重要/强大的功能。当您需要一个依赖于多个输入的单个结果时,它会派上用场。该结果被绑定到一个特殊的逻辑,该逻辑通常在“MultiValueConverter”中实现。因此,任何输入的更改都应该体现在输出结果中。在 Silverlight 中,此功能缺失!

在本文中,我将展示我提出的三种解决方案,从“快速简单”到“类似 WPF”。

背景

在将 WPF 应用程序移植到 Silverlight 时,我遇到了这个“缺失的功能”问题(Silverlight 程序员都熟悉......),因为 Silverlight 只是 WPF 的一个子集。像任何其他软件开发人员一样,我做的第一件事就是谷歌搜索......

在研究了建议的方法后,我得出了这些结论

  1. 其中一些解决方案对我来说太聪明/太复杂了。
  2. 解决方案不如我希望的那样健壮。
  3. 例如

    • 不支持 DependencyObject 多重绑定(仅支持 FrameworkElement
    • Binding 中缺乏 RelativeSource
  4. 实现方式与基础 WPF 方式相去甚远(有时很笨拙),这使得移植到 Silverlight 非常混乱。

所以,我想我应该试试,用自己的方式来解决它……

一些“提示”引导我找到了我提出的解决方案

  1. 微软在所有 Silverlight 版本中一直排除此功能,这可能有两个原因
    1. 微软对其开发者的需求漠不关心……
    2. 微软“认为”使用标准可用工具可以相对简单地实现此功能。
    3. 我发现,对我来说,采用一种方法更有成效:对于我遇到的任何算法问题,存在一个简单、优雅且快速的解决方案,我只需要找到它……所以我认为第二个原因是“真正”的原因。

  2. 思考多重绑定的核心功能应该会“触发”某人的灵感
  3. 哪个标准 Silverlight 功能具有“监视和响应属性更改”的“能力”?是的,DependencyProperty!以及它的变体 AttachedProperty

  4. Silverlight 5.0 中引入的新功能
    • RelativeSourceAncestorType
    • MarkupExtension(简而言之,XAML 中“自动”实例化的对象,它有一个返回值)。

考虑到这些“提示”,我提出了三个解决方案

1. 快速简单

如果您只考虑多重绑定的**功能**,您可以使用此方法来实现。

  • 构造一个“专用”类,其中包含与您的输入绑定匹配的附加属性(您甚至可以为这些属性赋予有意义的名称)。
  • 将任何这些附加属性的更改中继到一个单一的“Any...Changed”子例程,您将在其中执行两项操作
    1. 执行您想要的多重绑定逻辑。
    2. 更新“结果属性”。

2. 部分优雅

作为最佳实践,最好将多重绑定分离到不同的任务中

  1. 多输入绑定通用“引擎”(适用于 XAML)
  2. 多值转一逻辑(通常作为 IMultiValueConverter 的实现)。

考虑到这一点,我们可以创建一个基于“AttachedProperty”的类(称为 MultiBindingUtil),它将拥有任意数量(为简单起见,示例只有三个预定义的)的附加属性用于输入绑定(称为 Binding1Binding(n))、用于ConverterAttachedProperty,最后,用于结果的AttachedProperty(在示例中称为 MBResult)。现在,我们在 XAML 中要做的就是将输入绑定的附加属性绑定到我们想要的任何内容,提供一个转换器,并将 MBResult 绑定回我们想要由多重绑定更改的属性。在多重绑定“引擎”内部,就像之前的示例一样,我们将把任何输入绑定的更改中继到一个单一的“Any...Changed”子例程;只有在那里,我们将使用该类的绑定作为输入,用提供的转换器的**转换后**结果更新 MBResult 属性。一切都很好,除了有一个有据可查/已报告的设计时错误发生在 Silverlight 中,当将元素的属性绑定到其自身的附加属性时。此错误以一种非常微妙且具有信息量的方式表现出来。

Ms_AttachedPropRef_Bug.JPG

我找不到任何解决此“本地路径”问题的方法。如果您知道如何修复它,请分享。

3. 类似 WPF

此解决方案提供了与 WPF 的多重绑定非常相似的 XAML 外观,这在移植时可能很有帮助。此外,它还利用了新的 Silverlight 5.0 MarkupExtension 支持以及前一个解决方案的 MultiBindingUtil 类。在这里,我们使用一种新的 MarkupExtension 类型类,称为“MyMultiBinding(Extension)”,它有一个 Content 属性 List<Binding>,名为(奇怪地)“Bindings”,以及一个名为(奇怪地)“Converter”的 IMultiValueConverter 类型属性。

使用此属性作为内容是通过此属性完成的

[ContentProperty("Bindings")]

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

override object ProvideValue(IServiceProvider serviceProvider)

我们将执行以下操作

  1. 获取“目标” FrameworkElement
  2. IProvideValueTarget pvt = 
      serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
    DependencyObject  TargetObject = pvt.TargetObject as DependencyObject ;
  3. MultiBindingUtil 的绑定属性“附加”到它,并将其值与“我们的”Bindings 列表匹配。
  4. for (int i = 0; i < _Bindings.Count ; i++)
    {
        string sDpName="Binding"+(i+1).ToString()+"Property";
        //using reflection to get the DependencyProperty from type/string
        FieldInfo fi = typeof(MultiBindingUtil).GetField(sDpName);
        if (fi==null)
        {
            throw new IndexOutOfRangeException(
              "MultiBindingUtil Max number of binding(3) exceeded");
        }
        DependencyProperty dp = (DependencyProperty)fi.GetValue(null);
        BindingExpressionBase beb = 
          BindingOperations.SetBinding(TargetObject, dp, _Bindings[i]);                   
    }
  5. Converter 属性“附加”到它,值为“我们的”Converter
  6. TargetObject.SetValue(MultiBindingUtil.ConverterProperty, this.Converter);
  7. 将返回值设置为 Binding(而不是简单值)。此绑定将绑定到 MBResult MultiBindingUtil 的附加属性(!)。
  8. Binding b = new Binding();
    b.Source = TargetObject;
    b.Path =new PropertyPath(MultiBindingUtil.MBResultProperty);
    return b;

备注

  1. 解决方案 1 和 2 应与 Silverlight 4.0 兼容。
  2. 解决方案 3 对 Style Setter 多重绑定不起作用。
  3. 快速简单解决方案(#1)可以在那里提供帮助,就像这样

    <Setter Property="mb:MultiBindingReplacement.EpisodeLength" 
            Value="{Binding Path=RangeMilSec}" />
    <Setter Property="mb:MultiBindingReplacement.Scale" 
            Value="{Binding Path=VM.ScaleTransScaleX}" />

    其中 MultiBindingReplacement 是专用类的名称,而 EpisodeLengthScale 是绑定的专用 DependencyProperty

    在类中,我执行“转换逻辑”并将结果设置到 Style 的目标对象的特殊属性中(如解决方案 3 中所述)。

© . All rights reserved.