我正在尝试在画布上绘制一条折线,该画布的每个点都将具有矩形。折线绑定到ViewModel中的点集合。
当我尝试为每个点设置DataTemplate
(如下所示)时,它在折线点上都没有显示矩形。
有什么方法可以在折线点上显示矩形?
稍后,我想通过拖动这些点来调整折线。
<Polyline Points="{Binding EdgePoints, Converter={StaticResource pointCollectionConverter}}" StrokeThickness="2">
<Polyline.Resources>
<DataTemplate DataType="{x:Type Point}">
<Rectangle Width="20" Height="20" Fill="Black"/>
</DataTemplate>
</Polyline.Resources>
</Polyline>
这里是我要绘制矩形的示例。
答案 0 :(得分:1)
您可能具有如下所示的视图模型。除了明显的部分外,它还向每个Vertex
附加/分离一个PropertyChanged处理程序,以触发Vertices
属性的PropertyChanged事件。这是更新折线的点绑定所必需的。
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Vertex : ViewModelBase
{
private Point point;
public Point Point
{
get { return point; }
set { point = value; OnPropertyChanged(); }
}
}
public class ViewModel : ViewModelBase
{
public ViewModel()
{
Vertices.CollectionChanged += VerticesCollectionChanged;
}
public ObservableCollection<Vertex> Vertices { get; }
= new ObservableCollection<Vertex>();
private void VerticesCollectionChanged(
object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (var item in e.NewItems.OfType<INotifyPropertyChanged>())
{
item.PropertyChanged += VertexPropertyChanged;
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var item in e.OldItems.OfType<INotifyPropertyChanged>())
{
item.PropertyChanged -= VertexPropertyChanged;
}
}
OnPropertyChanged(nameof(Vertices));
}
private void VertexPropertyChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged(nameof(Vertices));
}
}
“顶点到PointCollection”转换器看起来像这样:
public class VerticesConverter : IValueConverter
{
public object Convert(
object value, Type targetType, object parameter, CultureInfo culture)
{
var vertices = value as IEnumerable<Vertex>;
return vertices != null
? new PointCollection(vertices.Select(v => v.Point))
: null;
}
public object ConvertBack(
object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
该视图将使用折线和ItemsControl。 ItemsTemplate将声明一个Thumb
元素来处理顶点的拖动。
<Canvas>
<Canvas.Resources>
<local:VerticesConverter x:Key="VerticesConverter"/>
<Style x:Key="ThumbStyle" TargetType="Thumb">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Rectangle Fill="Transparent" Stroke="Red"
Width="10" Height="10" Margin="-5,-5"/>
</ControlTemplate>
</Setter.Value>
</Setter>
<EventSetter Event="DragDelta" Handler="ThumbDragDelta"/>
</Style>
</Canvas.Resources>
<Polyline Points="{Binding Vertices, Converter={StaticResource VerticesConverter}}"
Stroke="DarkBlue" StrokeThickness="3" StrokeLineJoin="Round"/>
<ItemsControl ItemsSource="{Binding Vertices}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Point.X}"/>
<Setter Property="Canvas.Top" Value="{Binding Point.Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Thumb Style="{StaticResource ThumbStyle}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
最后,Thumb的DragDelta处理程序:
private void ThumbDragDelta(object sender, DragDeltaEventArgs e)
{
var vertex = (Vertex)((Thumb)sender).DataContext;
vertex.Point = new Point(
vertex.Point.X + e.HorizontalChange,
vertex.Point.Y + e.VerticalChange);
}