我让UserControl将可缩放的画布包装为用户可以拖动的形状。
最近,我尝试进行更改以遵循在this question中获得的建议;而是将一个变换应用于具有形状的整个画布,我尝试将其分别应用于每个形状的Geometry。想法是消除缩放对字体大小和线条粗细的影响。
不幸的是,尽管我大部分都在工作(形状显示在应有的位置),但我似乎打破了单个形状在画布上的拖动。我无法解释原因。
症状是DragDelta事件处理程序正在报告每个HorizontalChange和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"/>