Creating a bindable Point in C# WPF

旧时模样 提交于 2019-12-03 14:59:30

Unfortunately, Point is a struct, and structs don't support inheritance. From MSDN

Note Structs do not support inheritance, but they can implement interfaces. For more information, see Interfaces (C# Programming Guide).

Maybe this doesn't answer your question directly but you can easily bind a Point with the help of a Converter. In your case it would be like

<SomeControl.SomePointProperty>
    <MultiBinding Converter="{StaticResource PointConverter}">
        <Binding ElementName="ParentControlName"
                 Path="Width"/>
        <Binding ElementName="ParentControlName"
                 Path="Height"/>
    </MultiBinding>                                        
</SomeControl.SomePointProperty>

PointConverter

public class PointConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double xValue = (double)values[0];
        double yValue = (double)values[1];
        return new Point(xValue, yValue);
    }
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

If you just want to bind the X value and have a static Y value you could do this like

<SomeControl SomePointProperty="{Binding Path=Width,
                                         ElementName=ParentControlName,
                                         Converter={StaticResource PointXConverter},
                                         ConverterParameter=20}"/>

PointXConverter

public class PointXConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double progressBarValue = (double)value;
        double yValue = System.Convert.ToDouble(parameter);
        return new Point(progressBarValue, yValue);
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
} 

Try to use Converters instead.

You may have to reimplement all the classes (Point, Polygon, Line etc.) from scratch, because Point is a structure, therefore it doesn't support inheritance (which also explains why Point does not support binding: it cannot inherit DependencyObject, which contains the necessary infrastructure for DPs).

There might be a way though - you could create a subclass of polygon and add a new DependencyProperty called "BindablePoints" which would be an observable collection (you would have to create a custom OC that would fire CollectionChanged when one of the points changed) of the points. The property would in its OnChanged update the main Points property of the Polygon.

I guess this could work, but I'm not sure whether it would be fast enough for whatever you are trying to do. Tou would still have to create subclasses of all the shapes you would want to use, but you wouldn't have to create them all from scratch.

  1. Write a wrapper class for point which implements the INotifyPropertyChanged interface

    public class BindingPoint : INotifyPropertyChanged
    {
        private Point point;
    
        public BindingPoint(double x, double y)
        {
            point = new Point(x, y);
        }
    
        public double X
        {
            get { return point.X; }
            set
            {
                point.X = value;
                OnPropertyChanged();
                OnPropertyChanged("Point");
            }
        }
    
        public double Y
        {
            get { return point.Y; }
            set
            {
                point.Y = value;
                OnPropertyChanged();
                OnPropertyChanged("Point");
            }
        }
    
        public Point Point
        {
            get { return point; }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    
  2. Bind startpoint / endPoint X and Y properties for example to a line instance

    Line line = new Line();
    BindingPoint startPoint = new BindingPoint(0,0);
    BindingPoint endPoint = new BindingPoint(0,0);
    
    var b = new Binding("X")
    {
        Source = startPoint,
        Mode = BindingMode.TwoWay
    };
    line.SetBinding(Line.X1Property, b);
    
    b = new Binding("Y")
    {
        Source = startPoint,
        Mode = BindingMode.TwoWay
    };
    line.SetBinding(Line.Y1Property, b);
    
    b = new Binding("X")
    {
        Source = endPoint,
        Mode = BindingMode.TwoWay
    };
    line.SetBinding(Line.X2Property, b);
    
    b = new Binding("Y")
    {
        Source = endPoint,
        Mode = BindingMode.TwoWay
    };
    line.SetBinding(Line.Y2Property, b);
    
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!