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); }