Search code examples
c#.netwpfdrawingcontext

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. 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.

My elements are rendered using a tree of custom DrawingVisual subclasses, with the root being a Border subclass that contains a VisualCollection. I solved the Y direction problem by specifying a ScaleTransform as the RenderTransform of that Border, essentially flipping the whole control vertically.

No such luck for the other issue, though. Any idea for how to center my origin?


Solution

  • 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.

    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.

    // 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.

    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.