In order to bind the Polyline Points attribute to your viewmodel successfully (i.e. to have it update when the bound PointCollection changes), you should avoid changing the PointCollection as a collection (Clear, Add, etc). The Polyline will not notice that, even binding to an ObservableCollection of Points with a custom converter will not help.
Instead, you should consider your PointCollection as a property: set it with a newly created PointCollection, and fire a NotifyPropertyChanged event:
即Polyline需要通过PointCollection赋值,而不是Add方法,才能出发属性修改通知。
private PointCollection points = new PointCollection();
public PointCollection Points
{
get { return points; }
set
{
points = value;
NotifyPropertyChanged("Points");
}
}
public void SomeUpdateFunc()
{
PointCollection pc = new PointCollection();
// Do some adding: pc.Add(new Point(x, y)); etc
this.Points = pc; // set via the setter, so the notification will fire
}
<Window x:Class="Polygon.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Polygon"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Canvas Grid.Row="0" Name="canvas" MouseMove="canvas_MouseMove" MouseLeftButtonDown="canvas_MouseLeftButtonDown" MouseRightButtonDown="canvas_MouseRightButtonDown" Background="#FF4787E8">
<Polygon Name="polyline" Points="{Binding Points}" Stroke="Red" StrokeThickness="3">
</Polygon>
</Canvas>
<Button Content="Set new points" Click="btnSetNew" Grid.Row="1"/>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
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;
namespace Polygon
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
bool flag = false;
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
if (flag == false)
return;
pointsCache[pointsCache.Count - 1] = e.GetPosition(canvas);
PointCollection localPoints = new PointCollection();
foreach (var item in pointsCache)
{
localPoints.Add(item);
}
this.Points = localPoints;
}
private void canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
PointCollection localPoints = new PointCollection();
flag = true;
pointsCache.Add(e.GetPosition(canvas));
if (pointsCache.Count == 1)
pointsCache.Add(e.GetPosition(canvas));
foreach (var item in pointsCache)
{
localPoints.Add(item);
}
this.Points = localPoints;
Console.WriteLine("Left Down: " + e.GetPosition(canvas));
}
private void canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
flag = false;
pointsCache.Clear();
Console.WriteLine("Right Down: " + e.GetPosition(canvas));
}
public event PropertyChangedEventHandler PropertyChanged;
PointCollection pointsCache = new PointCollection();
PointCollection points = new PointCollection();
public PointCollection Points
{
get
{
return this.points;
}
set
{
if (this.points != value)
{
this.points = value;
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Points"));
}
}
}
}
private void btnSetNew(object sender, RoutedEventArgs e)
{
this.Points = new PointCollection(
new[] { new Point(23, 2), new Point(12, 556), new Point(4, 89) });
}
}
}
参考文章: