Is it possible to have just a part of a margin in a binding in XAML

40 Views Asked by At

I have a XAML, containing information like this:

... Margin="10,20,30,40" ...

I know that it is very easy to set the left margin in a binding, as such:

Margin="{Binding margin_value}"

... but this would not fill in the values "20, 30, 40".

Everywhere I search on the internet, I see the same answer:

You are looking for Top, Left, Bottom and Right. In order to fill those in, here's the C# code.

I'm not interested in C# code, I would like to set it in the XAML directly as a binding result, but everything I tried (Margin.X="{Binding ...}", Margin.Left="{Binding ...}", Left.Margin="{Binding ...}", ...) seem not to work, although I'm convinced it should be really easy.

Does anybody know how to do this?
Thanks in advance

2

There are 2 best solutions below

0
lidqy On

You can specify as few or many of the four Thickness-Properties as you like, be it one, two, three or four out of Left, Top, Left or Buttom.
However ommitting one just will implicitly make it hold the value of 0.
So all you gain is not writing the 0.
WPF built-in converter for Margin or other properties of type Thickness takes 1, 2 or 4 arguments but not 3.
And when you specify one or two its just a shorthand and all four value(s) are applied anyways.
So if you don't want to specify one of them you can do it with a more verbose syntax that names the properties:

<TextBox Text="Hello">
  <TextBox.Margin>
      <Thickness Left="8" Top="2" Bottom="2" /><!-- Right missing -->
  </TextBox.Margin>
</TextBox>

<TextBox Text="Hello">
  <TextBox.Margin>
      <Thickness Right="10" /><!-- Left Top Bottom -->
  </TextBox.Margin>
</TextBox>

But as already stated this is just kind of a lengthy way for specifying this markup:

<TextBox Text="Hello" Margin="8 2 0 2" />
<TextBox Text="Hello" Margin="0 0 10 0" />

Moreover a thickness is just a plain struct, it has no dependency properties. So you can't bind to the named four dimension properties. Conclusion: Use the built-in type converter and specify all 4 values where the shorthands don't satisfy your demands.

0
emoacht On

The syntax you want can be achieved with attached properties like the following.

public static class Margin
{
    public static double GetLeft(DependencyObject obj) => (double)obj.GetValue(LeftProperty);
    public static void SetLeft(DependencyObject obj, double value) => obj.SetValue(LeftProperty, value);
    public static readonly DependencyProperty LeftProperty =
        DependencyProperty.RegisterAttached("Left", typeof(double), typeof(Margin),
            new PropertyMetadata(
                defaultValue: 0D,
                propertyChangedCallback: (d, e) =>
                {
                    if (d is FrameworkElement element)
                    {
                        element.Margin = new Thickness((double)e.NewValue, 0, 0, 0);

                        // If the other values should be kept.
                        // element.Margin = new Thickness((double)e.NewValue, element.Margin.Top, element.Margin.Right, element.Margin.Bottom);
                    }
                }));
}
<Button local:Margin.Left="100"/>

You can add Top, Right, Bottom, or something as well.