/// <summary> /// Walks up the visual tree from the specified visual and returns the nearest instance of <see cref="AdornerLayer"/>. /// </summary> /// <param name="visual">The visual at which to begin searching for adorner layers.</param> /// <returns>The nearest <see cref="AdornerLayer"/> which is above <paramref name="visual"/> in the visual tree.</returns> public static AdornerLayer GetAdornerLayer(Visual visual) { Contract.Require(visual, "visual"); var current = (DependencyObject)visual; while (current != null) { if (current is AdornerDecorator) return ((AdornerDecorator)current).AdornerLayer; current = VisualTreeHelper.GetParent(current); } return null; }
/// <summary> /// Returns a transformation matrix which can be used to transform coordinates from this visual to /// the specified ancestor of this visual. /// </summary> /// <param name="ancestor">The ancestor to which coordinates will be transformed.</param> /// <param name="inDevicePixels">A value indicating whether the transform is scaled to device pixels (<c>true</c>) or device-independent pixels (<c>false</c>).</param> /// <returns>A <see cref="Matrix"/> which represents the specified transformation.</returns> public Matrix GetTransformToAncestorMatrix(Visual ancestor, Boolean inDevicePixels = false) { Contract.Require(ancestor, "ancestor"); return this.MatrixTransformToAncestorInternal(ancestor, false, inDevicePixels); }
/// <summary> /// Returns a transformation matrix which can be used to transform coordinates from this visual to /// the specified ancestor of this visual. /// </summary> /// <param name="ancestor">The ancestor to which coordinates will be transformed.</param> /// <param name="invert">A value indicating whether to invert the resulting matrix.</param> /// <param name="inDevicePixels">A value indicating whether the transform is scaled to device pixels (<c>true</c>) or device-independent pixels (<c>false</c>).</param> /// <returns>A <see cref="Matrix"/> which represents the specified transformation.</returns> private Matrix MatrixTransformToAncestorInternal(Visual ancestor, Boolean invert, Boolean inDevicePixels = false) { var mtxFinal = Matrix.Identity; DependencyObject current; for (current = this; current != null && current != ancestor; current = VisualTreeHelper.GetParent(current)) { var uiElement = current as UIElement; if (uiElement != null) { var bounds = uiElement.UntransformedRelativeBounds.Location; if (inDevicePixels) { bounds = uiElement.View.Display.DipsToPixels(bounds); } var mtxTransform = uiElement.GetTransformMatrix(inDevicePixels); var mtxTranslateToClientSpace = Matrix.CreateTranslation( (Single)bounds.X, (Single)bounds.Y, 0f); Matrix mtxResult; Matrix.Concat(ref mtxFinal, ref mtxTransform, out mtxResult); Matrix.Concat(ref mtxResult, ref mtxTranslateToClientSpace, out mtxFinal); } } if (current != ancestor) { var paramName = invert ? "descendant" : "ancestor"; var message = invert ? PresentationStrings.ElementIsNotADescendant : PresentationStrings.ElementIsNotAnAncestor; throw new ArgumentException(message, paramName); } if (invert) { if (Matrix.TryInvert(mtxFinal, out mtxFinal)) { return mtxFinal; } return Matrix.Identity; } return mtxFinal; }
/// <summary> /// Occurs when the object's visual parent is changed. /// </summary> /// <param name="oldParent">The visual's old visual parent.</param> /// <param name="newParent">The visual's new visual parent.</param> protected virtual void OnVisualParentChanged(Visual oldParent, Visual newParent) { }
/// <summary> /// Removes a visual child from this object. /// </summary> /// <param name="child">The child object to remove from this object.</param> protected internal void RemoveVisualChild(Visual child) { if (child == null || child.visualParent == null) return; if (child.visualParent == this) { child.visualParent = null; child.OnVisualParentChangedInternal(this, null); } }
/// <summary> /// Adds a visual as a child of this object. /// </summary> /// <param name="child">The child object to add to this object.</param> protected internal void AddVisualChild(Visual child) { if (child == null) return; if (child.visualParent != null) throw new InvalidOperationException(PresentationStrings.VisualAlreadyHasAParent); if (child.visualParent != this) { var oldParent = child.visualParent; var newParent = this; child.visualParent = newParent; child.OnVisualParentChangedInternal(oldParent, newParent); } }
/// <summary> /// Invokes the <see cref="OnVisualParentChanged(Visual, Visual)"/> method. /// </summary> /// <param name="oldParent">The visual's old visual parent.</param> /// <param name="newParent">The visual's new visual parent.</param> internal virtual void OnVisualParentChangedInternal(Visual oldParent, Visual newParent) { OnVisualParentChanged(oldParent, newParent); }
/// <summary> /// Transforms a point from the coordinate space of this visual to the coordinate space /// of the specified descendant visual. /// </summary> /// <param name="descendant">The descendant to which coordinates will be transformed.</param> /// <param name="point">The point to transform.</param> /// <returns>The transformed point.</returns> public Point2D TransformToDescendant(Visual descendant, Point2D point) { var matrix = GetTransformToDescendantMatrix(descendant); Point2D result; Point2D.Transform(ref point, ref matrix, out result); return result; }
/// <summary> /// Transforms a vector from the coordinate space of this visual to the coordinate space /// of the specified descendant visual. /// </summary> /// <param name="descendant">The descendant to which coordinates will be transformed.</param> /// <param name="vector">The vector to transform.</param> /// <returns>The transformed vector.</returns> public Vector2 TransformToDescendant(Visual descendant, Vector2 vector) { var matrix = GetTransformToDescendantMatrix(descendant); Vector2 result; Vector2.Transform(ref vector, ref matrix, out result); return result; }
/// <summary> /// Transforms a point from the coordinate space of this visual to the coordinate space /// of the specified ancestor visual. /// </summary> /// <param name="ancestor">The ancestor to which coordinates will be transformed.</param> /// <param name="point">The point to transform.</param> /// <returns>The transformed point.</returns> public Point2D TransformToAncestor(Visual ancestor, Point2D point) { var matrix = GetTransformToAncestorMatrix(ancestor); Point2D result; Point2D.Transform(ref point, ref matrix, out result); return result; }
/// <summary> /// Transforms a vector from the coordinate space of this visual to the coordinate space /// of the specified ancestor visual. /// </summary> /// <param name="ancestor">The ancestor to which coordinates will be transformed.</param> /// <param name="vector">The vector to transform.</param> /// <returns>The transformed vector.</returns> public Vector2 TransformToAncestor(Visual ancestor, Vector2 vector) { var matrix = GetTransformToAncestorMatrix(ancestor); Vector2 result; Vector2.Transform(ref vector, ref matrix, out result); return result; }
/// <summary> /// Retrieves a transform which can be used to transform coordinates from this visual /// to the specified descendant visual. /// </summary> /// <param name="descendant">The descendant to which coordinates will be transformed.</param> /// <returns>A <see cref="Transform"/> which represents the specified transformation.</returns> public Transform TranformToDescendant(Visual descendant) { return new MatrixTransform(GetTransformToDescendantMatrix(descendant)); }
/// <summary> /// Retrieves a transform which can be used to transform coordinates from this visual /// to the specified ancestor visual. /// </summary> /// <param name="ancestor">The ancestor to which coordinates will be transformed.</param> /// <returns>A <see cref="Transform"/> which represents the specified transformation.</returns> public Transform TransformToAncestor(Visual ancestor) { return new MatrixTransform(GetTransformToAncestorMatrix(ancestor)); }
/// <summary> /// Returns a transformation matrix which can be used to transform coordinates from this visual to /// the specified descendant of this visual. /// </summary> /// <param name="descendant">The descendnat to which coordinates will be transformed.</param> /// <param name="inDevicePixels">A value indicating whether the transform is scaled to device pixels (<c>true</c>) or device-independent pixels (<c>false</c>).</param> /// <returns>A <see cref="Matrix"/> which represents the specified transformation.</returns> public Matrix GetTransformToDescendantMatrix(Visual descendant, Boolean inDevicePixels = false) { Contract.Require(descendant, "descendant"); return descendant.MatrixTransformToAncestorInternal(this, true, inDevicePixels); }
/// <inheritdoc/> protected override void OnVisualParentChanged(Visual oldParent, Visual newParent) { base.OnVisualParentChanged(oldParent, newParent); EnsureIsInitialized(); }
/// <inheritdoc/> internal override void OnVisualParentChangedInternal(Visual oldParent, Visual newParent) { var parent = VisualParent as FrameworkElement; if (parent != null) { if (parent.IsLoaded != IsLoaded) { if (parent.IsLoaded) { EnsureIsLoaded(true); } else { EnsureIsLoaded(false); } } } else { if (IsLoaded) { EnsureIsLoaded(false); } } base.OnVisualParentChangedInternal(oldParent, newParent); }