Is there way to bind Point structure coordinates in XAML? For example, I want to create a triangle, which has points depended on control width and height.
<Polygon>
<Polygon.Points>
<Point X="{Binding ElementName=control, Path=ActualWidth}" Y="{Binding ElementName=control, Path=ActualHeight}"/>
</Polygon.Points>
</Polygon>
Error:
A 'Binding' cannot be set on the 'X' property of type 'Point'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
I can't use inheritance, because Point type is a structure. I tried to create PointCollection property binding, but it wasn't working well.
Here you go
I attempted to solve the triangle with two approach
result

Viewbox approach
if you are interested in rendering a triangle of size of a control then this could be your choice
<Grid>
<Viewbox Stretch="Fill">
<Path Data="M 1.5,0 L 3,3 0,3 Z"
Width="3" Height="3"
Fill="Gray" />
</Viewbox>
</Grid>
above approach will render a triangle and will resize to the size of the parent control via Viewbox, additionally you can add a rotation transform to path and rotate the triangle as per your needs.
this approach is recommended if you simply need a triangle no matter how
Polygon using Converter
<Grid xmlns:l="clr-namespace:CSharpWPF"
x:Name="control">
<Grid.Resources>
<l:ElementToTrianglePointsConverter x:Key="ElementToTrianglePointsConverter" />
</Grid.Resources>
<Polygon Points="{Binding ElementName=control, Converter={StaticResource ElementToTrianglePointsConverter}}"
FillRule="Nonzero"
Fill="Gray" />
</Grid>
converter
namespace CSharpWPF
{
public class ElementToTrianglePointsConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
FrameworkElement element = value as FrameworkElement;
PointCollection points = new PointCollection();
Action fillPoints = () =>
{
points.Clear();
points.Add(new Point(element.ActualWidth / 2, 0));
points.Add(new Point(element.ActualWidth, element.ActualHeight));
points.Add(new Point(0, element.ActualHeight));
};
fillPoints();
element.SizeChanged += (s, ee) => fillPoints();
return points;// store;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
above approach is little buggy, I always have to re-size the window it before I can see the triangle. I can see it by default at design time but not at runtime unless i resize the window. although polygon have points in it but not rendered, not sure why? need to investigate the issue
u can use MultiBinding and converter.
it may looks like this:
<Window x:Class="WpfApplication13.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local ="clr-namespace:WpfApplication13"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:converter x:Key="pointConverter" />
</Window.Resources>
<Grid x:Name="control" >
<Polygon Fill="Black" Stroke="Black">
<Polygon.Points>
<MultiBinding Converter="{StaticResource pointConverter}" >
<Binding Path="ActualWidth" ElementName="control"/>
<Binding Path="ActualHeight" ElementName="control"/>
</MultiBinding>
</Polygon.Points>
</Polygon>
</Grid>
</Window>
or you can do it in background:
public MainWindow()
{
InitializeComponent();
MultiBinding mb = new MultiBinding();
Binding bind = new Binding("ActualWidth");
bind.Source = control;
mb.Bindings.Add(bind);
bind = new Binding("ActualHeight");
bind.Source = control;
mb.Bindings.Add(bind);
mb.Converter = new converter();
pg.SetBinding(Polygon.PointsProperty, mb);
}
class converter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
double width = (double)values[0];
double height = (double)values[1];
PointCollection pc = new PointCollection();
pc.Add(new Point(0, 0));
pc.Add(new Point(width - 10, height - 10));
return pc;
}
catch
{
return null;
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With