0

I have a canvas with some images, and i'm also using DrawGeometry, to draw a circle that is filling when the time is passing.

This is how i draw the circle in my DrawingContext:

protected override void OnRender(DrawingContext drawingContext)
{
    base.OnRender(drawingContext);
    MyUtils.RenderProgressClock(drawingContext, clockPosition, 50, gameTime / totalTime);
}

And calling the InvalidateVisual(); to call it.

But Doing this my circle is behind my images and i cant see it, how can i draw it infront of them?

Im totally new to WPF and its giving me a hard Time....

This is the other method code as requested:

 private static PathGeometry GetClockGeometry(Point position, double percentage, double radius)
        {
            const double innerFactor = 0.90;
            double innerRadius = radius * innerFactor;

            PathGeometry pie = new PathGeometry();

            PathFigure pathFigure = new PathFigure();
            pathFigure.StartPoint = new Point(0, -innerRadius);
            pathFigure.IsClosed = true;

            if (percentage > kMaxClockPercentage)
            {
                percentage = kMaxClockPercentage;
            }
            double angle = 360.0 * percentage;

            // Starting Point
            LineSegment inOutLine = new LineSegment(new Point(0, -radius), true);

            // Arc
            ArcSegment outerArc = new ArcSegment();

            outerArc.IsLargeArc = angle >= 180.0;
            outerArc.Point = new Point(Math.Cos((angle - 90) * Math.PI / 180.0) * radius, Math.Sin((angle - 90) * Math.PI / 180.0) * radius);
            outerArc.Size = new Size(radius, radius);
            outerArc.SweepDirection = SweepDirection.Clockwise;

            LineSegment outInLine = new LineSegment(new Point(outerArc.Point.X * innerFactor, outerArc.Point.Y * innerFactor), true);

            ArcSegment innerArc = new ArcSegment();
            innerArc.IsLargeArc = angle >= 180.0;
            innerArc.Point = pathFigure.StartPoint;
            innerArc.Size = new Size(innerRadius, innerRadius);
            innerArc.SweepDirection = SweepDirection.Counterclockwise;

            pathFigure.Segments.Add(inOutLine);
            pathFigure.Segments.Add(outerArc);
            pathFigure.Segments.Add(outInLine);
            pathFigure.Segments.Add(innerArc);

            pie.Transform = new TranslateTransform(position.X, position.Y);
            pie.Figures.Add(pathFigure);

            return pie;
        }
Cœur
  • 37,241
  • 25
  • 195
  • 267
Luis Tellez
  • 2,785
  • 1
  • 20
  • 28

2 Answers2

1

OK, now that I understand a little better what is going on, I see that my initial answer won't directly work for you. However, I also see that you have a bit of a problem.

Just the general nature of the way OnRender works means that what you draw is always going to end up behind the images and whatnot that you add to the window.

Add to that the fact that you're putting all this drawing code for a specific feature (the progress clock) into the window itself, and this solution feels a little off.

You might want to explore some alternatives.

A simple one would be to create a UserControl to draw the Clock. That UserControl could have a DependencyProperty for the % that it should be filled. You could use your (roughly) same OnRender code in the UserControl or you could do it some other fancy ways (I'm sure there's some way to do it in all XAML, though I don't know it off the top of my head). Then you just put that clock into the window like all your other images/controls.

You could also do it creating a CustomControl, though that takes a little bit more knowledge about WPF and Resources and whatnot to understand how it works. Since you're new to WPF, that might be a bit much right now.

Tim
  • 14,999
  • 1
  • 45
  • 68
  • Where `_TimeLayer` should be declared *after* `_ImageLayer` to be on top, unless you set [Panel.ZIndex](http://msdn.microsoft.com/en-us/library/system.windows.controls.panel.zindex(v=vs.110).aspx). – Clemens Dec 20 '12 at 19:41
  • And for an overridden `OnRender` the upper control does not need to be a Canvas. It could be a simple UIElement. – Clemens Dec 20 '12 at 19:42
  • Yeah, I had that backwards. Doing things too quickly. Thanks Clemens – Tim Dec 20 '12 at 20:16
  • The problem is that when im drawing on the OnRender i dont do it in any specific Canvas, my images on the camvas show ok and i have multiples Layers like this. – Luis Tellez Dec 21 '12 at 12:15
  • Can you explain a little more what you mean that you don't do it on any specific canvas? Also, maybe you could post a little more code - that might help us. Like what's actually going on in the RenderProgressClock function and is the OnRender function the handler for a Canvas? A usercontrol? A window? – Tim Dec 21 '12 at 14:16
  • Its for the window, i dont knopw how to make it specific to a canvas. – Luis Tellez Dec 21 '12 at 19:14
  • I see what's going on now. I've changed my answer. Let me know your thoughts. – Tim Dec 21 '12 at 20:10
  • Thx Tim, i didint saw your answer until today and already made the control and its working fine. – Luis Tellez Dec 26 '12 at 11:16
1

You need to show us how your circle is added to the Canvas.

WPF is a retained drawing system, so the order the controls appear in it's visual-tree dictates their stacking order.. OnRender() really means AccumulateDrawingObjects() as it doesn't directly draw, it just creates a set of objects to draw.

Also, you don't need to InvalidateVisual() if an object is staying the same size, as it causes a very expensive re-layout.

More efficient ways to re-render are to use a DependencyProperty with AffectsRender... Or to create a DrawingGroup, add it to the DrawingContext during OnRender(), then anytime later you can DrawingGroup.Open() to change the drawing commands in the DrawingGroup.

David Jeske
  • 2,306
  • 24
  • 29