是什么导致WPF DragDelta值在每次调用时突然累积?

时间:2019-04-17 21:43:52

标签: wpf

我让UserControl将可缩放的画布包装为用户可以拖动的形状。

最近,我尝试进行更改以遵循在this question中获得的建议;而是将一个变换应用于具有形状的整个画布,我尝试将其分别应用于每个形状的Geometry。想法是消除缩放对字体大小和线条粗细的影响。

不幸的是,尽管我大部分都在工作(形状显示在应有的位置),但我似乎打破了单个形状在画布上的拖动。我无法解释原因。

症状是DragDelta事件处理程序正在报告每个Horizo​​ntalChange和VerticalChange的 累积 值。因此,我的形状现在即使很小的移动也可以缩小屏幕的边缘。他们曾经不是那样。

(在事件args上设置“已处理”布尔值无效)

我在下面发布了一些代码。尽管我感谢任何不愿阅读它的人,但实际上我对使人完全可以使DragDelta报告累积值的一般概念更加感兴趣。该文档指出,它们仅应作为自上次调用DragDelta以来的值。

我不能成为第一个犯此错误的人。这是常见的问题,有共同的原因吗?

无论如何,如果您仍然在阅读,这里是细节。形状由接口IShape表示。

public interface IShape
{
    Geometry RelativeGeometry { get; }  // Geometry relative to shape origin
    Geometry AbsoluteGeometry { get; }  // Geometry relative to canvas origin
}

IShape对象绘制在UserControl内的Canvas上的ItemsControl中

<Canvas x:Name="Scene">
    <ItemsControl x:Name="ShapesLayer" ItemsSource="{Binding Shapes}"
                  ItemTemplate={StaticResource ShapeTemplate}"/>
</Canvas>

这是ItemControl用来绘制IShape的ItemTemplate

<DataTemplate x:Key="ShapeTemplate" DataType="{x:Type gci:IShape}">
    <Canvas>
        <!-- Visible shape (not selectable) -->

        <Path Data="{Binding AbsoluteGeometry, {StaticResource TransformGeometry}, ConverterParameter={StaticResource Trans}}"
              IsHitTestVisible="False"/>

        <!-- Invisible but selectable thumb control for dragging shape -->

        <Thumb">
            <Thumb.Style>
                <EventSetter Event="DragDelta"             Handler="Shape_DragDelta"/>
            </Thumb.Style>
            <Thumb.Template>
                <ControlTemplate TargetType="{x:Type Thumb}">
                    <Path Fill="Transparent" Stroke="Transparent">
                        <Path.Data>
                            <RectangleGeometry Rect="{Binding AbsoluteGeometry.Bounds}"
                                               Transform="{StaticResource Trans}"/>
                        </Path.Data>
                    </Path>
                </ControlTemplate>
            </Thumb.Template>
        </Thumb>
    </Canvas>
</DataTemplate>

这是隐藏代码中形状拇指控件的DragDelta处理程序

private void Shape_DragDelta(object sender, DragDeltaEventArgs e)
{
    if (!(sender is FrameworkElement fe) || !(fe.DataContext is IShape shape))
        return;

    // Move each selected shape by the delta.

    var v = new Vector {X = e.HorizontalChange, Y = e.VerticalChange};
    foreach (var s in Shapes.Where(shp => shp.IsSelected))
    {
        if (s.Offset(v) && !(_movedShapes.Contains(s)))
            _movedShapes.Add(s);

    }

    e.Handled = true;
}

最后,这是变换,在我的控件的资源中声明,并被所有形状使用。它基于控件中的自定义Scale和OffsetX / OffsetY依赖项属性。我的控件使用鼠标/触摸处理程序在代码背后设置了这些值。它们会传播到该资源,从而传播到形状。

<TransformGroup x:Key="Trans">

    <!-- "Root" is the name of the control.  It exposes custom dependency
    properties "ZoomScale, "OffsetX" and "OffsetY" which apply to the entire
    control and therefore are not changed when a shape is dragged  -->

    <ScaleTransform CenterX="0" CenterY="0" 
                    ScaleX="{Binding ElementName=Root, Path=ZoomScale}" 
                    ScaleY="{Binding ElementName=Root, Path=ZoomScale}"
    />
    <TranslateTransform X="{Binding ElementName=Root, Path=OffsetX}" 
                        Y="{Binding ElementName=Root, Path=OffsetY}"/>
</TransformGroup>

<!-- Value Converter that applies a transform to a Geometry  -->

<gcc:TransformGeometryConverter x:Key="TransformGeometry"/>

0 个答案:

没有答案