Why is a Line shape on a Canvas drifting away whil

2019-03-01 19:04发布

I see a strange behaviour dragging in Line shape over a Canvas that I cannot explain. The Line shape is in a Thumb DataTemplate like so:

<DataTemplate DataType="{x:Type vm:MyLine}">
    <Thumb DragDelta="Thumb_DragDelta">
        <Thumb.Template>
            <ControlTemplate TargetType="Thumb">
                <Line Fill="LightBlue" StrokeThickness="2" Y1="{Binding Y1}" Y2="{Binding Y2}" X1="{Binding X1}" X2="{Binding X2}" Stroke="LightBlue" x:Name="Line"/>
            </ControlTemplate>
        </Thumb.Template>
    </Thumb>
</DataTemplate>

The Canvas is ItemsPanelTemplate of a ListBox. In the ListBox.ItemContainerStyle there is no Canvas.Top or Canvas.Left Binding or Setter. Also no Binding for Width and Height.

The Line on the Canvs is dragging but it drifts away from the mouse position. Fairly wild and quick.

In code behind the dragging has the effect:

line.X1 += e.HorizontalChange; line.X2 += e.HorizontalChange;
line.Y1 += e.VerticalChange; line.Y2 += e.VerticalChange;

The setters for X..Y raise PropertyChanged otherwise the Line wouldn't move.

What should I do for a proper dragging behaviour for Line and why?
Binding Mode=OneWay makes no difference.

2条回答
Luminary・发光体
2楼-- · 2019-03-01 19:47

It turns out that the Line shape behaves somewhat different from the Ellipse shape when added to a Thumb. The Thumb fires in its DragDelta event the total displacment of the mouse w.r.t. the position where the left button was pressed when the dragging started.

For an ellipse this is ok, because internally, the EllipseGeometry of the Ellipse shape is stretched to fill Rectangle that is positioned on the Canvas with Canvas.Left, Canvas.Top, Width and Height. Apparantly the total displacement is the correct value to animate the dragging of the ellipse on the canvas.

For a Line the correct value to animate the dragging of the ellipse on the canvas is the difference of the displacement between two consecutive DragDelta events. A Line is drawn on the basis of X1, X2, Y1, Y2 properties of an internal LineGeometry. The Rectangle of its GeometryBounds are ignored (although the line is clipped beyond this border). The Line's Canvas.Left=Canvas.Top can then be set to 0 and Width and Height equal to the ActualHeight and ActualWidth of the Canvas.

One could also create an own Ellipse shape with a Center and Radius property. Such a shape then would behave like the Line shape.

What I did is create a ThumbShape as a base class, copying code from Thumb.cs of MS. Therfore I also had to copy the corresponding EventArgs classes and EventHandler delegates. I added to the DragDelta eventarguments a relative mouse change so that I can choose whether to use the relative offset or the total offset of the dragging.

查看更多
We Are One
3楼-- · 2019-03-01 20:09

I had the same problem and after this answer "For a Line the correct value to animate the dragging of the ellipse on the canvas is the difference of the displacement between two consecutive DragDelta events." I developed this solution, worked for me, hope this helps someone

 public class Connector : Thumb
{
    private double _oldX = 0;
    private double _oldY = 0;


    public Connector()
    {
        DragDelta += Connector_DragDelta;
        DragCompleted += Connector_DragCompleted;
    }

    private void Connector_DragCompleted(object sender, DragCompletedEventArgs e)
    {
        _oldX = 0;
        _oldY = 0;
    }

    private void Connector_DragDelta(object sender, DragDeltaEventArgs e)
    {
        Thumb thumb = e.Source as Thumb;
        DiagramConnectorViewModel viewModel = (DiagramConnectorViewModel)thumb.DataContext;

        double leftOffSet = _oldX - e.HorizontalChange;
        _oldX = e.HorizontalChange;
        viewModel.X1 -= leftOffSet;
        viewModel.X2 -= leftOffSet;

        double topOffSet = _oldY - e.VerticalChange;
        _oldY = e.VerticalChange;
        viewModel.Y1 -= topOffSet;
        viewModel.Y2 -= topOffSet;

    }
查看更多
登录 后发表回答