views:

927

answers:

3

I want to add a constant value onto an incoming bound integer. In fact I have several places where I want to bind to the same source value but add different constants. So the ideal solution would be something like this...

<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}"/>

(NOTE: This is an example to show the idea, my actual binding scenario is not to the canvas property of a TextBox. But this shows the idea more clearly)

At the moment the only solution I can think of is to expose many different source properties each of which adds on a different constant to the same internal value. So I could do something like this...

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

But this is pretty grim because in the future I might need to keep adding new properties for new constants. Also if I need to change the value added I need to go an alter the source object which is pretty naff.

There must be a more generic way than this? Any WPF experts got any ideas?

+4  A: 

I believe you can do this with a value converter. Here is a blog entry that addresses passing a parameter to the value converter in the xaml. And this blog gives some details of implementing a value converter.

Steve Steiner
The fact the value converter can take a parameter seems like a good approach to solving the problem here. Thanks for the input.
Phil Wright
A: 

I've never used WPF, but I have a possible solution.

Can your binding Path map to a Map? If so, it should then be able to take an argument (the key). You'd need to create a class that implements the Map interface, but really just returns the base value that you initialized the "Map" with added to the key.

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

Without some ability to pass the number from the tag, I don't see how you're going to get it to return different deltas from the original value.

Hope it helped

Bill James
+2  A: 

Using a value converter is a good solution to the problem as it allows you to modify the source value as it's being bound to the UI.

I've used the following in a couple of places.

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();
    }
}

Example

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