Changing a Polygon's Points

青春壹個敷衍的年華 提交于 2019-12-05 19:12:22

I was not being satisfied with the previous answer I gave as it is after all a workaround..

I found a better solution to the problem which will not require to reset the databinds.

So the binding from XAML is being directed to a property with INCC however the data itself is converted to Points for the polygon to use when drawing.

<Window x:Class="WpfApplication9.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication9"
    Title="MainWindow" Height="350" Width="525" LocationChanged="Window_LocationChanged" >
<Window.Resources>
    <local:MyPointCollectionConverter x:Key="mcolconv" />
</Window.Resources>
<Canvas>
    <Polygon Name="SpeechPoly" Stroke="Black" StrokeThickness="2" 
             Points="{Binding Path=myPointCollection, Converter={StaticResource mcolconv}}" />
</Canvas>

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;

namespace WpfApplication9
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private ObservableCollection<Point> _myPointCollection = new ObservableCollection<Point>();
    public ObservableCollection<Point> myPointCollection { get { return _myPointCollection; } }

    public MainWindow()
    {
        myPointCollection.Add(new Point(100, 50));
        myPointCollection.Add(new Point(150, 100));
        myPointCollection.Add(new Point(50, 100));
        InitializeComponent();
        DataContext = this;
    }

    private void ResetPolygon(Point Point1, Point Point2, Point Point3)
    {
        myPointCollection.Clear();
        myPointCollection.Add(Point1);
        myPointCollection.Add(Point2);
        myPointCollection.Add(Point3);
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs("myPointCollection"));
    }

    private void Window_LocationChanged(object sender, EventArgs e)
    {
        if (this.IsLoaded)
        {
            Random rnd = new Random();
            Point Point1 = new Point(rnd.Next(50, 200), rnd.Next(50, 200));
            Point Point2 = new Point(rnd.Next(50, 200), rnd.Next(50, 200));
            Point Point3 = new Point(rnd.Next(50, 200), rnd.Next(50, 200));
            ResetPolygon(Point1, Point2, Point3);
        }

    }
}

public class MyPointCollectionConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var regPtsColl = new PointCollection(); //regular points collection.
        var obsPtsColl = (ObservableCollection<Point>)value; //observable which is used to raise INCC event.
        foreach (var point in obsPtsColl)
            regPtsColl.Add(point);
        return regPtsColl;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }

    #endregion
}
}

The PointsCollection is not using the INotifyCollectionChanged..
so binding will never know that somthing has changed.

You can go around this by refreshing the binding.

Here is an example that do what you asked for:

<Window x:Class="WpfApplication9.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525" LocationChanged="Window_LocationChanged" >
<Canvas>
    <Polygon Name="SpeechPoly" Stroke="Black" StrokeThickness="2" Points="{Binding Path=myPointCollection}" />
</Canvas>

using System;
using System.Windows;
using System.Windows.Media;

namespace WpfApplication9
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public PointCollection myPointCollection { get; set; }

    public MainWindow()
    {
        myPointCollection = new PointCollection
        {
            new Point(100, 50),
            new Point(150, 100),
            new Point(50, 100)
        };
        InitializeComponent();
        DataContext = this;
    }

    private void ResetPolygon(Point Point1, Point Point2, Point Point3)
    {
        myPointCollection[0] = Point1;
        myPointCollection[1] = Point2;
        myPointCollection[2] = Point3;
        DataContext = null;
        DataContext = this;
    }

    private void Window_LocationChanged(object sender, EventArgs e)
    {
        if (this.IsLoaded)
        {
            Random rnd = new Random();
            Point Point1 = new Point(rnd.Next(50, 200), rnd.Next(50, 200));
            Point Point2 = new Point(rnd.Next(50, 200), rnd.Next(50, 200));
            Point Point3 = new Point(rnd.Next(50, 200), rnd.Next(50, 200));
            ResetPolygon(Point1, Point2, Point3);
        }

    }
}

}
GameAlchemist

Well what you do in the Window_LocationChanged handler, is to add points so no wonder you end up with more polygons. Your myPointCollection must be an ObservableCollection, and you must clear the collection before adding the points. I was wondering also if you could use a class inheriting from Point (System.Windows.Point) but overloading x and y to NotifyingPropertyChanged them so the binding can update. If it works, you don't have to change the Collection any more, but the Collection content.

Edit after update:

It looks like the problem is in your update: since you update it with the same Collection no update occurs.
This is perfectly normal behaviour since the Collection (a PointCollection) does not implement CollectionChanged, so even if you clear it, all that the clr 'sees' is the same object, so no change, hence no update.

You should NOT modify(clear) the point collection of the Xaml Polygon object itself, since the binding is enough.

  1. Try creating a new PointCollection each time, add the points, and assign the list to the Polygon Points .

  2. OR try to make notifying points and change the points. Maybe you can notify both X and Y with empty string "" which means everything changed, OR notify X with "X" and Y with "Y".

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!