Set a margin from a binding
Solution 1
Return the margin?
public Thickness Margin
{
get { return new Thickness(BondIndent,0,BondIndent,0);}
}
Then change:
<Image x:Name="_image" Source="mat.png" Margin="{Binding EditorRow.Margin}" />
Solution 2
You probably need to use a ValueConverter for this. Something like:
public class LeftRightThicknessConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is int)
{
int margin = (int)value;
return Thickness(margin, 0, margin, 0);
}
return Thickness();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
You can then use the converter in the following way:
<Grid>
<Grid.Resources>
<xxx:LeftRightThicknessConverter x:Key="LeftRightThicknessConverter" />
</Grid.Resources>
<Image Margin="{Binding SomePropertyPath, Converter={StaticResource LeftRightThicknessConverter}}" />
</Grid>
Assuming that xxx
is a valid xml-namespace.
Solution 3
Instead of returning an int
you can return a Thickness, which the Margin
actually is:
public Thickness BondIndent
{
get
{
int margin = _bondSequence * 5;
return new Thickness(margin, 0, margin, 0);
}
}
The reason why your example works is because Thickness
has overloaded constructors that take 1, 2 or 4 arguments. Whenthe constructor that takes 1 argument is called, all sides are initialized to that value. WPF automatically converts this to a Thickness
based on the bound value.
On another topic, BondIndent
might better be called BondMargin
or BondThickness
now.
Solution 4
Just wrote some attached properties that should make it easy to set an individual Margin value from a binding or static resource:
WPF:
public class Margin
{
public static readonly DependencyProperty LeftProperty = DependencyProperty.RegisterAttached(
"Left",
typeof(double),
typeof(Margin),
new PropertyMetadata(0.0, LeftChanged));
private static void LeftChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var frameworkElement = d as FrameworkElement;
if (frameworkElement != null)
{
Thickness currentMargin = frameworkElement.Margin;
frameworkElement.Margin = new Thickness((double)e.NewValue, currentMargin.Top, currentMargin.Right, currentMargin.Bottom);
}
}
public static void SetLeft(UIElement element, double value)
{
element.SetValue(LeftProperty, value);
}
public static double GetLeft(UIElement element)
{
return 0;
}
public static readonly DependencyProperty TopProperty = DependencyProperty.RegisterAttached(
"Top",
typeof(double),
typeof(Margin),
new PropertyMetadata(0.0, TopChanged));
private static void TopChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var frameworkElement = d as FrameworkElement;
if (frameworkElement != null)
{
Thickness currentMargin = frameworkElement.Margin;
frameworkElement.Margin = new Thickness(currentMargin.Left, (double)e.NewValue, currentMargin.Right, currentMargin.Bottom);
}
}
public static void SetTop(UIElement element, double value)
{
element.SetValue(TopProperty, value);
}
public static double GetTop(UIElement element)
{
return 0;
}
public static readonly DependencyProperty RightProperty = DependencyProperty.RegisterAttached(
"Right",
typeof(double),
typeof(Margin),
new PropertyMetadata(0.0, RightChanged));
private static void RightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var frameworkElement = d as FrameworkElement;
if (frameworkElement != null)
{
Thickness currentMargin = frameworkElement.Margin;
frameworkElement.Margin = new Thickness(currentMargin.Left, currentMargin.Top, (double)e.NewValue, currentMargin.Bottom);
}
}
public static void SetRight(UIElement element, double value)
{
element.SetValue(RightProperty, value);
}
public static double GetRight(UIElement element)
{
return 0;
}
public static readonly DependencyProperty BottomProperty = DependencyProperty.RegisterAttached(
"Bottom",
typeof(double),
typeof(Margin),
new PropertyMetadata(0.0, BottomChanged));
private static void BottomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var frameworkElement = d as FrameworkElement;
if (frameworkElement != null)
{
Thickness currentMargin = frameworkElement.Margin;
frameworkElement.Margin = new Thickness(currentMargin.Left, currentMargin.Top, currentMargin.Right, (double)e.NewValue);
}
}
public static void SetBottom(UIElement element, double value)
{
element.SetValue(BottomProperty, value);
}
public static double GetBottom(UIElement element)
{
return 0;
}
}
UWP:
public class Margin
{
public static readonly DependencyProperty LeftProperty = DependencyProperty.RegisterAttached(
"Left",
typeof(double),
typeof(Margin),
new PropertyMetadata(0.0));
public static void SetLeft(UIElement element, double value)
{
var frameworkElement = element as FrameworkElement;
if (frameworkElement != null)
{
Thickness currentMargin = frameworkElement.Margin;
frameworkElement.Margin = new Thickness(value, currentMargin.Top, currentMargin.Right, currentMargin.Bottom);
}
}
public static double GetLeft(UIElement element)
{
return 0;
}
public static readonly DependencyProperty TopProperty = DependencyProperty.RegisterAttached(
"Top",
typeof(double),
typeof(Margin),
new PropertyMetadata(0.0));
public static void SetTop(UIElement element, double value)
{
var frameworkElement = element as FrameworkElement;
if (frameworkElement != null)
{
Thickness currentMargin = frameworkElement.Margin;
frameworkElement.Margin = new Thickness(currentMargin.Left, value, currentMargin.Right, currentMargin.Bottom);
}
}
public static double GetTop(UIElement element)
{
return 0;
}
public static readonly DependencyProperty RightProperty = DependencyProperty.RegisterAttached(
"Right",
typeof(double),
typeof(Margin),
new PropertyMetadata(0.0));
public static void SetRight(UIElement element, double value)
{
var frameworkElement = element as FrameworkElement;
if (frameworkElement != null)
{
Thickness currentMargin = frameworkElement.Margin;
frameworkElement.Margin = new Thickness(currentMargin.Left, currentMargin.Top, value, currentMargin.Bottom);
}
}
public static double GetRight(UIElement element)
{
return 0;
}
public static readonly DependencyProperty BottomProperty = DependencyProperty.RegisterAttached(
"Bottom",
typeof(double),
typeof(Margin),
new PropertyMetadata(0.0));
public static void SetBottom(UIElement element, double value)
{
var frameworkElement = element as FrameworkElement;
if (frameworkElement != null)
{
Thickness currentMargin = frameworkElement.Margin;
frameworkElement.Margin = new Thickness(currentMargin.Left, currentMargin.Top, currentMargin.Right, value);
}
}
public static double GetBottom(UIElement element)
{
return 0;
}
}
Usage:
<TextBlock Text="Test"
app:Margin.Top="{Binding MyValue}"
app:Margin.Right="{StaticResource MyResource}"
app:Margin.Bottom="20" />
The nice thing is they won't override the other values on the Margin, so you can combine them as well.
user589195
Updated on June 01, 2022Comments
-
user589195 almost 2 years
I have a binding value that returns a int that represents a value I wasnt to assign to left and right margins of an element.
Heres what I've tried but it wont compile.
It works if I set the entire margin, but I only want left and right.
Xaml:
<Image x:Name="_image" Source="mat.png" Margin="{Binding EditorRow.BondIndent},0,{Binding EditorRow.BondIndent},0" />
class:
public int BondIndent { get { return _bondSequence * 5; } }
-
default over 11 yearsHow about returning a
Thickness
instead? -
user589195 over 11 yearsDefault as I have control over what is returned from the class behind. Please could you add an answer based on returning a thickness and I will mark as answer
-
default over 11 yearsadded an answer instead. HTH
-
-
default over 11 yearsHow does the OP use this valueconverter?
-
user589195 over 11 yearsCan the value converters be static and stored in another assembly?
-
odyss-jii over 11 yearsYou can have the definition of the converter class in another assembly. But you need an instance accessible from the XAML. Typically, you would create an instance like in the example above in the resources of an element (a UserControl element for example). You can define xml namespaces which refer to your assembly (and specific namespace) by adding
xmlns:xxx="clr-namespace:MyOtherAssembly.TheNamespace;assembly=MyOtherAssembly"
to the root node of the usercontrol or templated control. Replacexxx
which some appropriate name of course. -
default over 11 yearsA suggestion would be to use
as
operator instead ofis
+cast
-
Daniel over 11 years@odyss-jii Since the OP isn't using MVVM, I don't see a reason to decouple to this degree. The nature of his property assumes the DataContext for the view is making decisions about how things should look... Which means a better (simpler) solution would just be to return a Thickness.
-
odyss-jii over 11 years@Doc That may well be the case, but I wished to preserve the OP's data model.
-
user589195 over 11 yearsThanks for this odyss - Would of worked fine but since I have control of the return type from the class I am just returning a thickness instead of an int. Useful example for me on how to use valueconverter aswell.
-
Nicolas over 7 yearssetters and getters aren't called directly. You have to add a PropertyCallback to the DependencyProperty. I can't really believe, that you tested it :)
-
RandomEngy over 7 years@Nicolas msdn.microsoft.com/en-us/library/ms749011(v=vs.110).aspx Scroll down to "Custom Attached Properties" -> "How to create an attached property". They use naming conventions for the getter and setter methods and you don't need to supply a property callback on the DependencyProperty. We've been using this all over our code; it does work.
-
Nicolas over 7 yearsBlend and Visual Studio Designer use those functions, but WPF not. Those methods are just interesting to get/set the properties through the code behind...but you set those properties in XAML in your example (not code behind). Because WPF is managing the information, you should not put logic into those methods, besides setting and getting the information.
-
RandomEngy over 7 years@Nicolas Ahh, WPF works a bit differently. Added a version of the attached property that works there.