代码使用Path
创建多边形。每次用户双击它时,它会关闭多边形并为第二个多边形添加另一个Path
对象,依此类推。我正在使用PointsToPathConverter
将Point
转换为Path
想要的集合。
这些积分已添加到Areas
集合中,但出于某种原因,OnPropertyChanged("Areas");
未更新ItemsControl
。可能是什么原因?
XAML
<ItemsControl ItemsSource="{Binding Areas}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Path Data="{Binding Path=., Converter={StaticResource ResourceKey=PointsToPathConverter}}" Stroke="Black" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
视图模型
public class VM : INotifyPropertyChanged
{
private ICommand _addPointCommand;
public ICommand AddPointCommand
{
get
{
if (_addPointCommand == null)
{
_addPointCommand = new RelayCommand<MouseButtonEventArgs>(AddPoint);
}
return _addPointCommand;
}
}
private ObservableCollection<List<Point>> _areas { get; set; }
public ObservableCollection<List<Point>> Areas
{
get
{
if (_areas == null)
{
_areas = new ObservableCollection<List<Point>>();
}
return _areas;
}
}
public VM()
{
Areas = new ObservableCollection<List<Point>>();
Areas.Add(new List<Point>());
}
private void AddPoint(MouseButtonEventArgs e)
{
var curPoints = Areas[Areas.Count - 1];
curPoints.Add(e.GetPosition((IInputElement)e.Source));
if (e.ClickCount == 2 && curMaskPoints.Count > 0)
{
curMaskPoints.Add(curMaskPoints[0]);
Areas.Add(new List<Point>());
}
OnPropertyChanged("Areas");
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
public class PointsToPathConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var points = (value as List<Point>);
if (points.Count > 0)
{
Point start = points[0];
List<LineSegment> segments = new List<LineSegment>();
for (int i = 1; i < points.Count; i++)
{
segments.Add(new LineSegment(points[i], true));
}
PathFigure figure = new PathFigure(start, segments, false); //true if closed
PathGeometry geometry = new PathGeometry();
geometry.Figures.Add(figure);
return geometry;
}
else
{
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
#endregion
}
B'/ P>
答案 0 :(得分:1)
这是解决方法。使嵌套集合可观察无济于事。您需要将嵌套集合替换为任一类型的新集合 - 包含相同的点集。您使用哪种类型的集合并不重要。只需要是一个不同的集合对象实例。
private void AddPoint(MouseButtonEventArgs e)
{
var curPoints = Areas[Areas.Count - 1];
curPoints.Add(e.GetPosition((IInputElement)e.Source));
// ** fix **
Areas[Areas.Count - 1] = new List<Point>(curPoints);
// ** end fix **
if (e.ClickCount == 2 && curMaskPoints.Count > 0)
{
curMaskPoints.Add(curMaskPoints[0]);
Areas.Add(new List<Point>());
}
}
由于同样的原因,Rufo先生更受尊敬的解决方案会做同样的事情:它只是通过不同的机制强制通知发生。
答案 1 :(得分:1)
问题的原因在这里
<Path Data="{Binding Path=., Converter={StaticResource ResourceKey=PointsToPathConverter}}" Stroke="Black" />
要更新Path.Data
,必须有通知。
将代码修改为
public class ObservableArea : GalaSoft.MvvmLight.ObservableObject
{
public ObservableArea()
{
Points = new ObservableCollection<Point>();
Points.CollectionChanged += ( s, e ) => RaisePropertyChanged( nameof( Points ) );
}
public ObservableCollection<Point> Points { get; }
}
public class VM : INotifyPropertyChanged
{
private ICommand _addPointCommand;
public ICommand AddPointCommand
{
get
{
if (_addPointCommand == null)
{
_addPointCommand = new RelayCommand<MouseButtonEventArgs>(AddPoint);
}
return _addPointCommand;
}
}
private ObservableCollection<ObservableArea> _areas { get; set; }
public ObservableCollection<ObservableArea> Areas
{
get
{
if (_areas == null)
{
_areas = new ObservableCollection<ObservableArea>();
}
return _areas;
}
}
public VM()
{
Areas = new ObservableCollection<ObservableArea>();
Areas.Add(new ObservableArea());
}
private void AddPoint(MouseButtonEventArgs e)
{
var curPoints = Areas[Areas.Count - 1];
curPoints.Points.Add(e.GetPosition((IInputElement)e.Source));
if (e.ClickCount == 2 && curMaskPoints.Count > 0)
{
curMaskPoints.Add(curMaskPoints[0]);
Areas.Add(new ObservableArea());
}
// useless and can be removed
// OnPropertyChanged("Areas");
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
和XAML到
<ItemsControl ItemsSource="{Binding Areas}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Path Data="{Binding Path=Points, Converter={StaticResource ResourceKey=PointsToPathConverter}}" Stroke="Black" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
作为一个证明,为什么提升PropertyChanged
事件对于价值没有改变的房产是无用的:
Areas
绑定到ItemsControl.ItemsSource
属性DependencyProperty
(have a look at the Reference Source),控制演示的更改只会在值的实际更改时发生,因为DP逻辑本身将比较新旧值,如果不相等,则它将调用PropertyChangedCallback(参见参考源中的ItemsControl.OnItemsSourceChanged
)。
每当引发PropertyChanged
事件时,绑定将分配值,但如果值与旧值相同,则不再有操作。
using System;
using System.Windows;
public class Program
{
public static void Main()
{
var foo = new Foo();
Console.WriteLine( "Set foo.Bar to 1" );
foo.Bar = 1;
Console.WriteLine( "Set foo.Bar to 1 (assigning the same value)" );
foo.Bar = 1;
Console.WriteLine( "Set foo.Bar to 2" );
foo.Bar = 2;
}
}
public class Foo : DependencyObject
{
public int Bar
{
get { return (int) GetValue( BarProperty ); }
set { SetValue( BarProperty, value ); }
}
public static readonly DependencyProperty BarProperty =
DependencyProperty.Register(
"Bar",
typeof( int ),
typeof( Foo ),
new PropertyMetadata(
defaultValue: 0,
propertyChangedCallback: new PropertyChangedCallback( OnBarChanged ) ) );
private static void OnBarChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
Console.WriteLine( "OnBarChanged: Property has changed from '{0}' to '{1}'", e.OldValue, e.NewValue );
}
}