[英]Draw relative to center with DrawingContext
I've been wondering how to draw stuff in WPF with a DrawingContext
relative to something that's not the top left corner of the control. 我一直想知道如何在WPF中使用
DrawingContext
相对于不在控件左上角的东西进行绘制。 My problem is that I want to draw some shapes by connecting various dots, and those dots have to be positionned relative to the center of the host control, with Y pointing upwards. 我的问题是我想通过连接各种点来绘制一些形状,并且这些点必须相对于主机控件的中心定位,Y指向上方。
My elements are rendered using a tree of custom DrawingVisual
subclasses, with the root being a Border
subclass that contains a VisualCollection
. 我的元素是使用自定义
DrawingVisual
子类的树呈现的,其根是包含VisualCollection
的Border
子类。 I solved the Y direction problem by specifying a ScaleTransform
as the RenderTransform
of that Border
, essentially flipping the whole control vertically. 我通过指定
ScaleTransform
作为Border
的RenderTransform
来解决Y方向问题,本质上是垂直翻转整个控件。
No such luck for the other issue, though. 但是,在其他问题上没有这样的运气。 Any idea for how to center my origin?
关于如何使我的血统居中的想法吗?
Instead of the ScaleTransform you could use a MatrixTransform that scales by -1 in y direction and translates the coordinate origin to the control's center. 可以使用MatrixTransform代替ScaleTransform,该MatrixTransform在y方向上按-1缩放并将坐标原点平移到控件的中心。 This transform must however be updated whenever the control's size changes.
但是,每当控件大小更改时,都必须更新此转换。 Hence you would override OnRenderSizeChanged like below (assuming that you set the
RenderTransform
property of your control): 因此,您将像下面那样重写OnRenderSizeChanged(假设您设置了控件的
RenderTransform
属性):
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
RenderTransform = new MatrixTransform(1d, 0d, 0d, -1d,
sizeInfo.NewSize.Width / 2d, sizeInfo.NewSize.Height / 2d);
}
EDIT: In case you don't want to transform the whole controls, you could also define a MatrixTransform as class member and apply it to every Visual in the visual children collection. 编辑:如果您不想转换整个控件,则还可以将MatrixTransform定义为类成员,并将其应用于视觉子级集合中的每个Visual。
private MatrixTransform transform = new MatrixTransform();
Assign to the Transform property of every new Visual: 分配给每个新Visual的Transform属性:
ContainerVisual visual = ...
visual.Transform = transform;
On size changes you would simply update that MatrixTransform: 关于大小更改,您只需更新该MatrixTransform:
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
transform.Matrix = new Matrix(1d, 0d, 0d, -1d,
sizeInfo.NewSize.Width / 2d, sizeInfo.NewSize.Height / 2d);
}
Of course you only need to apply the Transform to "top-level" visuals. 当然,您只需要将“变换”应用于“顶级”视觉效果即可。 Children of those visuals will be transformed by the Transform of their parents.
这些视觉效果的孩子将通过父母的改造而改变。 I do not exactly understand how you manage your visuals by a "Border subclass that contains a VisualCollection".
我不完全了解如何通过“包含VisualCollection的Border子类”管理视觉效果。 The typical approach would be to have one parent ContainerVisual as root of the visual tree.
典型的方法是将一个父ContainerVisual作为视觉树的根。 Transforms would then be applied to this root visual only.
然后,仅将变换应用于此基本视觉效果。
您尝试过TranslateTransform吗?
Alright, I got it. 好吧,我明白了。 Here's how I've done it.
这是我的方法。
First, I defined a GroupTransform
and assigned to a WorldTransform
property on my Border
subclass. 首先,我定义了一个
GroupTransform
并分配给我的Border
子类的WorldTransform
属性。
var trans = new TranslateTransform();
var conv = new HalfConverter(); // a custom converter that halves whatever you pass to it
BindingOperations.SetBinding(trans, TranslateTransform.XProperty, new Binding { Path = new PropertyPath(ActualWidthProperty), Source = this, Converter = conv });
BindingOperations.SetBinding(trans, TranslateTransform.YProperty, new Binding { Path = new PropertyPath(ActualHeightProperty), Source = this, Converter = conv });
WorldTransform = new TransformGroup();
WorldTransform.Children.Add(new ScaleTransform { ScaleY = -1.0 });
WorldTransform.Children.Add(trans);
VisualTransform = WorldTransform;
Then, when I create a new instance of my custom DrawingVisual
, I assign its Transform
property to my WorldTransform
. 然后,当我创建自定义
DrawingVisual
的新实例时,将其Transform
属性分配给WorldTransform
。
// ZoneVisual is my DrawingVisual subclass
var vis = new ZoneVisual(zone) { Transform = WorldTransform };
When I add a new element (a Node
, by the way), I simply need to transform it by the inverse of my WorldTransform
. 当我添加一个新元素(顺便说一下,是一个
Node
)时,我只需要通过WorldTransform
的逆来对其进行转换。
Voila. 瞧 This might not be the best way, but it seems to work pretty well.
这可能不是最好的方法,但似乎效果很好。 I don't have remarkably high performance needs, so it will probably do the job.
我对高性能的需求不高,因此它可能会胜任。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.