0

Why this geometry transform doesn't work?

private void DrawElement(DrawingVisual dv)
    {

        using (var dvc = dv.RenderOpen())
        {
            GeometryGroup gg = new GeometryGroup();
            var pen = new Pen(Brushes.Black, 2);
            TranslateTransform tt = new TranslateTransform(0, (!IsInverted ? -1 : 1) * _pixelsPerMillimeter);
            TransformGroup tg = new TransformGroup();

            Point lu, lb, ru, rb;
            lu = new Point(rct_center.Left, (!IsMaxillar ? rct_center.Bottom - _pixelsPerMillimeter : _pixelsPerMillimeter + rct_center.Top));//
            lb = new Point(lu.X, lu.Y + (!IsInverted ? -1 : 1) * rct_center.Height / 2);//
            ru = new Point(rct_center.Right - _pixelsPerMillimeter, lu.Y);//
            rb = new Point(ru.X, lb.Y);//
            LineGeometry upperLeft = new LineGeometry(lu, new Point(lu.X + _pixelsPerMillimeter, lu.Y));
            LineGeometry bottomLeft = new LineGeometry(lb, new Point(lb.X + _pixelsPerMillimeter, lb.Y));
            LineGeometry upperRight = new LineGeometry(ru, new Point(ru.X + _pixelsPerMillimeter, ru.Y));
            LineGeometry bottomRight = new LineGeometry(rb, new Point(rb.X + _pixelsPerMillimeter, rb.Y));
            gg.Children.Add(upperLeft);
            gg.Children.Add(bottomLeft);
            gg.Children.Add(upperRight);
            gg.Children.Add(bottomRight);
            for (int j = 30 - 1; j >= 0; --j) //-1 because the start line isn't drawn.
            {
                dvc.DrawGeometry(Brushes.Transparent, pen, gg);

                tg.Children.Add(tt);
                gg.Transform = tg;
            }
        }

    }

I want to draw repeatedly the 4 lines group below the previous or viceversa (if IsInverted). When I debug the transformgroup matrix is modified, but the transformation isn't applied in the geometry group. I'm newbie in wpf, from winforms and i'm a little bit lost without GDI GraphicsPath.

I want something like this

There is someway to do it better? Maybe i'm thinking a lot in GDI way to do it.

DrkDeveloper
  • 939
  • 7
  • 17
  • @Clemens edit with image and new explanation. – DrkDeveloper Mar 23 '18 at 17:16
  • That's just a fixed number of lines with fixed lengths and distances at the four corners of the UIElement where you override OnRender? And one line that covers the whole width? Why do you override OnRender at all, instead of just putting an Image element and your drawings (e.g. in a Canvas) in a common parent element, e.g. a Grid? If you seriously ask how to "do better", you need to add significantly more details to your question. – Clemens Mar 23 '18 at 17:21
  • This a custom Control i did in Winforms, and i want to port (and learn during the process) to WPF: https://i.imgur.com/fsIw5uf.png I want to Draw the ruler, but it depends of the size of the control. All the cells are editable. I achieve recreate the table in WPF, i achieve recreate the teeth image in WPF. The drawed lines depends of values of the cells. And you can delete teeth, etc... – DrkDeveloper Mar 23 '18 at 17:29
  • I still find this really confusing. Why transform at all rather than just using the starting Y to define where they go? You're setting the transform property numerous times - why not once? – Andy Mar 23 '18 at 17:55
  • How should i do it? @Andy I have to draw the 4 lines group several times, then i have to transform it or recreate the 4 lines. What have more performance? – DrkDeveloper Mar 23 '18 at 18:02
  • One of your problems with this question is you will find few developers have used low level graphics at all. That is then compounded by the difficulty of following exactly what you're trying to do. In any case. I wouldn't worry about the performance with drawing a few lines. If you're still stuck after setting that transform just once then maybe it's time to consider a rather different approach. If you want rectangles, you could build a combined geometry with multiple rectangles in it and use that as the data of a path. Move the path round if you need to. – Andy Mar 23 '18 at 18:23
  • Why not create geometry group of 4*30 lines? Why apply transformations recursively? I don't know which is better in terms of performance, but my guess is that 120 lines is easier on the system then applying... mmm... 465 (1 + 2 + ... + 30) transformations. – Sergey.quixoticaxis.Ivanov Mar 23 '18 at 18:43
  • @Andy i gonna find another aproach, but the transformations in WPF as I see are a little bit broken. GDI was easier gp.Transform(matrix); and the transform was applied. In WPF i didn't know how to "do the apply" of the transformation. – DrkDeveloper Mar 23 '18 at 19:30
  • It's not at all broken. You just don't understand it. One problem is that you're reusing a single Geometry and a single Transform object in your loop, where you should instead create new ones for every loop cycle. DrawGeometry doesn't magically create a copy of the Geometry you've passed in. – Clemens Mar 24 '18 at 00:25
  • @Clemens TransformGroup avoid create new transforms, only add to transformgroup another transform (the same in this case), isn't it? And then i apply the new transform to the geometry, doesn't have sense? – DrkDeveloper Mar 24 '18 at 02:26
  • No, makes no sense. Besides that all this transform stuff seems highly redundant. You can simply draw lines at coordinates. – Clemens Mar 24 '18 at 07:37

1 Answers1

0

What you want to do here is use the rendering context's (dvc's) Push method instead of relying on the Transform of the geometry object itself. When using the drawing contexts, WPF relies on Push/Pop operations for setting the transform. You can see a related answer here: How do you apply a Scale Translation to a DrawingContext?

In addition, I think you need to study how C# handles reference types. The way you have it in your sample code, you are assigning the same instance of the transform to each geometry object, which I don't think was intended. I'm not sure if the Push method uses the context during the call or after; you'd have to experiment with that. Creating a new TranslateTransform inside your inner loop would be a sure way to avoid that. However, I agree with the commentators in that using some offset property would be more performant.

Brannon
  • 5,324
  • 4
  • 35
  • 83
  • Wow, I didn't remember this question. Thanks for the answer, but in this time I learned how WPF works (2 years are a lot). At the end I did it the right way, I made a custom UIElement for the ruler itself and created the logic inside it. – DrkDeveloper Dec 01 '20 at 05:41