WPF:如何将Control绑定到由多个依赖项属性组成的公式?

时间:2010-06-12 22:43:44

标签: wpf properties user-controls dependencies

我正在研究Expression Blend,我正在设计一个自定义控件,里面有一个包含5行的Grid,还有两个Dependency属性:“Value”和“Maximum”。其中三行具有固定高度,我想要做的是将剩余行高分别设置为“值/最大值”和“1值/最大值”。我该怎么做呢?

当我将高度设置为“值”时,似乎会做出反应,但当我将其设置为“值/最大值”时,它会停止工作。我仍然对WPF有点新意,所以必须有另一种方法来实现我的意图,但在搜索后我不会在其他地方找到我的问题。

代码:

<Grid x:Name="LayoutRoot" Width="Auto" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="32"/>
        <RowDefinition Height="{Binding Path=(Value/Maximum), ElementName=UserControl, Mode=Default}"/>
        <RowDefinition Height="16"/>
        <RowDefinition Height="{Binding Path=(1-Value/Maximum), ElementName=UserControl, Mode=Default}"/>
        <RowDefinition Height="32"/>
    </Grid.RowDefinitions>
    (...)

顺便说一句,Value总是不是负二倍小于或等于最大值;所以除法的结果将是0.0到1.0之间的数字。我想要一个“星”而不是“像素”行高。

2 个答案:

答案 0 :(得分:3)

您需要MultiValueConverter。我不确定我理解你在做什么,但基本上,对于XAML:

<RowDefinition>
    <RowDefinition.Height>
         <MultiBinding Converter={StaticResource ...}>
             <Binding ElementName=UserControl, Path=Value ... />
             <Binding ElementName=UserControl, Path=Maximum ... />
         </MultiBinding>
    </RowDefinition.Height>
</RowDefinition>

然后在代码中,您需要声明一个实现IMultiValueConverter的类,并且在Convert方法中,values将包含各种正常Binding的事物列表返回(0是最高的一个(这里是值),1是下一个,等等)。最后,您只需要将新类的StaticResource添加到XAML:

<Grid.Resources>
    <localxmlns:YourNewMultiValueConverter x:Key="Whatever" />
</Grid.Resources>

这应该允许你做你想做的事。

在没有intellisense的情况下输入xaml真的很糟糕

答案 1 :(得分:1)

这是一个MultiValueConverter,您可以使用JustABill的答案:

public class RatioStarSizing : IMultiValueConverter
{
  public static readonly RatioStarSizing Instance = new RatioStarSizing();

  public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
  {
    return new GridLength((double)values[0] / (double)values[1], GridUnitType.Star);
  }
  public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
  {
    throw new NotImplementedException();
  }
}

这将允许您使用此XAML:

<Grid x:Name="LayoutRoot" Width="Auto" Background="Transparent">    
  <Grid.RowDefinitions>    
    <RowDefinition Height="32"/>    
    <RowDefinition>
      <RowDefinition.Height>
        <MultiBinding Converter="{x:Static RatioStarSizing}">
          <Binding ElementName="UserControl" Path="Value" />
          <Binding ElementName="UserControl" Path="Maximum" />
        </MultiBinding>
      </RowDefinition.Height>
    </RowDefinition> Height="{Binding Path=(Value/Maximum), ElementName=UserControl, Mode=Default}"/>    
    <RowDefinition Height="16"/>    
    <RowDefinition Height="*" />
    <RowDefinition Height="32"/>    
</Grid.RowDefinitions>    
(...)    

注意使用星形大小以避免需要两个MultiValueConverters的聪明技巧:第一个元素设置为值/最大值的星号,因此如果Value为4且Maximum为10,则转换器将返回“0.4 *”作为大小,导致以下实际行高。

  <Grid.RowDefinitions>    
    <RowDefinition Height="32"/>    
    <RowDefinition Height="0.4*"/>
    <RowDefinition Height="16"/>    
    <RowDefinition Height="*" />
    <RowDefinition Height="32"/>    
  </Grid.RowDefinitions>    

正如您所看到的,这将通过单个MultiValueConverter实现您所需的功能。

作为一个脚注,我开发了一个我计划很快开源的库,这样我就可以用这种方式编写完整的东西而无需转换器:

  <Grid.RowDefinitions>    
    <RowDefinition Height="32"/>    
    <RowDefinition Height="{edf:ExpressionBinding
                             new GridLength(Value/Maximum, GridUnitType.Star)"/>
    <RowDefinition Height="16"/>    
    <RowDefinition Height="*" />
    <RowDefinition Height="32"/>    
  </Grid.RowDefinitions>    

我发布此库供公众使用后,我会在此处添加评论。