0

We have a StreamGeometry object which we would like to render in about 400 different locations during the OnRender call. The problem is, of course, that a geometry object uses absolute coordinates.

While we could of course apply transforms before the render call, that means we'd in essence be creating 400 transforms as well, which just seems like overkill.

We just want to say 'Render this in that location, like this (Note: DrawGeometryAtPoint is fictitious)...

protected override void OnRender(System.Windows.Media.DrawingContext dc)
{
    base.OnRender(dc);

    var myGeometry = new StreamGeometry();

    // Code to init the geometry goes here

   // Render the same geometry but at four different locations
    dc.DrawGeometryAtPoint(Brush1, Pen1, myGeometry, Origin1);
    dc.DrawGeometryAtPoint(Brush2, Pen2, myGeometry, Origin2);
    dc.DrawGeometryAtPoint(Brush3, Pen3, myGeometry, Origin3);
    dc.DrawGeometryAtPoint(Brush4, Pen4, myGeometry, Origin4);
}

So can it be done?

Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286
  • Please bear in mind that if you use the VisualBrush with a virtual control, you may need to do `Measure` and `Arrange` calls to property size the visual. – newb Dec 17 '12 at 20:13

1 Answers1

0

This is essentially the same question as your previous one.

Either you push a separate transform before each rendering.

var transform = new TranslateTransform(origin.X, origin.Y);
transform.Freeze();
dc.PushTransform();
dc.DrawGeometry(brush, pen, geometry;
dc.Pop();

This is essentially the same as putting a GeometryDrawing in a DrawingGroup and set the DrawingGroup.Transform property.

Or you put the StreamGeometry into a GeometryGroup and set the Transform there.

var transform = new TranslateTransform(origin.X, origin.Y);
transform.Freeze();
var group = new GeometryGroup { Transform = transform };
group.Children.Add(geometry);
dc.DrawGeometry(brush, pen, group;

As i told you in my comment to the other question, there is no way to get around having a separate Transform object for every rendering of the same Geometry at different locations.


EDIT: You should consider a different design. Instead of running a complete OnRender pass each time your objects move a bit, you should render once and afterwards only change the Tranform objects. Which must then of course not be frozen. Therefore you would not override OnRender in some control, but provide a special control that hosts a DrawingVisual.

Community
  • 1
  • 1
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • Not exactly sure that will work. I also realize my question may be misleading so I've updated it to show what we're really after... rendering StreamGeometry paths in multiple locations. – Mark A. Donohoe Dec 20 '12 at 21:26
  • That's a completely different question. I will also update my answer. – Clemens Dec 20 '12 at 21:43
  • Well it wasn't completely different as my original thought was to render the StreamGeometry in its own Visual, then render that visual in multiple places. Still, that was an attempt at a solution to the real problem which is as I stated above. The issue as I see it is that OnRender really doesn't actually *do* the rendering. It merely sets up the DrwingGroups that WPF renders offline at a later time. That's why I'm not sure what I'm after is possible without creating multiple TranslateTransform objects and lots of Push/Pop calls, which stinks. – Mark A. Donohoe Dec 20 '12 at 21:50
  • I guess you finally have to accept that WPF simply is like that. A Transform object costs *nothing*. And i doubt that you get a real performance problem by creating 400 Transforms. You might however take care that your OnRender isn't called too often. – Clemens Dec 20 '12 at 22:00
  • Actually, we have noticed a performance problem with those 400, because in actuality, it's in response to a scrollbar as the user scrolls, so that is magnified. The code without the transforms was pretty quick (but looked wrong). As soon as we added the transforms, there was a noticeable degredation in the scrolling performance. But as they say, those are the breaks! I've always said I love *programming* WPF, but I am not a fan of the *performance* of WPF. It's a trade-off I guess. – Mark A. Donohoe Dec 20 '12 at 22:08
  • Oh... and I forgot I had created that other question. That's actually why I created this one... as an attempted solution to that one, which is why this one originally talked about visuals. Oh well. I broke Stack! LOL! – Mark A. Donohoe Dec 20 '12 at 22:10
  • On the comment about the design, the list is virtualized so we have no choice but to go this route, or else we'd be creating tens of thousands of these items. But to the point you raised, how do you tell the control it has to re-render (actual, not the OnRender pass)? I mean say I do the single-OnRender call that sets up all the transforms like you suggest. Now I update one of those transforms. Does WPF simply re-render (again, actual) that geometry at the new location without going through the OnRender override again? If so, that opens up some new ideas at least. – Mark A. Donohoe Dec 20 '12 at 22:41
  • That's exactly what happens. As long as the total number of objects (in [DrawingVisual.Drawing](http://msdn.microsoft.com/en-us/library/system.windows.media.drawingvisual.drawing.aspx)) doesn't change, you can render them once and later only update their transforms. The rest is done by the WPF render thread. You could do such an initial rendering for eaxmple in the constructor of a UIElement-derived object and draw into a DrawingVisual that is returned by an overridden [GetVisualChild](http://msdn.microsoft.com/en-us/library/system.windows.media.visual.getvisualchild.aspx) method. – Clemens Dec 20 '12 at 23:14