Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wpf-graphics-rendering-overview.md] clarifying VisualTree traversal order #1943

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

glenn-slayden
Copy link
Contributor

@glenn-slayden glenn-slayden commented Dec 16, 2024

copyedit (medium): one paragraph, for your consideration and review.


Internal previews

📄 File 🔗 Preview link
dotnet-desktop-guide/framework/wpf/graphics-multimedia/wpf-graphics-rendering-overview.md dotnet-desktop-guide/framework/wpf/graphics-multimedia/wpf-graphics-rendering-overview

…traversal order

Copyedit one paragraph for your review.
@adegeo
Copy link
Contributor

adegeo commented Dec 18, 2024

Hi @glenn-slayden

I'll need to do some investigating on this PR as it's changing some of the wording that's very specific to behavior. I assume that when this content was originally written, it was done so with the product group. Like, why was "left to right" chosen as the phrase to communicate render order? Is it true? Does position factor into sibling rendering? I'll have to explore the code or find someone that knows more than myself.

Another example is that you introduced "child nodes are always rendered first" is that 100% without a doubt true? Or is this an assumption? Can something else in code or in behavior actually alter the order so that it isn't true? I don't know.

I'm curious, what's the motivation behind this PR?

@adegeo adegeo requested a review from a team December 18, 2024 18:14
@adegeo
Copy link
Contributor

adegeo commented Dec 18, 2024

@dotnet/wpf-developers

@glenn-slayden
Copy link
Contributor Author

Thanks for the feedback. As you can check my logs, I don't make many PRs, but when I do I hope the information is solid, especially when proffered to a serious commercial venture. I am a past MS SDE dev and have specialized in working on Visual/Drawing/DrawingVisual-level code for WPF since it started in 2007 or so. I even have a few "actually retained graphics" successes in this type of WPF design, which is admittedly off-the-beaten-path. Most people just stick with the Measure/Arrange layout pass model since it's easier and more comprehensible.

Retained-mode programming on WPF is not easy, but its reasonably capable and fantastically performant when it works. Just trying to improve things, but if my submission doesn't satisfy your standards then it's no offense.

@adegeo
Copy link
Contributor

adegeo commented Jan 6, 2025

Thanks for the response Glenn! I'll dive into this PR. The only reason I was questioning you is just the fact that there are so many AI bots that do these odd wording changes, so as soon as I start asking questions with no response I sort of get the idea.

My only concern is for myself, I just don't know that much about it to validate a submission in this area. Considering the holiday season is now over, I hope to get some of the WPF product group to look at it. From my point of view it seems solid, but I just want them to give a stamp of approval.

Thanks again, and I appreciate your thoroughness!

@singhashish-wpf
Copy link
Member

Maybe I am not understanding it in the depths, however a small experiment appears to prove the opposite that the child is drawn later and the parent is drawn first.

            <Canvas>
                <Rectangle Width="300" Height="300" Fill="Blue"
                       Canvas.Left="50" Canvas.Top="50" />

                <!-- Child Rectangle (Partially Transparent) -->
                <Rectangle Width="150" Height="150" Fill="Yellow" Opacity="0.7"
                       Canvas.Left="125" Canvas.Top="125" />
            </Canvas>

Above code results in

image

@singhashish-wpf singhashish-wpf self-requested a review January 9, 2025 06:09
@glenn-slayden
Copy link
Contributor Author

Maybe I am not understanding it in the depths, however a small experiment appears to prove the opposite that the child is drawn later and the parent is drawn first.

            <Canvas>
                <Rectangle Width="300" Height="300" Fill="Blue"
                       Canvas.Left="50" Canvas.Top="50" />

                <!-- Child Rectangle (Partially Transparent) -->
                <Rectangle Width="150" Height="150" Fill="Yellow" Opacity="0.7"
                       Canvas.Left="125" Canvas.Top="125" />
            </Canvas>

In your code, the two rectangles are siblings, not parent/child. They are both children of the <Canvas> element.

@singhashish-wpf
Copy link
Member

Maybe I am not understanding it in the depths, however a small experiment appears to prove the opposite that the child is drawn later and the parent is drawn first.

            <Canvas>
                <Rectangle Width="300" Height="300" Fill="Blue"
                       Canvas.Left="50" Canvas.Top="50" />

                <!-- Child Rectangle (Partially Transparent) -->
                <Rectangle Width="150" Height="150" Fill="Yellow" Opacity="0.7"
                       Canvas.Left="125" Canvas.Top="125" />
            </Canvas>

In your code, the two rectangles are siblings, not parent/child. They are both children of the <Canvas> element.

Yep. Agreed
However, even if we modify the sample to have a textbox inside a Textblock where there is a parent child relationship, we see that the child is obscuring the parent, not the other way.
image

@glenn-slayden
Copy link
Contributor Author

glenn-slayden commented Jan 11, 2025

We may be talking about different things here. The Visual Tree is traversed in a certain order to produce a list of MIL render instructions, which is not necessarily isomorphic to the effective nesting of the “retained graphics” drawings.

That’s because, in OnRender, a UIElement can order its drawing instructions any way it likes, for example, drawing a solid background first, which would then be obscured by any child it explicitly drew, or the other way around. But DrawingVisual is a Visual that doesn’t use OnRender.

WPF drawings can be built using complex DrawingGroup hierarchies and then just a single simple Visual with AddVisualChild at the top, and it will still render (and re-render) without involving user-mediated OnRender callbacks. That’s the retained mode Visual Tree.

I’ll defer to any expert WPF devs on any of my errors here. Feel free to abandon this PR if it’s too arcane or obscure, or too much trouble to clarify... Thanks.

@adegeo
Copy link
Contributor

adegeo commented Jan 14, 2025

If the changes are making the paragraph more complex while the original paragraph was still accurate, perhaps the changes should be an additional paragraph describing the edge cases or just more detail about when/how it could rendered in a way you're not expecting when considering the order listed in the XAML.

When I look at the original paragraph, the part that doesn't make sense to me is

The root visual’s children are then traversed, left to right.

I don't understand what left-to-right means in this context. Are they saying where it lands on the screen, left -> right? Is it talking about the collection of children in the visual tree, should that be top-down?

@glenn-slayden
Copy link
Contributor Author

Yes, “left-to-right” is not useful here and should definitely be fixed. (I think it might be trying to refer to the actual graphical layout of the accompanying examples, but that has nothing to do with how WPF works.) Child elements are drawn according to the order listed by their parent, from 0… N, regardless of the screen position or size they get rendered at.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants