static T?FindDescendantWithBreadthFirstSearch(DependencyObject element, ref TPredicate predicate) { // We're using a pooled buffer writer to amortize allocations for the temporary collection of children // to visit for each level. The underlying array is deliberately just of type object and not DependencyObject // to reduce the number of generic instantiations and allow the rented arrays to be reused more. using ArrayPoolBufferWriter <object> bufferWriter = ArrayPoolBufferWriter <object> .Create(); int childrenCount = VisualTreeHelper.GetChildrenCount(element); // Add the top level children for (int i = 0; i < childrenCount; i++) { DependencyObject child = VisualTreeHelper.GetChild(element, i); if (child is T result && predicate.Match(result)) { return(result); } bufferWriter.Add(child); } // Explore each depth level for (int i = 0; i < bufferWriter.Count; i++) { DependencyObject parent = (DependencyObject)bufferWriter[i]; childrenCount = VisualTreeHelper.GetChildrenCount(parent); for (int j = 0; j < childrenCount; j++) { DependencyObject child = VisualTreeHelper.GetChild(parent, j); if (child is T result && predicate.Match(result)) { return(result); } bufferWriter.Add(child); } } return(null); }
/// <summary cref="IEnumerator.MoveNext"/> public bool MoveNext() { while (enumerator.MoveNext()) { if (predicate.Match(enumerator.Current)) { return(true); } } return(false); }
static T?FindDescendantWithDepthFirstSearch(DependencyObject element, ref TPredicate predicate) { int childrenCount = VisualTreeHelper.GetChildrenCount(element); for (int i = 0; i < childrenCount; i++) { DependencyObject child = VisualTreeHelper.GetChild(element, i); if (child is T result && predicate.Match(result)) { return(result); } T?descendant = FindDescendantWithDepthFirstSearch(child, ref predicate); if (descendant is not null) { return(descendant); } } return(null); }