wpf 嵌套的多绑定

fsi0uk1n  于 2023-01-27  发布在  其他
关注(0)|答案(7)|浏览(215)

我使用WPF已经有一段时间了,但是今天我第一次需要将一个MultiBinding嵌套在另一个MultiBinding中,类似于:

<MultiBinding>
   <Binding />       
   <MultiBinding>
      <Binding />
      <Binding />
   </MultiBinding>
</MultiBinding>

我得到一个异常,指出框架不允许这样做:
未处理XamlParseException:向类型为“System.Collections.ObjectModel.集合(System.Windows.Data.BindingBase)”的集合添加值时引发异常。
InnerException更明确:
BindingCollection不支持MultiBinding类型的项。只允许使用Binding。
因此,在网上挖掘更多信息时,我偶然发现了X1 E0 F1 X,这正是我的问题。
感谢您的反馈。WPF目前不支持此功能。多年来一直要求提供此功能(最近一次是在本月初-请参阅https://connect.microsoft.com/WPF/feedback/details/650164/nested-multibinding)。我们将继续考虑在将来的版本中提供此功能。
现在我已经平静下来,我不会让它变得容易。但我仍然需要这个,我如何嵌套多绑定

lbsnaicq

lbsnaicq1#

我知道这是一个老问题,但我认为这是一个更好的方法:

<FrameworkElement x:Name="IsBuyAndAmountInReference">
    <FrameworkElement.Tag>
        <MultiBinding Converter="{StaticResource LogicAndToBool}">
            <Binding Path="OrderData.IsBuy" />
            <Binding Path="OrderData.AmountInReference" />
        </MultiBinding>
    </FrameworkElement.Tag>
</FrameworkElement>
<FrameworkElement x:Name="IsSellAndAmountInBase">
    <FrameworkElement.Tag>
        <MultiBinding Converter="{StaticResource LogicAndToBool}">
            <Binding Path="OrderData.IsBuy" Converter="{StaticResource BooleanToBooleanInvert}" />
            <Binding Path="OrderData.AmountInReference" Converter="{StaticResource BooleanToBooleanInvert}" />
        </MultiBinding>
    </FrameworkElement.Tag>
</FrameworkElement>

<Slider Grid.Row="2" Grid.ColumnSpan="4">
    <Slider.Visibility>
        <MultiBinding Converter="{StaticResource LogicOrToVisibility}">
            <Binding ElementName="IsBuyAndAmountInReference" Path="Tag" />
            <Binding ElementName="IsSellAndAmountInBase" Path="Tag" />
        </MultiBinding>
    </Slider.Visibility>
</Slider>
xytpbqjk

xytpbqjk2#

其他建议的替代方法是使用附加属性将嵌套的MultiBinding保存为中间值。
例如,代替:

<Element>
  <Element.Property>
    <MultiBinding>
      <Binding Path="A" />       
      <MultiBinding>
        <Binding Path="B" />
        <Binding Path="C" />
      </MultiBinding>
    </MultiBinding>
  </Element.Property>
</Element>

...执行以下操作:

<Element Name="ElementName">
  <ElementProperties.AttachedProperty>
    <MultiBinding>
      <Binding Path="B" />
      <Binding Path="C" />
    </MultiBinding>
  </ElementProperties.AttachedProperty>
  <Element.Property>
    <MultiBinding>
      <Binding Path="A" />       
      <Binding ElementName="ElementName" Path="(ElementProperties.AttachedProperty)" />
    </MultiBinding>
  </Element.Property>
</Element>

我知道这个问题已经有六年多的历史了,但我遇到了这个问题,所以其他人也会遇到。

fquxozlt

fquxozlt3#

如果你有一个带参数的转换器,你可以这样做:

  • 创建一个类,用于将“固定”数据传递给转换器
  • DependencyProperties添加到类中(以便可以绑定Xaml中的值)
  • 在XAML中,使用带有转换器的绑定,而不是多绑定,类似于:
<MultiBinding>
    <Binding Source="SomeObject" Path="CoreValue" Converter="{StaticResource YourNewConverter}">
        <Binding.ConverterParameter>
            <ns:ParameterClass Value1="{Binding Parameter1}" Value2="{Binding Parameter1}" />
        </Binding.ConverterParameter>
    </Binding>
 ....

限制是(AFAIK)只有在CoreValue发生变化时才会重新计算该值,而在转换器参数发生变化时不会自动重新绑定。
(对任何错误表示歉意,我在没有使用VS进行测试的情况下输入了这个...)

xwbd5t1u

xwbd5t1u4#

我意识到这是一个老问题了,但我刚刚碰到了与OP完全相同的问题。幸运的是,在我的例子中,我可以绑定到一个子元素,其中多绑定的结果已经被计算出来了,但这让我想到...
一个解决方案(尽管公认不是很干净)是将多值绑定的值写入一个“spare”属性,如元素的“Tag”,然后可以通过指定“ElementName”属性在其他多值绑定中引用该属性。
如果你需要多个嵌套的多值绑定,那么你可以创建一个带有依赖属性的“伪”对象来存储多个中间结果。
遗憾的是微软没有实现一个正确的嵌套系统...

neekobn8

neekobn85#

只需在MultiConverter中使用一个多绑定即可。
或者我更喜欢在你的视图模型/数据上下文的一个属性中暴露你的条件。

hvvq6cgz

hvvq6cgz6#

如果你绑定到一个字符串,你可以使用StringFormat,就像这个例子:

<TextBlock>
   <TextBlock.Text>
     <MultiBinding StringFormat="{}{0:0.###}/{1:0.###}" Mode="OneWay">
                        <Binding ElementName="This" Path="AggregatedDocDetail.ConfirmedQty"></Binding>
                        <Binding ElementName="This" Path="AggregatedDocDetail.Qty">   </Binding>
       </MultiBinding>
     </TextBlock.Text>
   </TextBlock>
ycl3bljg

ycl3bljg7#

您也可以使用简单的绑定代理。

<DataGrid.ContextMenu>
    <ContextMenu>
        ...
        <MenuItem Click="MenuItem_Click" Header="Use in filter" Command="{Binding SetCatFilterCommand}">
            <MenuItem.Resources>
                <local:BindingProxy x:Key="AsLitterIsEnabled" >
                    <local:BindingProxy.Data>
                        <MultiBinding Converter="{local:ViewCatConverter}"  
                            ConverterParameter="AsLitterIsEnabled">
                            <Binding Path="Heart.Cat" Mode="OneWay"/>
                            <Binding Path="Heart.SelectedLitters"                                 Mode="OneWay"/>
                        </MultiBinding>
                    </local:BindingProxy.Data>
                </local:BindingProxy>
            </MenuItem.Resources>
            <MenuItem.CommandParameter>
                <MultiBinding Converter="{local:MultiValueToArrayConverter}">
                    <Binding Path="Heart.SelectedLitters"/>
                    <Binding Source="AsLitter"/>
                    <Binding Path="CatFilter"/>
                    <Binding Path="Data" Source="{StaticResource AsLitterIsEnabled}"/>
                </MultiBinding>
             </MenuItem.CommandParameter>
         </MenuItem>
         ...
    </ContextMenu>
</DataGrid.ContextMenu>

绑定代理类:

using System.Windows;

public class BindingProxy : Freezable
{
    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object),
        typeof(BindingProxy));

    public object Data
    {
        get => GetValue(DataProperty);
        set => SetValue(DataProperty, value);
    }

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }
}

相关问题