WPF DataBinding具有简单的算术运算?

时间:2008-09-24 05:19:30

标签: wpf data-binding

我想在传入的绑定整数上添加一个常量值。事实上,我有几个地方,我想绑定到相同的源值,但添加不同的常量。所以理想的解决方案就是这样......

<TextBox Canvas.Top="{Binding ElementName=mySource, Path=myInt, Constant=5}"/>
<TextBox Canvas.Top="{Binding ElementName=mySource, Path=myInt, Constant=8}"/>
<TextBox Canvas.Top="{Binding ElementName=mySource, Path=myInt, Constant=24}"/>

(注意:这是一个展示这个想法的例子,我的实际绑定方案不是TextBox的canvas属性。但这更清楚地表明了这个想法)

目前我能想到的唯一解决方案是暴露许多不同的源属性,每个源属性都将不同的常量添加到相同的内部值。所以我可以做这样的事......

<TextBox Canvas.Top="{Binding ElementName=mySource, Path=myIntPlus5}"/>
<TextBox Canvas.Top="{Binding ElementName=mySource, Path=myIntPlus8}"/>
<TextBox Canvas.Top="{Binding ElementName=mySource, Path=myIntPlus24}"/>

但这非常严峻,因为将来我可能需要不断为新常量添加新属性。此外,如果我需要更改添加的值,我需要更改源对象,这是非常naff。

必须有比这更通用的方法吗?任何WPF专家都有任何想法吗?

5 个答案:

答案 0 :(得分:19)

我使用我创建的MathConverter来执行所有简单的算术运算。转换器的代码是here,它可以像这样使用:

<TextBox Canvas.Top="{Binding SomeValue, 
             Converter={StaticResource MathConverter},
             ConverterParameter=@VALUE+5}" />

您甚至可以将其用于更高级的算术运算,例如

Width="{Binding ElementName=RootWindow, Path=ActualWidth,
                Converter={StaticResource MathConverter},
                ConverterParameter=((@VALUE-200)*.3)}"

答案 1 :(得分:7)

我相信你可以用价值转换器来做到这一点。这是一个blog entry,用于将参数传递给xaml中的值转换器。 this blog提供了实现值转换器的一些细节。

答案 2 :(得分:5)

使用值转换器是解决问题的好方法,因为它允许您在绑定到UI时修改源值。

我在几个地方使用了以下内容。

public class AddValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        object result = value;
        int parameterValue;

        if (value != null && targetType == typeof(Int32) && 
            int.TryParse((string)parameter, 
            NumberStyles.Integer, culture, out parameterValue))
        {
            result = (int)value + (int)parameterValue;
        }

        return result;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

实施例     

 <Setter Property="Grid.ColumnSpan"
         Value="{Binding 
                   Path=ColumnDefinitions.Count,
                   RelativeSource={RelativeSource AncestorType=Grid},
                   Converter={StaticResource addValueConverter},
                   ConverterParameter=1}"
  />

答案 3 :(得分:0)

我从未使用过WPF,但我有一个可能的解决方案。

您的绑定路径可以映射到地图吗?如果是这样,它应该能够采取一个参数(密钥)。您需要创建一个实现Map接口的类,但实际上只返回初始化“Map”并添加到键中的基值。

public Integer get( Integer key ) { return baseInt + key; }  // or some such

如果没有能力从标签中传递数字,我不会看到你如何让它从原始值返回不同的增量。

答案 4 :(得分:0)

我将使用多绑定转换器,例如以下示例:

C#代码:

namespace Example.Converters
{
        public class ArithmeticConverter : IMultiValueConverter
        {            
            public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            {
                double result = 0;

                for (int i = 0; i < values.Length; i++)
                {
                    if (!double.TryParse(values[i]?.ToString(), out var parsedNumber)) continue;

                    if (TryGetOperations(parameter, i, out var operation))
                    {
                        result = operation(result, parsedNumber);
                    }
                }

                return result;
            }

            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
            {
                return new[] { Binding.DoNothing, false };
            }


            private static bool TryGetOperations(object parameter, int operationIndex, out Func<double, double, double> operation)
            {
                operation = null;
                var operations = parameter?.ToString().Split(',');

                if (operations == null || operations.Length == 0) return false;

                if (operations.Length <= operationIndex)
                {
                    operationIndex = operations.Length - 1;
                }

                return Operations.TryGetValue(operations[operationIndex]?.ToString(), out operation);
            }

            public const string Add = "+";
            public const string Subtract = "-";
            public const string Multiply = "*";
            public const string Divide = "/";

            private static IDictionary<string, Func<double, double, double>> Operations = new Dictionary<string, Func<double, double, double>>
            {
                { Add, (x, y) => x + y },
                { Subtract, (x, y) => x - y },
                { Multiply, (x, y) => x * y },
                { Divide, (x, y) => x / y }
            };
        }
}

XAML代码:

<UserControl 
     xmlns:converters="clr-namespace:Example.Converters">
    <UserControl.Resources>
                    <converters:ArithmeticConverter x:Key="ArithmeticConverter" />
    </UserControl.Resources>

...

<MultiBinding Converter="{StaticResource ArithmeticConverter}" ConverterParameter="+,-">
            <Binding Path="NumberToAdd" />
            <Binding Path="NumberToSubtract" />
</MultiBinding>