views:

1457

answers:

4

I have a button control style and I want to change the padding from whatever the data-bound version is to adjust for a glyph that needs a 2 pixel offset. I'll use SimpleButton from SimpleStyles.xaml as an example (... shows where the trigger code was removed for conciseness):

<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>

What I want to do is add some extra margin where Padding="{TemplateBinding Padding}". Something like Padding="{TemplateBinding Padding} + 2,0,0,0".

Is there a XAML syntax to that? If not, is there a best approach when doing this in code (Decorator?) ?

+2  A: 

No, not in this version of XAML - use a Value Converter to do your math.

Paul Betts
Reference IValueConverter and IMultiValueConverter.
sixlettervariables
Can you provide an example of using a value converter to do this math - it seems more like misuse to me.
Geoff Cox
+1  A: 

There is a product available at Blendables.com called Eval Binding and Simple Binding does this now. (The product is not free) Check out the whitepaper here

For example for the bellow XAML code you need a converter to do the operation.

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

But with EvalBinding you can do like bellow

    <Ellipse Fill="Blue" Height="50"
    Width="{blendables:EvalBinding [{Self}.Height]/2}" />
Jobi Joy
EvalBinding can't handle the scenario Geoff's asked for, because it can't create a 'new' Thickness object.
sixlettervariables
+1  A: 

Check out the ExpressionConverter in this library.

HTH, Kent

Kent Boogaart
It doesn't look like an ExpressionConverter can create a new object.
sixlettervariables
+2  A: 

Currently XAML does not parse expressions in Binding syntax, etc. However, you can use an IValueConverter or IMultiValueConverter to help yourself out:

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 code behind:

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