你能在数据绑定的 WPF 样式中做“数学”吗

Posted

技术标签:

【中文标题】你能在数据绑定的 WPF 样式中做“数学”吗【英文标题】:Can you do "math" within WPF Styles that are data-bound 【发布时间】:2010-09-24 13:52:16 【问题描述】:

我有一个按钮控件样式,我想更改数据绑定版本的填充,以针对需要 2 像素偏移的字形进行调整。我将使用 SimpleStyles.xaml 中的 SimpleButton 作为示例(...为简洁起见,显示了删除触发器代码的位置):

<Style x:Key="SimpleButton" TargetType="x:Type Button" BasedOn="x:Null">
  <Setter Property="FocusVisualStyle" Value="DynamicResource SimpleButtonFocusVisual"/>
  <Setter Property="Background" Value="DynamicResource NormalBrush"/>
  <Setter Property="BorderBrush" Value="DynamicResource NormalBorderBrush"/>
  <Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="x:Type Button">
            <!-- We use Grid as a root because it is easy to add more elements to customize the button -->
           <Grid x:Name="Grid">
             <Border x:Name="Border" Background="TemplateBinding Background" BorderBrush="TemplateBinding BorderBrush" BorderThickness="TemplateBinding BorderThickness" Padding="TemplateBinding Padding"/>

              <!-- Content Presenter is where the text content etc is placed by the control. The bindings are useful so that the control can be parameterized without editing the template -->
             <ContentPresenter HorizontalAlignment="TemplateBinding HorizontalContentAlignment" Margin="TemplateBinding Padding" VerticalAlignment="TemplateBinding VerticalContentAlignment" RecognizesAccessKey="True"/>
           </Grid>
     ...
    </Setter.Value>                     
  </Setter>
</Style>

我想要做的是在 Padding="TemplateBinding Padding" 的地方添加一些额外的边距。像 Padding="TemplateBinding Padding + 2,0,0,0"。

这有 XAML 语法吗?如果没有,在代码中执行此操作时是否有最佳方法(装饰器?)?

【问题讨论】:

【参考方案1】:

目前 XAML 不解析 Binding 语法等中的表达式。但是,您可以使用 IValueConverter 或 IMultiValueConverter 来帮助自己:

XAML:

<Setter.Value>
    <ControlTemplate TargetType="x:Type Button">
       <Grid x:Name="Grid">
         <Grid.Resources>
             <local:ThicknessAdditionConverter x:Key="AdditiveThickness" />
         </Grid.Resources>
         <Border x:Name="Border">
             <Border.Padding>
                 <Binding Path="Padding" RelativeSource="RelativeSource TemplatedParent"
                          Converter="StaticResource AdditiveThickness">
                     <Binding.ConverterParameter>
                         <Thickness>2,0,0,0</Thickness>
                     </Binding.ConverterParameter>
                 </Binding>
             </Border.Padding>
         </Border>
 ...
</Setter.Value>  

IValueConverter 后面代码:

public class ThicknessAdditionConverter : IValueConverter

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    
        if (value == null) return new Thickness(0, 0, 0, 0);
        if (!(value is Thickness)) throw new ArgumentException("Value not a thickness", "value");
        if (!(parameter is Thickness)) throw new ArgumentException("Parameter not a thickness", "parameter");

        var thickness = new Thickness(0, 0, 0, 0);
        var t1 = (Thickness)value;
        var t2 = (Thickness)parameter;

        thickness.Left = t1.Left + t2.Left;
        thickness.Top = t1.Top + t2.Top;
        thickness.Right = t1.Right + t2.Right;
        thickness.Bottom = t1.Bottom + t2.Bottom;

        return thickness;
    

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    
        throw new NotImplementedException();
    

【讨论】:

【参考方案2】:

Blendables.com 上有一个产品,名为 Eval BindingSimple Binding 现在可以做到这一点。 (该产品不是免费的)在这里查看whitepaper

例如,对于下面的 XAML 代码,您需要一个转换器来执行操作。

<Ellipse Fill="Blue" Height="50"
    Width="Binding RelativeSource=RelativeSource Self, 
        Path=Height, Converter=StaticResource MyConverter" />

但是使用 EvalBinding 你可以像下面那样做

    <Ellipse Fill="Blue" Height="50"
    Width="blendables:EvalBinding [Self.Height]/2" />

【讨论】:

【参考方案3】:

不,不在此版本的 XAML 中 - 使用值转换器进行数学运算。

【讨论】:

您能否提供一个使用值转换器进行此数学运算的示例 - 这对我来说更像是滥用。【参考方案4】:

查看this library 中的ExpressionConverter

【讨论】:

【参考方案5】:

您可以利用变换进行一些简单的数学运算。

查看 Charles Petzold 很久以前提出的这个技巧: http://www.charlespetzold.com/blog/2006/04/060223.html

不幸的是,它似乎对您的特定场景没有帮助...因为您只想更改 Padding 的厚度类型的 Left 属性...而且这不是您可以单独绑定的依赖属性。

但是,我觉得有必要添加这个答案,因为它可以帮助其他人通过 Google 或其他搜索引擎找到他们的方式。

【讨论】:

【参考方案6】:

查看 MathConverter:http://rachel53461.wordpress.com/2011/08/20/the-math-converter/

您可以在此处发送一个表达式作为转换器参数,其中@VALUE 是您要绑定的值:

ConverterParameter=((@VALUE-15)*.2)

【讨论】:

以上是关于你能在数据绑定的 WPF 样式中做“数学”吗的主要内容,如果未能解决你的问题,请参考以下文章

你能在Vim中使用特定于文件类型的键绑定吗?

WPF 数据网格样式

WPF 样式中的绑定导致莫名其妙的“找不到管理 FrameworkElement”错误

WPF——ComboBox控件怎么绑定数据

你能在文本中隐藏数据吗?

WPF MVVM--数据绑定