C# 使用DrawingContext相对于中心绘制

C# 使用DrawingContext相对于中心绘制,c#,.net,wpf,drawingcontext,C#,.net,Wpf,Drawingcontext,我一直在想,如何在WPF中绘制与控件左上角以外的对象相关的内容。我的问题是,我想通过连接不同的点来绘制一些形状,这些点必须相对于主控件的中心进行定位,Y向上 我的元素是使用自定义DrawingVisual子类树呈现的,根是包含VisualCollection的Border子类。我通过指定一个ScaleTransform作为该边框的渲染转换,基本上垂直翻转整个控件,解决了Y方向的问题 不过,在另一个问题上没有这样的运气。你知道如何居中我的原点吗?你试过了吗?你可以用矩阵变换代替缩放变换,在y方向上

我一直在想,如何在WPF中绘制与控件左上角以外的对象相关的内容。我的问题是,我想通过连接不同的点来绘制一些形状,这些点必须相对于主控件的中心进行定位,Y向上

我的元素是使用自定义
DrawingVisual
子类树呈现的,根是包含
VisualCollection
Border
子类。我通过指定一个
ScaleTransform
作为该
边框的
渲染转换
,基本上垂直翻转整个控件,解决了Y方向的问题


不过,在另一个问题上没有这样的运气。你知道如何居中我的原点吗?

你试过了吗?

你可以用矩阵变换代替缩放变换,在y方向上缩放-1,并将坐标原点转换到控件的中心。但是,每当控件的大小更改时,必须更新此转换。因此,您将覆盖OnRenderSizeChanged,如下所示(假设您设置控件的
RenderTransform
属性):

编辑:如果不想转换整个控件,还可以将MatrixTransform定义为类成员,并将其应用于VisualChildren集合中的每个视觉对象

private MatrixTransform transform = new MatrixTransform();
指定给每个新视觉对象的变换特性:

ContainerVisual visual = ...
visual.Transform = transform;
在大小更改时,您只需更新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);
}

当然,您只需要将转换应用于“顶级”视觉效果。这些视觉效果的孩子将被他们父母的转变所改变。我不完全理解如何通过“包含VisualCollection的Border子类”来管理视觉效果。典型的方法是将一个父ContainerVisual作为可视化树的根。然后,变换将仅应用于此根可视对象。

好的,我知道了。我是这样做的

首先,我定义了一个
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;
然后,当我创建自定义
DrawingVisual
的新实例时,我将其
Transform
属性指定给我的
WorldTransform

// ZoneVisual is my DrawingVisual subclass
var vis = new ZoneVisual(zone) { Transform = WorldTransform };
当我添加一个新元素(顺便说一句,
节点
)时,我只需要用我的
WorldTransform
的倒数对它进行变换

// ZoneVisual is my DrawingVisual subclass
var vis = new ZoneVisual(zone) { Transform = WorldTransform };

瞧。这可能不是最好的方法,但似乎效果很好。我没有非常高的性能需求,因此它可能会完成这项工作。

不幸的是,这会移动整个
边框
控件。请参阅我的编辑。我认为这仍然比你的解决方案简单得多。主要的一点是,它对所有视觉效果都使用相同的转换实例。实际上,这正是我的解决方案所做的。我不这么认为。至少它比我的绑定多了两个:-)啊,你的意思是你也对所有的视觉对象使用相同的转换。好的,没错。我没有仔细阅读你的答案。我仍然认为应该只有一个根ContainerVisual。