none
Polygon with Thumbs RRS feed

  • Question

  • Hi,
    i'm trying to make editable polygon and as long as it's my first steps with wpf, i don't get some things, why polygon corners doesn't match thumbs positions? Or may be i'm going to completly wrong direction?


    Code:

        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();

                var myPolygon = new CustomPolyLine(mainCanvas);

                myPolygon.AddThumb(mainCanvas.Width / 2, mainCanvas.Height / 2);
                myPolygon.AddThumb(mainCanvas.Width / 2, mainCanvas.Height / 2 + 100);
                myPolygon.AddThumb(mainCanvas.Width / 2 + 100, mainCanvas.Height / 2 + 100);

                myPolygon.Fill = Brushes.Blue;
                myPolygon.Stretch = Stretch.Fill;
                myPolygon.Stroke = Brushes.Black;
                myPolygon.StrokeThickness = 2;
                mainCanvas.Children.Add(myPolygon);           
            }              
        }


        public class CustomPolyLine : Shape
        {
            public CustomPolyLine(Canvas mainCanvas)
            {
                canvas = mainCanvas;
                Thumbs.CollectionChanged += Thumbs_CollectionChanged;
            }

            private readonly Canvas canvas;

            public void AddThumb(double x, double y)
            {
                var thumb = new Thumb();
                Canvas.SetLeft(thumb, x);
                Canvas.SetTop(thumb, y);
                thumb.Height = 10;
                thumb.Width = 10;
                thumb.Background = Brushes.Orange;
                thumb.DragDelta += thumb_DragDelta;
                thumb.Cursor = Cursors.Hand;
                Thumbs.Add(thumb);
                canvas.Children.Add(thumb);            
            }
          
            void Thumbs_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {            
                InvalidateMeasure();
            }

            void thumb_DragDelta(object sender, DragDeltaEventArgs e)
            {
                var thumb = (Thumb)sender;            
                double left = Canvas.GetLeft(thumb) + e.HorizontalChange;
                double top = Canvas.GetTop(thumb) + e.VerticalChange;
                Canvas.SetLeft(thumb, left);
                Canvas.SetTop(thumb, top);
                InvalidateMeasure();
            }

            public ObservableCollection<Thumb> Thumbs
            {
                get
                {
                    return
                    (ObservableCollection<Thumb>)GetValue(PointsProperty);
                }
                set
                {
                    SetValue(PointsProperty, value);
                }
            }

            public static readonly DependencyProperty PointsProperty =
            DependencyProperty.Register("PointsProperty",
            typeof(ObservableCollection<Thumb>), typeof(CustomPolyLine), new
            FrameworkPropertyMetadata(new ObservableCollection<Thumb>(),
            FrameworkPropertyMetadataOptions.AffectsRender |
            FrameworkPropertyMetadataOptions.AffectsMeasure));

            protected override Geometry DefiningGeometry
            {
                get
                {
                    var geometry = new StreamGeometry {FillRule = FillRule.Nonzero};

                    using (var context = geometry.Open())
                    {
                        GetGeometry(context);
                    }

                    geometry.Freeze();
                    return geometry;
                }
            }

            static Point PointFromThumb(Thumb thumb)
            {
                return new Point(Canvas.GetLeft(thumb), Canvas.GetTop(thumb));
            }

            void GetGeometry(StreamGeometryContext context)
            {
                context.BeginFigure(PointFromThumb(Thumbs[0]), true, false);

                foreach (var thumb in Thumbs)
                {
                    context.LineTo(PointFromThumb(thumb), true, true);
                }
                context.LineTo(PointFromThumb(Thumbs[0]), true, true);
            }
        } 

    Monday, December 8, 2008 8:12 PM

Answers

  • I found that the OnRender method is not triggled if the RenderSize does not change.
    Then we can find a trick to let your program work.
    Modify the rendersize in thumb_DragDelta();
    C#
            void thumb_DragDelta(object sender, DragDeltaEventArgs e) 
            { 
                var thumb = (Thumb)sender; 
                double ThumbLeft = Canvas.GetLeft(thumb); 
                double ThumbTop = Canvas.GetTop(thumb); 
                double left = ThumbLeft + e.HorizontalChange; 
                double top = ThumbTop + e.VerticalChange; 
                Canvas.SetLeft(thumb, left); 
                Canvas.SetTop(thumb, top); 
                InvalidateMeasure(); 
                Size s = this.RenderSize;  
                s.Height += 1; 
                s.Width += 1; 
                this.RenderSize = s;   
            } 


    Full code:
    C#
    using System; 
    using System.Collections.Generic; 
    using System.Collections.ObjectModel; 
    using System.Collections.Specialized; 
    using System.Linq; 
    using System.Text; 
    using System.Windows; 
    using System.Windows.Controls; 
    using System.Windows.Data; 
    using System.Windows.Documents; 
    using System.Windows.Input; 
    using System.Windows.Media; 
    using System.Windows.Media.Imaging; 
    using System.Windows.Navigation; 
    using System.Windows.Shapes; 
    using System.Windows.Controls.Primitives; 
     
    namespace PolygonwithThumbs_20081212 
        /// <summary> 
        /// Interaction logic for Window1.xaml 
        /// </summary> 
        public partial class Window1 : Window 
        { 
            private CustomPolyLine myPolygon; 
            public Window1() 
            { 
                InitializeComponent(); 
                myPolygon = new CustomPolyLine(mainCanvas); 
                myPolygon.InvalidateVisual(); 
                myPolygon.AddThumb(mainCanvas.Width / 2, mainCanvas.Height / 2); 
                myPolygon.AddThumb(mainCanvas.Width / 2, mainCanvas.Height / 2 + 100); 
                myPolygon.AddThumb(mainCanvas.Width / 2 + 100, mainCanvas.Height / 2 + 100); 
                myPolygon.HorizontalAlignment = HorizontalAlignment.Center; 
                myPolygon.VerticalAlignment = VerticalAlignment.Center; 
                myPolygon.Fill = Brushes.Blue;  
                myPolygon.Stroke = Brushes.Black; 
                myPolygon.StrokeThickness = 2
                mainCanvas.Children.Add(myPolygon); 
            } 
     
            private void Window_MouseDoubleClick(object sender, MouseButtonEventArgs e) 
            { 
                Point pointClicked = e.GetPosition(mainCanvas); 
                myPolygon.AddThumb(pointClicked.X, pointClicked.Y); 
            }  
        } 
     
        public class CustomPolyLine : Shape 
        { 
            private readonly Canvas canvas; 
            public CustomPolyLine(Canvas mainCanvas) 
            { 
                canvas = mainCanvas
                Thumbs.CollectionChanged += Thumbs_CollectionChanged; 
                Canvas.SetZIndex(this, -100); 
            } 
     
            protected override void OnRender(DrawingContext drawingContext) 
            { 
                base.OnRender(drawingContext); 
            } 
             
     
            public void AddThumb(double x, double y) 
            { 
                var thumb = new Thumb(); 
                Canvas.SetLeft(thumb, x); 
                Canvas.SetTop(thumb, y); 
                thumb.Height = 10
                thumb.Width = 10
                thumb.Background = Brushes.Orange; 
                thumb.DragDelta += thumb_DragDelta; 
                thumb.Cursor = Cursors.Hand; 
                thumb.InvalidateVisual(); 
                Thumbs.Add(thumb); 
                canvas.Children.Add(thumb); 
            } 
     
            void Thumbs_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
            { 
                InvalidateMeasure();  
            } 
     
     
            void thumb_DragDelta(object sender, DragDeltaEventArgs e) 
            { 
                var thumb = (Thumb)sender; 
                double ThumbLeft = Canvas.GetLeft(thumb); 
                double ThumbTop = Canvas.GetTop(thumb); 
                double left = ThumbLeft + e.HorizontalChange; 
                double top = ThumbTop + e.VerticalChange; 
                Canvas.SetLeft(thumb, left); 
                Canvas.SetTop(thumb, top); 
                InvalidateMeasure(); 
                Size s = this.RenderSize;  
                s.Height += 1; 
                s.Width += 1; 
                this.RenderSize = s;   
            } 
              
     
     
            public ObservableCollection<Thumb> Thumbs 
            { 
                get 
                { 
                    return 
                    (ObservableCollection<Thumb>)GetValue(PointsProperty); 
                } 
                set 
                { 
                    SetValue(PointsProperty, value); 
                } 
            } 
            public static readonly DependencyProperty PointsProperty = 
            DependencyProperty.Register("PointsProperty", 
            typeof(ObservableCollection<Thumb>), typeof(CustomPolyLine), new 
            FrameworkPropertyMetadata(new ObservableCollection<Thumb>(), 
            FrameworkPropertyMetadataOptions.AffectsRender | 
            FrameworkPropertyMetadataOptions.AffectsMeasure)); 
     
     
            protected override Geometry DefiningGeometry 
            { 
                get 
                { 
                    var geometry = new StreamGeometry { FillRuleFillRule = FillRule.Nonzero }; 
                    using (var context = geometry.Open()) 
                    { 
                        GetGeometry(context); 
                    } 
     
                    geometry.Freeze(); 
                    return geometry; 
                } 
            } 
     
     
            static Point PointFromThumb(Thumb thumb) 
            { 
                return new Point(Canvas.GetLeft(thumb) + 5, Canvas.GetTop(thumb) + 5); 
            } 
     
            protected override Size MeasureOverride(Size constraint) 
            { 
                double minx = double.PositiveInfinity; 
                double miny = double.PositiveInfinity; 
                double maxx = double.NegativeInfinity; 
                double maxy = double.NegativeInfinity; 
                foreach (var thumb in Thumbs) 
                { 
                    if (minx > Canvas.GetLeft(thumb)) 
                    { 
                        minx = Canvas.GetLeft(thumb); 
                    } 
                    if (maxx < Canvas.GetLeft(thumb)) 
                    { 
                        maxx = Canvas.GetLeft(thumb); 
                    } 
                    if (miny > Canvas.GetTop(thumb)) 
                    { 
                        miny = Canvas.GetTop(thumb); 
                    } 
                    if (maxy < Canvas.GetTop(thumb)) 
                    { 
                        maxy = Canvas.GetTop(thumb); 
                    } 
                } 
     
                return new Size(maxx - minx, maxy - miny); 
            } 
     
     
            void GetGeometry(StreamGeometryContext context) 
            { 
     
                context.BeginFigure(PointFromThumb(Thumbs[0]), true, false); 
     
                foreach (var thumb in Thumbs) 
                { 
                    context.LineTo(PointFromThumb(thumb), true, true); 
                } 
                context.LineTo(PointFromThumb(Thumbs[0]), true, true); 
     

                 
     
            } 
        }   
     

    • Marked as answer by Tao Liang Monday, December 15, 2008 1:17 AM
    Friday, December 12, 2008 4:16 AM

All replies

  • I've adjusted code little bit and now it's partly working, but there's a problem:
    when i move thumb so, that bounding rect is the same size as before moving (it's not easy to move it so in triangle, but if there's more corners, it's easier to find movements, when bounding rect size doesn't change), my polygon isn't redrawing.
    using System;  
    using System.Collections.Generic;  
    using System.Collections.ObjectModel;  
    using System.Collections.Specialized;  
    using System.Linq;  
    using System.Text;  
    using System.Windows;  
    using System.Windows.Controls;  
    using System.Windows.Controls.Primitives;  
    using System.Windows.Data;  
    using System.Windows.Documents;  
    using System.Windows.Input;  
    using System.Windows.Media;  
    using System.Windows.Media.Imaging;  
    using System.Windows.Navigation;  
    using System.Windows.Shapes;  
     
    namespace editPoly  
    {  
        /// <summary> 
        /// Interaction logic for Window1.xaml  
        /// </summary> 
        public partial class Window1 : Window  
        {  
            private CustomPolyLine myPolygon;  
            public Window1()  
            {  
                InitializeComponent();  
     
                myPolygon = new CustomPolyLine(mainCanvas);  
     
                myPolygon.AddThumb(mainCanvas.Width / 2, mainCanvas.Height / 2);  
                myPolygon.AddThumb(mainCanvas.Width / 2, mainCanvas.Height / 2 + 100);  
                myPolygon.AddThumb(mainCanvas.Width / 2 + 100, mainCanvas.Height / 2 + 100);  
     
                myPolygon.HorizontalAlignment = HorizontalAlignment.Center;  
                myPolygon.VerticalAlignment = VerticalAlignment.Center;  
                myPolygon.Fill = Brushes.Blue;  
                //myPolygon.Stretch = Stretch.Fill;  
                myPolygon.Stroke = Brushes.Black;  
                myPolygon.StrokeThickness = 2;  
                mainCanvas.Children.Add(myPolygon);             
            }  
     
            private void Window_MouseDoubleClick(object sender, MouseButtonEventArgs e)  
            {  
                Point pointClicked = e.GetPosition(mainCanvas);  
                myPolygon.AddThumb(pointClicked.X, pointClicked.Y);  
            }  
        }  
     
        public class CustomPolyLine : Shape  
        {  
            public CustomPolyLine(Canvas mainCanvas)  
            {  
                canvas = mainCanvas;  
                Thumbs.CollectionChanged += Thumbs_CollectionChanged;  
                Canvas.SetZIndex(this, -100);  
            }  
     
            private readonly Canvas canvas;  
     
            public void AddThumb(double x, double y)  
            {  
                var thumb = new Thumb();  
                Canvas.SetLeft(thumb, x);              
                Canvas.SetTop(thumb,y);  
                thumb.Height = 10;  
                thumb.Width = 10;  
                thumb.Background = Brushes.Orange;  
                thumb.DragDelta += thumb_DragDelta;  
                thumb.Cursor = Cursors.Hand;  
                Thumbs.Add(thumb);  
                canvas.Children.Add(thumb);  
            }  
     
            void Thumbs_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)  
            {  
                InvalidateMeasure();  
            }  
     
     
            void thumb_DragDelta(object sender, DragDeltaEventArgs e)  
            {  
                var thumb = (Thumb)sender;  
                double left = Canvas.GetLeft(thumb) + e.HorizontalChange;  
                double top = Canvas.GetTop(thumb) + e.VerticalChange;  
                Canvas.SetLeft(thumb, left);  
                Canvas.SetTop(thumb, top);  
                InvalidateMeasure();              
            }  
     
     
            public ObservableCollection<Thumb> Thumbs  
            {  
                get  
                {  
                    return  
                    (ObservableCollection<Thumb>)GetValue(PointsProperty);  
                }  
                set  
                {  
                    SetValue(PointsProperty, value);  
                }  
            }  
     
     
            public static readonly DependencyProperty PointsProperty =  
            DependencyProperty.Register("PointsProperty",  
            typeof(ObservableCollection<Thumb>), typeof(CustomPolyLine), new  
            FrameworkPropertyMetadata(new ObservableCollection<Thumb>(),  
            FrameworkPropertyMetadataOptions.AffectsRender |  
            FrameworkPropertyMetadataOptions.AffectsMeasure));  
     
     
            protected override Geometry DefiningGeometry  
            {  
                get  
                {  
                    var geometry = new StreamGeometry { FillRuleFillRule = FillRule.Nonzero };  
     
     
                    using (var context = geometry.Open())  
                    {  
                        GetGeometry(context);  
                    }  
     
                    geometry.Freeze();  
                    return geometry;  
                }  
            }  
     
     
            static Point PointFromThumb(Thumb thumb)  
            {  
                return new Point(Canvas.GetLeft(thumb) + 5, Canvas.GetTop(thumb) + 5);  
            }  
     
            protected override Size MeasureOverride(Size constraint)  
            {  
                double minx = double.PositiveInfinity;  
                double miny = double.PositiveInfinity;  
                double maxx = double.NegativeInfinity;  
                double maxy = double.NegativeInfinity;  
                foreach (var thumb in Thumbs)  
                {  
                    if (minx > Canvas.GetLeft(thumb))  
                    {  
                        minx = Canvas.GetLeft(thumb);  
                    }  
                    if (maxx < Canvas.GetLeft(thumb))  
                    {  
                        maxx = Canvas.GetLeft(thumb);  
                    }  
                    if (miny > Canvas.GetTop(thumb))  
                    {  
                        miny = Canvas.GetTop(thumb);  
                    }  
                    if (maxy < Canvas.GetTop(thumb))  
                    {  
                        maxy = Canvas.GetTop(thumb);  
                    }  
                }  
                  
                return new Size(maxx - minx, maxy - miny);  
            }  
              
     
            void GetGeometry(StreamGeometryContext context)  
            {              
                context.BeginFigure(PointFromThumb(Thumbs[0]), true, false);  
     
                foreach (var thumb in Thumbs)  
                {  
                    context.LineTo(PointFromThumb(thumb), true, true);  
                }  
                context.LineTo(PointFromThumb(Thumbs[0]), true, true);  
                  
            }  
        }   
     
    }  
     

     

    Tuesday, December 9, 2008 3:24 PM
  • I found that the OnRender method is not triggled if the RenderSize does not change.
    Then we can find a trick to let your program work.
    Modify the rendersize in thumb_DragDelta();
    C#
            void thumb_DragDelta(object sender, DragDeltaEventArgs e) 
            { 
                var thumb = (Thumb)sender; 
                double ThumbLeft = Canvas.GetLeft(thumb); 
                double ThumbTop = Canvas.GetTop(thumb); 
                double left = ThumbLeft + e.HorizontalChange; 
                double top = ThumbTop + e.VerticalChange; 
                Canvas.SetLeft(thumb, left); 
                Canvas.SetTop(thumb, top); 
                InvalidateMeasure(); 
                Size s = this.RenderSize;  
                s.Height += 1; 
                s.Width += 1; 
                this.RenderSize = s;   
            } 


    Full code:
    C#
    using System; 
    using System.Collections.Generic; 
    using System.Collections.ObjectModel; 
    using System.Collections.Specialized; 
    using System.Linq; 
    using System.Text; 
    using System.Windows; 
    using System.Windows.Controls; 
    using System.Windows.Data; 
    using System.Windows.Documents; 
    using System.Windows.Input; 
    using System.Windows.Media; 
    using System.Windows.Media.Imaging; 
    using System.Windows.Navigation; 
    using System.Windows.Shapes; 
    using System.Windows.Controls.Primitives; 
     
    namespace PolygonwithThumbs_20081212 
        /// <summary> 
        /// Interaction logic for Window1.xaml 
        /// </summary> 
        public partial class Window1 : Window 
        { 
            private CustomPolyLine myPolygon; 
            public Window1() 
            { 
                InitializeComponent(); 
                myPolygon = new CustomPolyLine(mainCanvas); 
                myPolygon.InvalidateVisual(); 
                myPolygon.AddThumb(mainCanvas.Width / 2, mainCanvas.Height / 2); 
                myPolygon.AddThumb(mainCanvas.Width / 2, mainCanvas.Height / 2 + 100); 
                myPolygon.AddThumb(mainCanvas.Width / 2 + 100, mainCanvas.Height / 2 + 100); 
                myPolygon.HorizontalAlignment = HorizontalAlignment.Center; 
                myPolygon.VerticalAlignment = VerticalAlignment.Center; 
                myPolygon.Fill = Brushes.Blue;  
                myPolygon.Stroke = Brushes.Black; 
                myPolygon.StrokeThickness = 2
                mainCanvas.Children.Add(myPolygon); 
            } 
     
            private void Window_MouseDoubleClick(object sender, MouseButtonEventArgs e) 
            { 
                Point pointClicked = e.GetPosition(mainCanvas); 
                myPolygon.AddThumb(pointClicked.X, pointClicked.Y); 
            }  
        } 
     
        public class CustomPolyLine : Shape 
        { 
            private readonly Canvas canvas; 
            public CustomPolyLine(Canvas mainCanvas) 
            { 
                canvas = mainCanvas
                Thumbs.CollectionChanged += Thumbs_CollectionChanged; 
                Canvas.SetZIndex(this, -100); 
            } 
     
            protected override void OnRender(DrawingContext drawingContext) 
            { 
                base.OnRender(drawingContext); 
            } 
             
     
            public void AddThumb(double x, double y) 
            { 
                var thumb = new Thumb(); 
                Canvas.SetLeft(thumb, x); 
                Canvas.SetTop(thumb, y); 
                thumb.Height = 10
                thumb.Width = 10
                thumb.Background = Brushes.Orange; 
                thumb.DragDelta += thumb_DragDelta; 
                thumb.Cursor = Cursors.Hand; 
                thumb.InvalidateVisual(); 
                Thumbs.Add(thumb); 
                canvas.Children.Add(thumb); 
            } 
     
            void Thumbs_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
            { 
                InvalidateMeasure();  
            } 
     
     
            void thumb_DragDelta(object sender, DragDeltaEventArgs e) 
            { 
                var thumb = (Thumb)sender; 
                double ThumbLeft = Canvas.GetLeft(thumb); 
                double ThumbTop = Canvas.GetTop(thumb); 
                double left = ThumbLeft + e.HorizontalChange; 
                double top = ThumbTop + e.VerticalChange; 
                Canvas.SetLeft(thumb, left); 
                Canvas.SetTop(thumb, top); 
                InvalidateMeasure(); 
                Size s = this.RenderSize;  
                s.Height += 1; 
                s.Width += 1; 
                this.RenderSize = s;   
            } 
              
     
     
            public ObservableCollection<Thumb> Thumbs 
            { 
                get 
                { 
                    return 
                    (ObservableCollection<Thumb>)GetValue(PointsProperty); 
                } 
                set 
                { 
                    SetValue(PointsProperty, value); 
                } 
            } 
            public static readonly DependencyProperty PointsProperty = 
            DependencyProperty.Register("PointsProperty", 
            typeof(ObservableCollection<Thumb>), typeof(CustomPolyLine), new 
            FrameworkPropertyMetadata(new ObservableCollection<Thumb>(), 
            FrameworkPropertyMetadataOptions.AffectsRender | 
            FrameworkPropertyMetadataOptions.AffectsMeasure)); 
     
     
            protected override Geometry DefiningGeometry 
            { 
                get 
                { 
                    var geometry = new StreamGeometry { FillRuleFillRule = FillRule.Nonzero }; 
                    using (var context = geometry.Open()) 
                    { 
                        GetGeometry(context); 
                    } 
     
                    geometry.Freeze(); 
                    return geometry; 
                } 
            } 
     
     
            static Point PointFromThumb(Thumb thumb) 
            { 
                return new Point(Canvas.GetLeft(thumb) + 5, Canvas.GetTop(thumb) + 5); 
            } 
     
            protected override Size MeasureOverride(Size constraint) 
            { 
                double minx = double.PositiveInfinity; 
                double miny = double.PositiveInfinity; 
                double maxx = double.NegativeInfinity; 
                double maxy = double.NegativeInfinity; 
                foreach (var thumb in Thumbs) 
                { 
                    if (minx > Canvas.GetLeft(thumb)) 
                    { 
                        minx = Canvas.GetLeft(thumb); 
                    } 
                    if (maxx < Canvas.GetLeft(thumb)) 
                    { 
                        maxx = Canvas.GetLeft(thumb); 
                    } 
                    if (miny > Canvas.GetTop(thumb)) 
                    { 
                        miny = Canvas.GetTop(thumb); 
                    } 
                    if (maxy < Canvas.GetTop(thumb)) 
                    { 
                        maxy = Canvas.GetTop(thumb); 
                    } 
                } 
     
                return new Size(maxx - minx, maxy - miny); 
            } 
     
     
            void GetGeometry(StreamGeometryContext context) 
            { 
     
                context.BeginFigure(PointFromThumb(Thumbs[0]), true, false); 
     
                foreach (var thumb in Thumbs) 
                { 
                    context.LineTo(PointFromThumb(thumb), true, true); 
                } 
                context.LineTo(PointFromThumb(Thumbs[0]), true, true); 
     

                 
     
            } 
        }   
     

    • Marked as answer by Tao Liang Monday, December 15, 2008 1:17 AM
    Friday, December 12, 2008 4:16 AM