简体   繁体   English

C#WPF如何在折线点上绘制矩形

[英]C# wpf how to draw rectangle on polyline points

I am trying to draw a polyline on a canvas which will have rectangle on each point. 我正在尝试在画布上画一条折线,在每个点上都将具有矩形。 The Polyline is bound to a collection of points from the ViewModel. 折线绑定到ViewModel中的点集合。

When I try to set DataTemplate for each point (like below) it shows no rectangle on polyline points. 当我尝试为每个点设置DataTemplate时(如下所示),它在折线点上没有显示矩形。

Is there some way to display rectangle on polyline points? 有什么办法可以在折线点上显示矩形?

Later I want to adjust the polyline by dragging these points. 稍后,我想通过拖动这些点来调整折线。

<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>

Here is example where I want to draw rectangles. 这是我要绘制矩形的示例。

例

You could have a view model like the one shown below. 您可能具有如下所示的视图模型。 Besides the obvious parts, it attaches/detaches a PropertyChanged handler to/from each Vertex in order to fire the PropertyChanged event for the Vertices property. 除了明显的部分外,它还会向每个Vertex附加/分离一个PropertyChanged处理程序,以触发Vertices属性的PropertyChanged事件。 This is necessary to update the Polyline's Point Binding. 这是更新折线的点绑定所必需的。

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));
    }
}

The Vertices to PointCollection converter could look like this: 顶点到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();
    }
}

The view would use a Polyline and an ItemsControl. 该视图将使用折线和ItemsControl。 The ItemsTemplate would declare a Thumb element that handles the dragging of vertex points. 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>

Finally, the Thumb's DragDelta handler: 最后,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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM