Czasem zachodzi potrzeba, by element sceny 3D wiedział o swojej obecności w scenie, np. w celu odpowiedniego obrócenia się, by być przodem do kamery. Oczywiście przy jego dodawaniu do sceny można by było przekazać do niego odpowiednie informacje o scenie, ale okazuje się, że każdy element sceny może sam uzyskać odpowiednie informacje, gdyż wszystkie elementy sceny 3D w WPF (i nie tylko sceny 3D) tworzą drzewo wizualne (visual tree).
Niniejszy wpis poza prezentacją różnych i niezależnych od konkretnego wykorzystania treści stanowi również opis pewnych zagadnień związanych z projektem Mesh Diagram 3D.Informacje dotyczące projektu oznaczone są etykietą MeshDiagram3D.
Wizualne drzewo (visual tree) reprezentuje wszystkie elementy w interfejsie użytkownika, na podstawie którego powstaje obraz aplikacji na urządzeniu wyjściowym (zazwyczaj ekranie). Wizualne drzewo jest używane do wielu rzeczy, takich jak rendering, routing zdarzeń, lokalizacji zasobów (jeśli element nie ma logicznego elementu nadrzędnego) i innych. Możliwe jest poruszanie się po drzewie z wykorzystaniem klasy VisualTreeHelper.
Wierzchołkami w drzewie mogą być obiekty typów dziedziczących po
klasach Visual
lub Visual3D.
Dla przykładu, we wspomnianym wcześniej problemie, w którym
element sceny musi poznać swój kontekst (np. Kamerę, która go
obserwuje), może przejść po elementach drzewa (wykorzystując
VisualTreeHelper.GetParent,
która zwraca obiekt typu DependencyObject,
będący elementem sceny, więc w tym przypadku Visual3D).
By znaleźć obiekt nadrzędny typu Viewport3DVisual,
z którego można pozyskać informacje na temat kamery.
Tutaj warto zwrócić jeszcze uwagę na jedną kwestię, wędrując w
górę drzewa, po elementach sceny 3D, nie trafiamy na końcu na
element typu Viewport3D,
ale na element typu Viewport3DVisual.
Klasa Viewport3DVisual
renderuje należące do niego (jako dzieci = children) obiekty
Visual3D
na wybrany prostokątny obszar 2D aplikacji. Viewport3DVisual jest
więc typową (2D) kontrolką WPF-a typu Visual
z elementami 3D (Visual3D)
jako dzieci (Właściwość Viewport3DVisual.Children
dostarcza kolekcję objektów Visual3D
zawartych w Viewport3DVisual).
Ostatecznie funkcja odnajdująca główny element (typu
Viewport3DVisual) w drzewie może wyglądać następująco:
public static Viewport3DVisual GetViewport3DVisual( DependencyObject visual ) { Viewport3DVisual viewport; if ( !( visual is Visual3D ) ) { throw new ArgumentException( "Must be of type Visual3D.", "visual" ); } while ( visual != null ) { if ( !( visual is ModelVisual3D ) ) { break; } visual = VisualTreeHelper.GetParent( visual ); } viewport = visual as Viewport3DVisual; if ( viewport == null && visual != null ) { throw new ApplicationException( String.Format( "Unsupported type: '{0}'. Expected tree of ModelVisual3Ds leading up to a Viewport3DVisual.", visual.GetType().FullName ) ); } return viewport; }
Na koniec chciałbym jeszce polecić artykuł z
portalu CodeProject: “Understanding
the Visual Tree and Logical Tree in WPF”.
Fajny ten post!
OdpowiedzUsuń