如何对 XAML 绑定值执行计算:反转、相乘、减去或相加?

Posted

技术标签:

【中文标题】如何对 XAML 绑定值执行计算:反转、相乘、减去或相加?【英文标题】:How perform calculation on a XAML Binding value: reverse it, multiply it, subtract from it or add to it? 【发布时间】:2011-06-25 13:42:48 【问题描述】:

首先;这个问题是反问的,我有一个答案!我从这里得到了很多帮助,我想把这个巧妙的技巧还给我。

假设您有一个想要绑定的值,但它在某种程度上或有些错误。

我有一种情况,我想绑定一个值,但是当值为 1 时,我需要 0,反之亦然。 曾经我想将元素的宽度绑定到父元素的宽度 - 68px。

【问题讨论】:

转换器的广泛使用的好主意。我会牢记这个想法。我曾经需要对绑定值进行的大部分数学运算都可以使用这个转换器来完成。我的经验是将这些称为线性变换函数或一阶多项式。我可能会将其命名为 LinearTransformConverter。 您应该将答案作为实际答案发布,而不是将其包含在问题中。 它在法语中也被称为“一级函数”......好吧,我猜到处都是:-D 聪明,但在大多数情况下,如果您使用值转换器而不是视图模型逻辑,您可能会犯某种错误。这当然有很多例外(例如,我确信存在没有视图模型的可靠用例,尽管我还没有看到)。但我的感觉是,值转换器通常是一种将代码注入 XAML 的 hack,这使得它成为一种将代码注入 hack 的 hack。 我在 8 年后才意识到,所以现在可能更清楚了,但我还是会说:@RobertRossney - 我非常不同意。 “不要将代码注入 XAML”的原则更正确地表述为“不要将业务/建模逻辑与表示逻辑混合”。涉及表达式甚至约束的 GUI 系统是 100% 有效和适当的——只要计算严格用于显示目的。 “有限”的情况,人们最终在他们的视图模型中进行那些只显示的计算,因为这更容易,这是错误的。 【参考方案1】:

输入FirstDegreeFunctionConverter

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;

namespace GenericWPF

    /// <summary>
    /// Will return a*value + b
    /// </summary>
    public class FirstDegreeFunctionConverter : IValueConverter
    
        public double A  get; set; 
    public double B  get; set; 

    #region IValueConverter Members

    public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
    
        double a = GetDoubleValue( parameter, A );

        double x = GetDoubleValue( value, 0.0 );

        return ( a * x ) + B;
    

    public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
    
        double a = GetDoubleValue( parameter, A );

        double y = GetDoubleValue( value, 0.0 );

        return ( y - B ) / a;
    

    #endregion


    private double GetDoubleValue( object parameter, double defaultValue )
    
        double a;
        if( parameter != null )
            try
            
                a = System.Convert.ToDouble( parameter );
            
            catch
            
                a = defaultValue;
            
        else
            a = defaultValue;
        return a;
    

如何使用它?

您在资源部分为每次使用创建一个资源:

<GenericWPF:FirstDegreeFunctionConverter x:Key="ReverseOne"
                            A="-1"
                            B="1" />

<Border Opacity="Binding Path=Opacity
    , ElementName=daOtherField
    , Converter=StaticResource ReverseOne" />

<GenericWPF:FirstDegreeFunctionConverter x:Key="ListboxItemWidthToErrorWidth"
     A="1"
     B="-68" />

<TextBox MaxWidth="Binding Path=ActualWidth
   , Converter=StaticResource ListboxItemWidthToErrorWidth
   , RelativeSource=RelativeSource FindAncestor, AncestorType=x:Type ListBoxItem" />

名字来源于函数y = a*x + b(挪威语称为“一级函数”),当然也可以升级为二级函数y= a*x^2 + bx + c,但我还没有找到它的用途。

我有一种情况,我想根据宽度制作列。每次宽度增加 200 像素时,我都希望容器显示另一列。当时我硬编码了一个转换器,但我应该改用 y=(a/x) + b 转换器。

现在,我应该给这个转换器起什么名字,以便每个人都明白它是什么?由于我是挪威人,所以我使用了我们在学校学到的表达方式,直接翻译。请,如果您有任何建议或意见,请告诉我。 您想到的任何改进或改进也将不胜感激......


也许“LinearTransformConverter”会更好地传达转换器为您做了什么,我会考虑一下。 还有其他建议吗? 托尔

【讨论】:

【参考方案2】:

更好的是PolynomialConverter,这是单向版本:

public class PolynomialConverter : IValueConverter

    public DoubleCollection Coefficients  get; set; 

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
        double x = (double)value;
        double output = 0;
        for (int i = Coefficients.Count - 1; i >= 0 ; i--)
            output += Coefficients[i] * Math.Pow(x, (Coefficients.Count - 1) - i);

        return output;
    

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
        //This one is a bit tricky, if anyone feels like implementing this...
        throw new NotSupportedException();
    

例子:

<!-- x^2 -->
<vc:PolynomialConverter Coefficients="1,0,0"/>
<!-- x + 5 -->
<vc:PolynomialConverter Coefficients="1,5"/>
<!-- 2x + 4 -->
<vc:PolynomialConverter Coefficients="2,4"/>

或者,可以使用 ConverterParameter 代替在转换器本身中设置系数。

DoubleCollection coefficients = DoubleCollection.Parse((string)parameter);
//...

【讨论】:

以上是关于如何对 XAML 绑定值执行计算:反转、相乘、减去或相加?的主要内容,如果未能解决你的问题,请参考以下文章

绑定到其他元素(高度减去5px)

如何反转 UISlider 的最小值-最大值?

3 运算符

3 运算符

有没有办法在 XAML 中链接多个值转换器?

如何使用 C# 反转 XAML PNG 图像的颜色?