0

So, I'm new to WPF Drawing. For performance reasons, I've had to switch from regular controls like ContentControl and UserControl to more light-weight elements like DrawingVisual. I am working on a diagramming app which would probably have a max of 1000 elements on the canvas that can be dragged, resized and such. Firstly, is it better to use DrawingVisual instead of Shape? Secondly, my main question here. I am adding DrawingVisual elements to the Canvas as such:

public class SVisualContainer : UIElement
{
    // Create a collection of child visual objects.
    private VisualCollection _children;

    public SVisualContainer()
    {
        _children = new VisualCollection(this);
        _children.Add(CreateDrawingVisualRectangle());
    }

    // Create a DrawingVisual that contains a rectangle.
    private DrawingVisual CreateDrawingVisualRectangle()
    {
        DrawingVisual drawingVisual = new DrawingVisual();

        // Retrieve the DrawingContext in order to create new drawing content.
        DrawingContext drawingContext = drawingVisual.RenderOpen();

        // Create a rectangle and draw it in the DrawingContext.
        Rect rect = new Rect(new System.Windows.Point(160, 100), new System.Windows.Size(320, 80));
        drawingContext.DrawRectangle(System.Windows.Media.Brushes.LightBlue, null, rect);

        // Persist the drawing content.
        drawingContext.Close();

        return drawingVisual;
    }

    // Provide a required override for the VisualChildrenCount property.
    protected override int VisualChildrenCount
    {
        get { return _children.Count; }
    }



    // Provide a required override for the GetVisualChild method.
    protected override Visual GetVisualChild(int index)
    {
        if (index < 0 || index >= _children.Count)
        {
            throw new ArgumentOutOfRangeException();
        }

        return _children[index];
    }
}

And within the canvas:

public void AddStateVisual()
{
    var sVisual = new SVisualContainer();
    Children.Add(sVisual);
    Canvas.SetLeft(sVisual, 10);
    Canvas.SetTop(sVisual, 10);
}

How can I increase the size of the Rectangle dynamically through code? I have tried setting the Height and Width of the Rectangle which did not work, played around with the ScaleTransform but that is probably not what I want. Would I need to redraw the Rectangle? Thanks!

heapoverflow
  • 85
  • 1
  • 8
  • 1
    Drawingvisual is lighter weight than shape but shape has width and height which sound like it might be a winner in your case. Whether the efficiency difference would be a problem depends on your expectations. Our map drawing software lets a user draw the outline shape for terrain. One is woods which is "filled" with trees. A tree is a usercontrol containing several shapes, a dropshadow and not exactly simple. Rendering about ten thousand trees takes under 3 seconds on my machine whilst in debug mode inside visual studio. I consider that acceptable but maybe you're expecting something faster. – Andy Aug 19 '20 at 15:43
  • That is great information. If rendering 10000 UserControls takes only 3 seconds, I think Shapes which are probably lighter than UserControls would surely fit my requirements. I'd still like to know how to resize a DrawingVisual just in case. But thanks for that info! – heapoverflow Aug 19 '20 at 16:42
  • Why doesn't ScaleTransform work for you? – Robert Harvey Aug 19 '20 at 17:01
  • Would ScaleTransform be appropriate for the scenario where the user will resize the visual in the canvas? I thought ScaleTransform is for zooming and such, but correct me if I'm wrong. E.g If there is a RectangleGeometry visual which has a width of 100, height of 100. And the user drags its corner, how can I increase/decrease the size using ScaleTransform? Currently, I'm just redrawing the RectangleGeometry. – heapoverflow Aug 19 '20 at 18:05
  • 1
    You could build a drawing or writeablebitmap and redraw the whole thing if things change. Elsewhere, i build a hypsometric image as a writeablebitmap and that took 29ms when i measured it. But i would worry about optimisation when you see an actual problem that needs fixing. Those trees are usercontrols rendered using datatemplates in an itemscontrol. It's likely each tree is more complex than you need. They each contain three paths and a dropshadow. Maybe usercontrols are overkill. If you instead just had one path with one geometry defining it, that would be far lighter. – Andy Aug 19 '20 at 18:21

1 Answers1

1

I ended up using DrawingVisual within UIElement as shown in the question, and continuously redrawing the DrawingVisual upon resize. The UIElement.RenderSize property, UIElement.MeasureCore method and UIElement.InvalidateMeasure method are central to this. This works quite well and the performance is acceptable.

heapoverflow
  • 85
  • 1
  • 8