Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding polygon points in XAML

Tags:

c#

binding

wpf

xaml

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.

like image 439
vdrake6 Avatar asked Jul 12 '26 05:07

vdrake6


2 Answers

Here you go

I attempted to solve the triangle with two approach

result

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

like image 83
pushpraj Avatar answered Jul 13 '26 18:07

pushpraj


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();
        }
    }
like image 26
Rang Avatar answered Jul 13 '26 17:07

Rang



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!