Question

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;
        }
Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top