Merge pull request #4791 from CommunityToolkit/revert-4333-feature/extended-tree-helpers
Revert "Feature/extended tree helpers"
This commit is contained in:
Коммит
aa39ee5d70
|
@ -1,24 +0,0 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates a type of search for elements in a visual or logical tree.
|
||||
/// </summary>
|
||||
public enum SearchType
|
||||
{
|
||||
/// <summary>
|
||||
/// Depth-first search, where each branch is recursively explored until the end before moving to the next one.
|
||||
/// </summary>
|
||||
DepthFirst,
|
||||
|
||||
/// <summary>
|
||||
/// Breadth-first search, where each depthwise level is completely explored before moving to the next one.
|
||||
/// This is particularly useful if the target element to find is known to not be too distant from the starting
|
||||
/// point and the whole visual/logical tree from the root is large enough, as it can reduce the traversal time.
|
||||
/// </summary>
|
||||
BreadthFirst
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Toolkit.Uwp.UI.Helpers.Internals;
|
||||
using Microsoft.Toolkit.Uwp.UI.Predicates;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
@ -29,22 +28,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
{
|
||||
PredicateByName predicateByName = new(name, comparisonType);
|
||||
|
||||
return FindDescendant<FrameworkElement, PredicateByName>(element, ref predicateByName, SearchType.DepthFirst);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the first descendant of type <see cref="FrameworkElement"/> with a given name.
|
||||
/// </summary>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="name">The name of the element to look for.</param>
|
||||
/// <param name="comparisonType">The comparison type to use to match <paramref name="name"/>.</param>
|
||||
/// <param name="searchType">The search type to use to explore the visual tree.</param>
|
||||
/// <returns>The descendant that was found, or <see langword="null"/>.</returns>
|
||||
public static FrameworkElement? FindDescendant(this DependencyObject element, string name, StringComparison comparisonType, SearchType searchType)
|
||||
{
|
||||
PredicateByName predicateByName = new(name, comparisonType);
|
||||
|
||||
return FindDescendant<FrameworkElement, PredicateByName>(element, ref predicateByName, searchType);
|
||||
return FindDescendant<FrameworkElement, PredicateByName>(element, ref predicateByName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -58,22 +42,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
{
|
||||
PredicateByAny<T> predicateByAny = default;
|
||||
|
||||
return FindDescendant<T, PredicateByAny<T>>(element, ref predicateByAny, SearchType.DepthFirst);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the first descendant element of a given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="searchType">The search type to use to explore the visual tree.</param>
|
||||
/// <returns>The descendant that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindDescendant<T>(this DependencyObject element, SearchType searchType)
|
||||
where T : notnull, DependencyObject
|
||||
{
|
||||
PredicateByAny<T> predicateByAny = default;
|
||||
|
||||
return FindDescendant<T, PredicateByAny<T>>(element, ref predicateByAny, searchType);
|
||||
return FindDescendant<T, PredicateByAny<T>>(element, ref predicateByAny);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -86,21 +55,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
{
|
||||
PredicateByType predicateByType = new(type);
|
||||
|
||||
return FindDescendant<DependencyObject, PredicateByType>(element, ref predicateByType, SearchType.DepthFirst);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the first descendant element of a given type.
|
||||
/// </summary>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="type">The type of element to match.</param>
|
||||
/// <param name="searchType">The search type to use to explore the visual tree.</param>
|
||||
/// <returns>The descendant that was found, or <see langword="null"/>.</returns>
|
||||
public static DependencyObject? FindDescendant(this DependencyObject element, Type type, SearchType searchType)
|
||||
{
|
||||
PredicateByType predicateByType = new(type);
|
||||
|
||||
return FindDescendant<DependencyObject, PredicateByType>(element, ref predicateByType, searchType);
|
||||
return FindDescendant<DependencyObject, PredicateByType>(element, ref predicateByType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -108,30 +63,14 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="predicate">The predicate to use to match the descendant nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the descendant nodes.</param>
|
||||
/// <returns>The descendant that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindDescendant<T>(this DependencyObject element, Func<T, bool> predicate)
|
||||
where T : notnull, DependencyObject
|
||||
{
|
||||
PredicateByFunc<T> predicateByFunc = new(predicate);
|
||||
|
||||
return FindDescendant<T, PredicateByFunc<T>>(element, ref predicateByFunc, SearchType.DepthFirst);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the first descendant element matching a given predicate.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="predicate">The predicate to use to match the descendant nodes.</param>
|
||||
/// <param name="searchType">The search type to use to explore the visual tree.</param>
|
||||
/// <returns>The descendant that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindDescendant<T>(this DependencyObject element, Func<T, bool> predicate, SearchType searchType)
|
||||
where T : notnull, DependencyObject
|
||||
{
|
||||
PredicateByFunc<T> predicateByFunc = new(predicate);
|
||||
|
||||
return FindDescendant<T, PredicateByFunc<T>>(element, ref predicateByFunc, searchType);
|
||||
return FindDescendant<T, PredicateByFunc<T>>(element, ref predicateByFunc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -141,129 +80,48 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// <typeparam name="TState">The type of state to use when matching nodes.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
|
||||
/// <param name="predicate">The predicate to use to match the descendant nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the descendant nodes.</param>
|
||||
/// <returns>The descendant that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindDescendant<T, TState>(this DependencyObject element, TState state, Func<T, TState, bool> predicate)
|
||||
where T : notnull, DependencyObject
|
||||
{
|
||||
PredicateByFunc<T, TState> predicateByFunc = new(state, predicate);
|
||||
|
||||
return FindDescendant<T, PredicateByFunc<T, TState>>(element, ref predicateByFunc, SearchType.DepthFirst);
|
||||
return FindDescendant<T, PredicateByFunc<T, TState>>(element, ref predicateByFunc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the first descendant element matching a given predicate.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <typeparam name="TState">The type of state to use when matching nodes.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
|
||||
/// <param name="predicate">The predicate to use to match the descendant nodes.</param>
|
||||
/// <param name="searchType">The search type to use to explore the visual tree.</param>
|
||||
/// <returns>The descendant that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindDescendant<T, TState>(this DependencyObject element, TState state, Func<T, TState, bool> predicate, SearchType searchType)
|
||||
where T : notnull, DependencyObject
|
||||
{
|
||||
PredicateByFunc<T, TState> predicateByFunc = new(state, predicate);
|
||||
|
||||
return FindDescendant<T, PredicateByFunc<T, TState>>(element, ref predicateByFunc, searchType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the first descendant element matching a given predicate.
|
||||
/// Find the first descendant element matching a given predicate, using a depth-first search.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <typeparam name="TPredicate">The type of predicate in use.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="predicate">The predicate to use to match the descendant nodes.</param>
|
||||
/// <param name="searchType">The search type to use to explore the visual tree.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the descendant nodes.</param>
|
||||
/// <returns>The descendant that was found, or <see langword="null"/>.</returns>
|
||||
private static T? FindDescendant<T, TPredicate>(this DependencyObject element, ref TPredicate predicate, SearchType searchType)
|
||||
private static T? FindDescendant<T, TPredicate>(this DependencyObject element, ref TPredicate predicate)
|
||||
where T : notnull, DependencyObject
|
||||
where TPredicate : struct, IPredicate<T>
|
||||
{
|
||||
// Depth-first search, with recursive implementation
|
||||
static T? FindDescendantWithDepthFirstSearch(DependencyObject element, ref TPredicate predicate)
|
||||
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
|
||||
|
||||
for (var i = 0; i < childrenCount; i++)
|
||||
{
|
||||
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
|
||||
DependencyObject child = VisualTreeHelper.GetChild(element, i);
|
||||
|
||||
for (int i = 0; i < childrenCount; i++)
|
||||
if (child is T result && predicate.Match(result))
|
||||
{
|
||||
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 result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
T? descendant = FindDescendant<T, TPredicate>(child, ref predicate);
|
||||
|
||||
// Breadth-first search, with iterative implementation and pooled local stack
|
||||
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++)
|
||||
if (descendant is not null)
|
||||
{
|
||||
DependencyObject child = VisualTreeHelper.GetChild(element, i);
|
||||
|
||||
if (child is T result && predicate.Match(result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
bufferWriter.Add(child);
|
||||
return descendant;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
static T? ThrowArgumentOutOfRangeExceptionForInvalidSearchType()
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(searchType), "The input search type is not valid");
|
||||
}
|
||||
|
||||
return searchType switch
|
||||
{
|
||||
SearchType.DepthFirst => FindDescendantWithDepthFirstSearch(element, ref predicate),
|
||||
SearchType.BreadthFirst => FindDescendantWithBreadthFirstSearch(element, ref predicate),
|
||||
_ => ThrowArgumentOutOfRangeExceptionForInvalidSearchType()
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -283,24 +141,6 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
return FindDescendant(element, name, comparisonType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the first descendant (or self) of type <see cref="FrameworkElement"/> with a given name.
|
||||
/// </summary>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="name">The name of the element to look for.</param>
|
||||
/// <param name="comparisonType">The comparison type to use to match <paramref name="name"/>.</param>
|
||||
/// <param name="searchType">The search type to use to explore the visual tree.</param>
|
||||
/// <returns>The descendant (or self) that was found, or <see langword="null"/>.</returns>
|
||||
public static FrameworkElement? FindDescendantOrSelf(this DependencyObject element, string name, StringComparison comparisonType, SearchType searchType)
|
||||
{
|
||||
if (element is FrameworkElement result && name.Equals(result.Name, comparisonType))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return FindDescendant(element, name, comparisonType, searchType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the first descendant (or self) element of a given type, using a depth-first search.
|
||||
/// </summary>
|
||||
|
@ -318,24 +158,6 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
return FindDescendant<T>(element);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the first descendant (or self) element of a given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="searchType">The search type to use to explore the visual tree.</param>
|
||||
/// <returns>The descendant (or self) that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindDescendantOrSelf<T>(this DependencyObject element, SearchType searchType)
|
||||
where T : notnull, DependencyObject
|
||||
{
|
||||
if (element is T result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return FindDescendant<T>(element, searchType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the first descendant (or self) element of a given type, using a depth-first search.
|
||||
/// </summary>
|
||||
|
@ -352,29 +174,12 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
return FindDescendant(element, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the first descendant (or self) element of a given type.
|
||||
/// </summary>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="type">The type of element to match.</param>
|
||||
/// <param name="searchType">The search type to use to explore the visual tree.</param>
|
||||
/// <returns>The descendant (or self) that was found, or <see langword="null"/>.</returns>
|
||||
public static DependencyObject? FindDescendantOrSelf(this DependencyObject element, Type type, SearchType searchType)
|
||||
{
|
||||
if (element.GetType() == type)
|
||||
{
|
||||
return element;
|
||||
}
|
||||
|
||||
return FindDescendant(element, type, searchType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the first descendant (or self) element matching a given predicate, using a depth-first search.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="predicate">The predicate to use to match the descendant nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the descendant nodes.</param>
|
||||
/// <returns>The descendant (or self) that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindDescendantOrSelf<T>(this DependencyObject element, Func<T, bool> predicate)
|
||||
where T : notnull, DependencyObject
|
||||
|
@ -387,25 +192,6 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
return FindDescendant(element, predicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the first descendant (or self) element matching a given predicate.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="predicate">The predicate to use to match the descendant nodes.</param>
|
||||
/// <param name="searchType">The search type to use to explore the visual tree.</param>
|
||||
/// <returns>The descendant (or self) that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindDescendantOrSelf<T>(this DependencyObject element, Func<T, bool> predicate, SearchType searchType)
|
||||
where T : notnull, DependencyObject
|
||||
{
|
||||
if (element is T result && predicate(result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return FindDescendant(element, predicate, searchType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the first descendant (or self) element matching a given predicate, using a depth-first search.
|
||||
/// </summary>
|
||||
|
@ -413,7 +199,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// <typeparam name="TState">The type of state to use when matching nodes.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
|
||||
/// <param name="predicate">The predicate to use to match the descendant nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the descendant nodes.</param>
|
||||
/// <returns>The descendant (or self) that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindDescendantOrSelf<T, TState>(this DependencyObject element, TState state, Func<T, TState, bool> predicate)
|
||||
where T : notnull, DependencyObject
|
||||
|
@ -426,130 +212,19 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
return FindDescendant(element, state, predicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the first descendant (or self) element matching a given predicate.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <typeparam name="TState">The type of state to use when matching nodes.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
|
||||
/// <param name="predicate">The predicate to use to match the descendant nodes.</param>
|
||||
/// <param name="searchType">The search type to use to explore the visual tree.</param>
|
||||
/// <returns>The descendant (or self) that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindDescendantOrSelf<T, TState>(this DependencyObject element, TState state, Func<T, TState, bool> predicate, SearchType searchType)
|
||||
where T : notnull, DependencyObject
|
||||
{
|
||||
if (element is T result && predicate(result, state))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return FindDescendant(element, state, predicate, searchType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find all descendant elements of the specified element. This method can be chained with
|
||||
/// LINQ calls to add additional filters or projections on top of the returned results.
|
||||
/// <para>
|
||||
/// This method is meant to provide extra flexibility in specific scenarios and it should not
|
||||
/// be used when only the first item is being looked for. In those cases, use one of the
|
||||
/// available <see cref="FindDescendant{T}(DependencyObject)"/> overloads instead,
|
||||
/// which will offer a more compact syntax as well as better performance in those cases.
|
||||
/// available <see cref="FindDescendant{T}(DependencyObject)"/> overloads instead, which will
|
||||
/// offer a more compact syntax as well as better performance in those cases.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <returns>All the descendant <see cref="DependencyObject"/> instance from <paramref name="element"/>.</returns>
|
||||
public static IEnumerable<DependencyObject> FindDescendants(this DependencyObject element)
|
||||
{
|
||||
return FindDescendants(element, SearchType.DepthFirst);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find all descendant elements of the specified element. This method can be chained with
|
||||
/// LINQ calls to add additional filters or projections on top of the returned results.
|
||||
/// <para>
|
||||
/// This method is meant to provide extra flexibility in specific scenarios and it should not
|
||||
/// be used when only the first item is being looked for. In those cases, use one of the
|
||||
/// available <see cref="FindDescendant{T}(DependencyObject)"/> overloads instead,
|
||||
/// which will offer a more compact syntax as well as better performance in those cases.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="searchType">The search type to use to explore the visual tree.</param>
|
||||
/// <returns>All the descendant <see cref="DependencyObject"/> instance from <paramref name="element"/>.</returns>
|
||||
public static IEnumerable<DependencyObject> FindDescendants(this DependencyObject element, SearchType searchType)
|
||||
{
|
||||
// Depth-first traversal, with recursion
|
||||
static IEnumerable<DependencyObject> FindDescendantsWithDepthFirstSearch(DependencyObject element)
|
||||
{
|
||||
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
|
||||
|
||||
for (var i = 0; i < childrenCount; i++)
|
||||
{
|
||||
DependencyObject child = VisualTreeHelper.GetChild(element, i);
|
||||
|
||||
yield return child;
|
||||
|
||||
foreach (DependencyObject childOfChild in FindDescendants(child))
|
||||
{
|
||||
yield return childOfChild;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Breadth-first traversal, with pooled local stack
|
||||
static IEnumerable<DependencyObject> FindDescendantsWithBreadthFirstSearch(DependencyObject element)
|
||||
{
|
||||
using ArrayPoolBufferWriter<object> bufferWriter = ArrayPoolBufferWriter<object>.Create();
|
||||
|
||||
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
|
||||
|
||||
for (int i = 0; i < childrenCount; i++)
|
||||
{
|
||||
DependencyObject child = VisualTreeHelper.GetChild(element, i);
|
||||
|
||||
yield return child;
|
||||
|
||||
bufferWriter.Add(child);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
yield return child;
|
||||
|
||||
bufferWriter.Add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static IEnumerable<DependencyObject> ThrowArgumentOutOfRangeExceptionForInvalidSearchType()
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(searchType), "The input search type is not valid");
|
||||
}
|
||||
|
||||
return searchType switch
|
||||
{
|
||||
SearchType.DepthFirst => FindDescendantsWithDepthFirstSearch(element),
|
||||
SearchType.BreadthFirst => FindDescendantsWithBreadthFirstSearch(element),
|
||||
_ => ThrowArgumentOutOfRangeExceptionForInvalidSearchType()
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find all first level descendant elements of the specified element. This method can be chained
|
||||
/// with LINQ calls to add additional filters or projections on top of the returned results.
|
||||
/// </summary>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <returns>All the first level descendant <see cref="DependencyObject"/> instance from <paramref name="element"/>.</returns>
|
||||
public static IEnumerable<DependencyObject> FindFirstLevelDescendants(this DependencyObject element)
|
||||
{
|
||||
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
|
||||
|
||||
|
@ -558,127 +233,12 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
DependencyObject child = VisualTreeHelper.GetChild(element, i);
|
||||
|
||||
yield return child;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find all first level descendant elements of the specified element. This method can be chained
|
||||
/// with LINQ calls to add additional filters or projections on top of the returned results.
|
||||
/// </summary>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <returns>All the first level descendant <see cref="DependencyObject"/> instance from <paramref name="element"/>.</returns>
|
||||
public static IEnumerable<DependencyObject> FindFirstLevelDescendantsOrSelf(this DependencyObject element)
|
||||
{
|
||||
yield return element;
|
||||
|
||||
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
|
||||
|
||||
for (var i = 0; i < childrenCount; i++)
|
||||
{
|
||||
DependencyObject child = VisualTreeHelper.GetChild(element, i);
|
||||
|
||||
yield return child;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find all descendant elements of the specified element (or self). This method can be chained
|
||||
/// with LINQ calls to add additional filters or projections on top of the returned results.
|
||||
/// <para>
|
||||
/// This method is meant to provide extra flexibility in specific scenarios and it should not
|
||||
/// be used when only the first item is being looked for. In those cases, use one of the
|
||||
/// available <see cref="FindDescendantOrSelf{T}(DependencyObject)"/> overloads instead,
|
||||
/// which will offer a more compact syntax as well as better performance in those cases.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <returns>All the descendant <see cref="DependencyObject"/> instance from <paramref name="element"/>.</returns>
|
||||
public static IEnumerable<DependencyObject> FindDescendantsOrSelf(this DependencyObject element)
|
||||
{
|
||||
return FindDescendantsOrSelf(element, SearchType.DepthFirst);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find all descendant elements of the specified element (or self). This method can be chained
|
||||
/// with LINQ calls to add additional filters or projections on top of the returned results.
|
||||
/// <para>
|
||||
/// This method is meant to provide extra flexibility in specific scenarios and it should not
|
||||
/// be used when only the first item is being looked for. In those cases, use one of the
|
||||
/// available <see cref="FindDescendantOrSelf{T}(DependencyObject)"/> overloads instead,
|
||||
/// which will offer a more compact syntax as well as better performance in those cases.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="searchType">The search type to use to explore the visual tree.</param>
|
||||
/// <returns>All the descendant <see cref="DependencyObject"/> instance from <paramref name="element"/>.</returns>
|
||||
public static IEnumerable<DependencyObject> FindDescendantsOrSelf(this DependencyObject element, SearchType searchType)
|
||||
{
|
||||
// Depth-first traversal, with recursion
|
||||
static IEnumerable<DependencyObject> FindDescendantsWithDepthFirstSearch(DependencyObject element)
|
||||
{
|
||||
yield return element;
|
||||
|
||||
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
|
||||
|
||||
for (var i = 0; i < childrenCount; i++)
|
||||
foreach (DependencyObject childOfChild in FindDescendants(child))
|
||||
{
|
||||
DependencyObject child = VisualTreeHelper.GetChild(element, i);
|
||||
|
||||
yield return child;
|
||||
|
||||
foreach (DependencyObject childOfChild in FindDescendants(child))
|
||||
{
|
||||
yield return childOfChild;
|
||||
}
|
||||
yield return childOfChild;
|
||||
}
|
||||
}
|
||||
|
||||
// Breadth-first traversal, with pooled local stack
|
||||
static IEnumerable<DependencyObject> FindDescendantsWithBreadthFirstSearch(DependencyObject element)
|
||||
{
|
||||
yield return element;
|
||||
|
||||
using ArrayPoolBufferWriter<object> bufferWriter = ArrayPoolBufferWriter<object>.Create();
|
||||
|
||||
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
|
||||
|
||||
for (int i = 0; i < childrenCount; i++)
|
||||
{
|
||||
DependencyObject child = VisualTreeHelper.GetChild(element, i);
|
||||
|
||||
yield return child;
|
||||
|
||||
bufferWriter.Add(child);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
yield return child;
|
||||
|
||||
bufferWriter.Add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static IEnumerable<DependencyObject> ThrowArgumentOutOfRangeExceptionForInvalidSearchType()
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(searchType), "The input search type is not valid");
|
||||
}
|
||||
|
||||
return searchType switch
|
||||
{
|
||||
SearchType.DepthFirst => FindDescendantsWithDepthFirstSearch(element),
|
||||
SearchType.BreadthFirst => FindDescendantsWithBreadthFirstSearch(element),
|
||||
_ => ThrowArgumentOutOfRangeExceptionForInvalidSearchType()
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -727,7 +287,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <param name="element">The starting element.</param>
|
||||
/// <param name="predicate">The predicate to use to match the ascendant nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the ascendant nodes.</param>
|
||||
/// <returns>The ascendant that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindAscendant<T>(this DependencyObject element, Func<T, bool> predicate)
|
||||
where T : notnull, DependencyObject
|
||||
|
@ -744,7 +304,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// <typeparam name="TState">The type of state to use when matching nodes.</typeparam>
|
||||
/// <param name="element">The starting element.</param>
|
||||
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
|
||||
/// <param name="predicate">The predicate to use to match the ascendant nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the ascendant nodes.</param>
|
||||
/// <returns>The ascendant that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindAscendant<T, TState>(this DependencyObject element, TState state, Func<T, TState, bool> predicate)
|
||||
where T : notnull, DependencyObject
|
||||
|
@ -760,7 +320,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <typeparam name="TPredicate">The type of predicate in use.</typeparam>
|
||||
/// <param name="element">The starting element.</param>
|
||||
/// <param name="predicate">The predicate to use to match the ascendant nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the ascendant nodes.</param>
|
||||
/// <returns>The ascendant that was found, or <see langword="null"/>.</returns>
|
||||
private static T? FindAscendant<T, TPredicate>(this DependencyObject element, ref TPredicate predicate)
|
||||
where T : notnull, DependencyObject
|
||||
|
@ -839,7 +399,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <param name="element">The starting element.</param>
|
||||
/// <param name="predicate">The predicate to use to match the ascendant nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the ascendant nodes.</param>
|
||||
/// <returns>The ascendant (or self) that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindAscendantOrSelf<T>(this DependencyObject element, Func<T, bool> predicate)
|
||||
where T : notnull, DependencyObject
|
||||
|
@ -859,7 +419,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// <typeparam name="TState">The type of state to use when matching nodes.</typeparam>
|
||||
/// <param name="element">The starting element.</param>
|
||||
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
|
||||
/// <param name="predicate">The predicate to use to match the ascendant nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the ascendant nodes.</param>
|
||||
/// <returns>The ascendant (or self) that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindAscendantOrSelf<T, TState>(this DependencyObject element, TState state, Func<T, TState, bool> predicate)
|
||||
where T : notnull, DependencyObject
|
||||
|
@ -878,8 +438,8 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// <para>
|
||||
/// This method is meant to provide extra flexibility in specific scenarios and it should not
|
||||
/// be used when only the first item is being looked for. In those cases, use one of the
|
||||
/// available <see cref="FindAscendant{T}(DependencyObject)"/> overloads instead,
|
||||
/// which will offer a more compact syntax as well as better performance in those cases.
|
||||
/// available <see cref="FindAscendant{T}(DependencyObject)"/> overloads instead, which will
|
||||
/// offer a more compact syntax as well as better performance in those cases.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="element">The root element.</param>
|
||||
|
@ -900,73 +460,5 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
element = parent;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find all ascendant elements of the specified element (or self). This method can be chained
|
||||
/// with LINQ calls to add additional filters or projections on top of the returned results.
|
||||
/// <para>
|
||||
/// This method is meant to provide extra flexibility in specific scenarios and it should not
|
||||
/// be used when only the first item is being looked for. In those cases, use one of the
|
||||
/// available <see cref="FindAscendantOrSelf{T}(DependencyObject)"/> overloads instead,
|
||||
/// which will offer a more compact syntax as well as better performance in those cases.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <returns>All the descendant <see cref="DependencyObject"/> instance from <paramref name="element"/>.</returns>
|
||||
public static IEnumerable<DependencyObject> FindAscendantsOrSelf(this DependencyObject element)
|
||||
{
|
||||
yield return element;
|
||||
|
||||
while (true)
|
||||
{
|
||||
DependencyObject? parent = VisualTreeHelper.GetParent(element);
|
||||
|
||||
if (parent is null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
yield return parent;
|
||||
|
||||
element = parent;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether or not a given <see cref="DependencyObject"/> instance is a descendant of another one.
|
||||
/// </summary>
|
||||
/// <param name="child">The input child element.</param>
|
||||
/// <param name="element">The element to look for in the ascendants hierarchy for <paramref name="child"/>.</param>
|
||||
/// <returns>Whether or not <paramref name="child"/> is a descendant of <paramref name="element"/>.</returns>
|
||||
public static bool IsDescendantOf(this DependencyObject child, DependencyObject element)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
DependencyObject? parent = VisualTreeHelper.GetParent(child);
|
||||
|
||||
if (parent is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parent == element)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
child = parent;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether or not a given <see cref="DependencyObject"/> instance is an ascendant of another one.
|
||||
/// </summary>
|
||||
/// <param name="parent">The input parent element.</param>
|
||||
/// <param name="element">The element to look for in the descendants hierarchy for <paramref name="parent"/>.</param>
|
||||
/// <returns>Whether or not <paramref name="parent"/> is an ascendant of <paramref name="element"/>.</returns>
|
||||
public static bool IsAscendantOf(this DependencyObject parent, DependencyObject element)
|
||||
{
|
||||
return IsDescendantOf(element, parent);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -63,7 +63,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="predicate">The predicate to use to match the child nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the child nodes.</param>
|
||||
/// <returns>The child that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindChild<T>(this FrameworkElement element, Func<T, bool> predicate)
|
||||
where T : notnull, FrameworkElement
|
||||
|
@ -80,7 +80,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// <typeparam name="TState">The type of state to use when matching nodes.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
|
||||
/// <param name="predicate">The predicate to use to match the child nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the child nodes.</param>
|
||||
/// <returns>The child that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindChild<T, TState>(this FrameworkElement element, TState state, Func<T, TState, bool> predicate)
|
||||
where T : notnull, FrameworkElement
|
||||
|
@ -96,7 +96,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <typeparam name="TPredicate">The type of predicate in use.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="predicate">The predicate to use to match the child nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the child nodes.</param>
|
||||
/// <returns>The child that was found, or <see langword="null"/>.</returns>
|
||||
private static T? FindChild<T, TPredicate>(this FrameworkElement element, ref TPredicate predicate)
|
||||
where T : notnull, FrameworkElement
|
||||
|
@ -296,7 +296,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="predicate">The predicate to use to match the child nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the child nodes.</param>
|
||||
/// <returns>The child (or self) that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindChildOrSelf<T>(this FrameworkElement element, Func<T, bool> predicate)
|
||||
where T : notnull, FrameworkElement
|
||||
|
@ -316,7 +316,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// <typeparam name="TState">The type of state to use when matching nodes.</typeparam>
|
||||
/// <param name="element">The root element.</param>
|
||||
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
|
||||
/// <param name="predicate">The predicate to use to match the child nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the child nodes.</param>
|
||||
/// <returns>The child (or self) that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindChildOrSelf<T, TState>(this FrameworkElement element, TState state, Func<T, TState, bool> predicate)
|
||||
where T : notnull, FrameworkElement
|
||||
|
@ -490,7 +490,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <param name="element">The starting element.</param>
|
||||
/// <param name="predicate">The predicate to use to match the parent nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the parent nodes.</param>
|
||||
/// <returns>The parent that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindParent<T>(this FrameworkElement element, Func<T, bool> predicate)
|
||||
where T : notnull, FrameworkElement
|
||||
|
@ -507,7 +507,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// <typeparam name="TState">The type of state to use when matching nodes.</typeparam>
|
||||
/// <param name="element">The starting element.</param>
|
||||
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
|
||||
/// <param name="predicate">The predicate to use to match the parent nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the parent nodes.</param>
|
||||
/// <returns>The parent that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindParent<T, TState>(this FrameworkElement element, TState state, Func<T, TState, bool> predicate)
|
||||
where T : notnull, FrameworkElement
|
||||
|
@ -523,7 +523,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <typeparam name="TPredicate">The type of predicate in use.</typeparam>
|
||||
/// <param name="element">The starting element.</param>
|
||||
/// <param name="predicate">The predicate to use to match the parent nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the parent nodes.</param>
|
||||
/// <returns>The parent that was found, or <see langword="null"/>.</returns>
|
||||
private static T? FindParent<T, TPredicate>(this FrameworkElement element, ref TPredicate predicate)
|
||||
where T : notnull, FrameworkElement
|
||||
|
@ -600,7 +600,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements to match.</typeparam>
|
||||
/// <param name="element">The starting element.</param>
|
||||
/// <param name="predicate">The predicate to use to match the parent nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the parent nodes.</param>
|
||||
/// <returns>The parent (or self) that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindParentOrSelf<T>(this FrameworkElement element, Func<T, bool> predicate)
|
||||
where T : notnull, FrameworkElement
|
||||
|
@ -620,7 +620,7 @@ namespace Microsoft.Toolkit.Uwp.UI
|
|||
/// <typeparam name="TState">The type of state to use when matching nodes.</typeparam>
|
||||
/// <param name="element">The starting element.</param>
|
||||
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
|
||||
/// <param name="predicate">The predicate to use to match the parent nodes.</param>
|
||||
/// <param name="predicate">The predicatee to use to match the parent nodes.</param>
|
||||
/// <returns>The parent (or self) that was found, or <see langword="null"/>.</returns>
|
||||
public static T? FindParentOrSelf<T, TState>(this FrameworkElement element, TState state, Func<T, TState, bool> predicate)
|
||||
where T : notnull, FrameworkElement
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Predicates
|
|||
private readonly TState state;
|
||||
|
||||
/// <summary>
|
||||
/// The predicate to use to match items.
|
||||
/// The predicatee to use to match items.
|
||||
/// </summary>
|
||||
private readonly Func<T, TState, bool> predicate;
|
||||
|
||||
|
@ -29,7 +29,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Predicates
|
|||
/// Initializes a new instance of the <see cref="PredicateByFunc{T, TState}"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
|
||||
/// <param name="predicate">The predicate to use to match items.</param>
|
||||
/// <param name="predicate">The predicatee to use to match items.</param>
|
||||
public PredicateByFunc(TState state, Func<T, TState, bool> predicate)
|
||||
{
|
||||
this.state = state;
|
||||
|
|
|
@ -15,14 +15,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Predicates
|
|||
where T : class
|
||||
{
|
||||
/// <summary>
|
||||
/// The predicate to use to match items.
|
||||
/// The predicatee to use to match items.
|
||||
/// </summary>
|
||||
private readonly Func<T, bool> predicate;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PredicateByFunc{T}"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="predicate">The predicate to use to match items.</param>
|
||||
/// <param name="predicate">The predicatee to use to match items.</param>
|
||||
public PredicateByFunc(Func<T, bool> predicate)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Helpers.Internals
|
||||
{
|
||||
/// <summary>
|
||||
/// A simple buffer writer implementation using pooled arrays.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of items to store in the list.</typeparam>
|
||||
/// <remarks>
|
||||
/// This type is a <see langword="ref"/> <see langword="struct"/> to avoid the object allocation and to
|
||||
/// enable the pattern-based <see cref="IDisposable"/> support. We aren't worried with consumers not
|
||||
/// using this type correctly since it's private and only accessible within the parent type.
|
||||
/// </remarks>
|
||||
internal struct ArrayPoolBufferWriter<T> : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The default buffer size to use to expand empty arrays.
|
||||
/// </summary>
|
||||
private const int DefaultInitialBufferSize = 128;
|
||||
|
||||
/// <summary>
|
||||
/// The underlying <typeparamref name="T"/> array.
|
||||
/// </summary>
|
||||
private T[] array;
|
||||
|
||||
/// <summary>
|
||||
/// The starting offset within <see cref="array"/>.
|
||||
/// </summary>
|
||||
private int index;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="ArrayPoolBufferWriter{T}"/> struct.
|
||||
/// </summary>
|
||||
/// <returns>A new <see cref="ArrayPoolBufferWriter{T}"/> instance.</returns>
|
||||
[Pure]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ArrayPoolBufferWriter<T> Create()
|
||||
{
|
||||
return new() { array = ArrayPool<T>.Shared.Rent(DefaultInitialBufferSize) };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total number of items stored in the current instance.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => this.array.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item at the specified offset into the current buffer in use.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the element to retrieve.</param>
|
||||
/// <returns>The item at the specified offset into the current buffer in use.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="index"/> is out of range.</exception>
|
||||
public T this[int index]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get
|
||||
{
|
||||
if ((uint)index >= this.index)
|
||||
{
|
||||
static void Throw() => throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
Throw();
|
||||
}
|
||||
|
||||
return this.array[index];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new item to the current collection.
|
||||
/// </summary>
|
||||
/// <param name="item">The item to add.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Add(T item)
|
||||
{
|
||||
if (this.index == this.array.Length)
|
||||
{
|
||||
ResizeBuffer();
|
||||
}
|
||||
|
||||
this.array[this.index++] = item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the underlying array and the stored items.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
Array.Clear(this.array, 0, this.index);
|
||||
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resizes <see cref="array"/> when there is no space left for new items.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private void ResizeBuffer()
|
||||
{
|
||||
T[] rent = ArrayPool<T>.Shared.Rent(this.index << 2);
|
||||
|
||||
Array.Copy(this.array, 0, rent, 0, this.index);
|
||||
Array.Clear(this.array, 0, this.index);
|
||||
|
||||
ArrayPool<T>.Shared.Return(this.array);
|
||||
|
||||
this.array = rent;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDisposable.Dispose"/>
|
||||
public void Dispose()
|
||||
{
|
||||
Array.Clear(this.array, 0, this.index);
|
||||
|
||||
ArrayPool<T>.Shared.Return(this.array);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Toolkit.Uwp;
|
||||
|
@ -53,43 +52,6 @@ namespace UnitTests.Extensions
|
|||
});
|
||||
}
|
||||
|
||||
[TestCategory("VisualTree")]
|
||||
[TestMethod]
|
||||
[DataRow(SearchType.DepthFirst)]
|
||||
[DataRow(SearchType.BreadthFirst)]
|
||||
public async Task Test_VisualTree_FindDescendantByName_Exists(SearchType searchType)
|
||||
{
|
||||
await App.DispatcherQueue.EnqueueAsync(async () =>
|
||||
{
|
||||
var treeRoot = XamlReader.Load(@"<Page
|
||||
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
|
||||
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""> <!-- Starting Point -->
|
||||
<Grid>
|
||||
<Grid>
|
||||
<Border/>
|
||||
<StackPanel>
|
||||
<TextBox/>
|
||||
<TextBlock x:Name=""TargetElement""/> <!-- Target -->
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>") as Page;
|
||||
|
||||
// Test Setup
|
||||
Assert.IsNotNull(treeRoot, "XAML Failed to Load");
|
||||
|
||||
// Initialize Visual Tree
|
||||
await SetTestContentAsync(treeRoot);
|
||||
|
||||
// Main Test
|
||||
var textBlock = treeRoot.FindDescendant("TargetElement", StringComparison.Ordinal, searchType);
|
||||
|
||||
Assert.IsNotNull(textBlock, "Expected to find something.");
|
||||
Assert.IsInstanceOfType(textBlock, typeof(TextBlock), "Didn't find expected typed element.");
|
||||
Assert.AreEqual("TargetElement", textBlock.Name, "Didn't find named element.");
|
||||
});
|
||||
}
|
||||
|
||||
[TestCategory("VisualTree")]
|
||||
[TestMethod]
|
||||
public async Task Test_VisualTree_FindDescendantByName_NotFound()
|
||||
|
@ -157,42 +119,6 @@ namespace UnitTests.Extensions
|
|||
});
|
||||
}
|
||||
|
||||
[TestCategory("VisualTree")]
|
||||
[TestMethod]
|
||||
[DataRow(SearchType.DepthFirst)]
|
||||
[DataRow(SearchType.BreadthFirst)]
|
||||
public async Task Test_VisualTree_FindDescendant_Exists(SearchType searchType)
|
||||
{
|
||||
await App.DispatcherQueue.EnqueueAsync(async () =>
|
||||
{
|
||||
var treeRoot = XamlReader.Load(@"<Page
|
||||
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
|
||||
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""> <!-- Starting Point -->
|
||||
<Grid>
|
||||
<Grid>
|
||||
<Border/>
|
||||
<StackPanel>
|
||||
<TextBox/>
|
||||
<TextBlock/> <!-- Target -->
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>") as Page;
|
||||
|
||||
// Test Setup
|
||||
Assert.IsNotNull(treeRoot, "XAML Failed to Load");
|
||||
|
||||
// Initialize Visual Tree
|
||||
await SetTestContentAsync(treeRoot);
|
||||
|
||||
// Main Test
|
||||
var textBlock = treeRoot.FindDescendant<TextBlock>(searchType);
|
||||
|
||||
Assert.IsNotNull(textBlock, "Expected to find something.");
|
||||
Assert.IsInstanceOfType(textBlock, typeof(TextBlock), "Didn't find expected typed element.");
|
||||
});
|
||||
}
|
||||
|
||||
[TestCategory("VisualTree")]
|
||||
[TestMethod]
|
||||
public async Task Test_VisualTree_FindDescendant_ItemsControl_Exists()
|
||||
|
@ -231,46 +157,6 @@ namespace UnitTests.Extensions
|
|||
});
|
||||
}
|
||||
|
||||
[TestCategory("VisualTree")]
|
||||
[TestMethod]
|
||||
[DataRow(SearchType.DepthFirst)]
|
||||
[DataRow(SearchType.BreadthFirst)]
|
||||
public async Task Test_VisualTree_FindDescendant_ItemsControl_Exists(SearchType searchType)
|
||||
{
|
||||
await App.DispatcherQueue.EnqueueAsync(async () =>
|
||||
{
|
||||
var treeRoot = XamlReader.Load(@"<Page
|
||||
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
|
||||
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""> <!-- Starting Point -->
|
||||
<Grid>
|
||||
<Grid>
|
||||
<Border/>
|
||||
<Pivot>
|
||||
<PivotItem>
|
||||
<TextBox/>
|
||||
</PivotItem>
|
||||
<PivotItem>
|
||||
<TextBlock/> <!-- Target -->
|
||||
</PivotItem>
|
||||
</Pivot>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>") as Page;
|
||||
|
||||
// Test Setup
|
||||
Assert.IsNotNull(treeRoot, "XAML Failed to Load");
|
||||
|
||||
// Initialize Visual Tree
|
||||
await SetTestContentAsync(treeRoot);
|
||||
|
||||
// Main Test
|
||||
var textBlock = treeRoot.FindDescendant<TextBlock>(searchType);
|
||||
|
||||
Assert.IsNotNull(textBlock, "Expected to find something.");
|
||||
Assert.IsInstanceOfType(textBlock, typeof(TextBlock), "Didn't find expected typed element.");
|
||||
});
|
||||
}
|
||||
|
||||
[TestCategory("VisualTree")]
|
||||
[TestMethod]
|
||||
public async Task Test_VisualTree_FindDescendant_NotFound()
|
||||
|
@ -351,55 +237,6 @@ namespace UnitTests.Extensions
|
|||
});
|
||||
}
|
||||
|
||||
[TestCategory("VisualTree")]
|
||||
[TestMethod]
|
||||
[DataRow(SearchType.DepthFirst)]
|
||||
[DataRow(SearchType.BreadthFirst)]
|
||||
public async Task Test_VisualTree_FindDescendants_Exists(SearchType searchType)
|
||||
{
|
||||
await App.DispatcherQueue.EnqueueAsync(async () =>
|
||||
{
|
||||
var treeRoot = XamlReader.Load(@"<Page
|
||||
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
|
||||
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""> <!-- Starting Point -->
|
||||
<Grid>
|
||||
<Grid>
|
||||
<Border/>
|
||||
<TextBlock x:Name=""One""/> <!-- Target -->
|
||||
<StackPanel>
|
||||
<TextBox/> <!-- Hidden Target -->
|
||||
<TextBlock x:Name=""Two""/> <!-- Target -->
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<TextBlock x:Name=""Three""/> <!-- Target -->
|
||||
</Grid>
|
||||
</Page>") as Page;
|
||||
|
||||
// Test Setup
|
||||
Assert.IsNotNull(treeRoot, "XAML Failed to Load");
|
||||
|
||||
// Initialize Visual Tree
|
||||
await SetTestContentAsync(treeRoot);
|
||||
|
||||
// Main Test
|
||||
var textBlocks = treeRoot.FindDescendants(searchType).OfType<TextBlock>();
|
||||
|
||||
Assert.IsNotNull(textBlocks, "Expected to find something.");
|
||||
|
||||
var array = textBlocks.ToArray();
|
||||
|
||||
Assert.AreEqual(4, array.Length, "Expected to find 4 TextBlock elements.");
|
||||
|
||||
// I don't think we want to guarantee order here, so just care that we can find each one.
|
||||
Assert.IsTrue(array.Any((tb) => tb.Name == "One"), "Couldn't find TextBlock 'One'");
|
||||
Assert.IsTrue(array.Any((tb) => tb.Name == "Two"), "Couldn't find TextBlock 'Two'");
|
||||
Assert.IsTrue(array.Any((tb) => tb.Name == "Three"), "Couldn't find TextBlock 'Three'");
|
||||
|
||||
// TextBox has one in its template!
|
||||
Assert.IsTrue(array.Any((tb) => tb.Name == "PlaceholderTextContentPresenter"), "Couldn't find hidden TextBlock from TextBox.");
|
||||
});
|
||||
}
|
||||
|
||||
[TestCategory("VisualTree")]
|
||||
[TestMethod]
|
||||
public async Task Test_VisualTree_FindDescendants_NotFound()
|
||||
|
@ -439,103 +276,6 @@ namespace UnitTests.Extensions
|
|||
});
|
||||
}
|
||||
|
||||
[TestCategory("VisualTree")]
|
||||
[TestMethod]
|
||||
public async Task Test_VisualTree_FindFirstLevelDescendants_Exists()
|
||||
{
|
||||
await App.DispatcherQueue.EnqueueAsync(async () =>
|
||||
{
|
||||
var treeRoot = XamlReader.Load(@"<Page
|
||||
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
|
||||
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""> <!-- Starting Point -->
|
||||
<Grid>
|
||||
<Border x:Name=""A""/>
|
||||
<TextBlock x:Name=""B""/>
|
||||
<StackPanel x:Name=""C"">
|
||||
<TextBox/>
|
||||
<TextBlock/>
|
||||
</StackPanel>
|
||||
<Grid x:Name=""D"">
|
||||
<TextBlock/>
|
||||
<StackPanel>
|
||||
<TextBox/>
|
||||
<TextBlock/>
|
||||
</StackPanel>
|
||||
<TextBlock/>
|
||||
</Grid>
|
||||
<TextBlock x:Name=""E""/>
|
||||
</Grid>
|
||||
</Page>") as Page;
|
||||
|
||||
// Test Setup
|
||||
Assert.IsNotNull(treeRoot, "XAML Failed to Load");
|
||||
|
||||
// Initialize Visual Tree
|
||||
await SetTestContentAsync(treeRoot);
|
||||
|
||||
// Main Test
|
||||
var rootGrid = treeRoot.FindDescendant<Grid>();
|
||||
var children = rootGrid.FindFirstLevelDescendants().ToArray();
|
||||
|
||||
Assert.AreEqual(5, children.Length, "Expected to find 5 children.");
|
||||
|
||||
Assert.IsTrue(children.Any(c => ((FrameworkElement)c).Name == "A"), "Couldn't find child 'A'");
|
||||
Assert.IsTrue(children.Any(c => ((FrameworkElement)c).Name == "B"), "Couldn't find child 'B'");
|
||||
Assert.IsTrue(children.Any(c => ((FrameworkElement)c).Name == "C"), "Couldn't find child 'C'");
|
||||
Assert.IsTrue(children.Any(c => ((FrameworkElement)c).Name == "D"), "Couldn't find child 'D'");
|
||||
Assert.IsTrue(children.Any(c => ((FrameworkElement)c).Name == "E"), "Couldn't find child 'E'");
|
||||
});
|
||||
}
|
||||
|
||||
[TestCategory("VisualTree")]
|
||||
[TestMethod]
|
||||
public async Task Test_VisualTree_FindFirstLevelDescendantsOrSelf_Exists()
|
||||
{
|
||||
await App.DispatcherQueue.EnqueueAsync(async () =>
|
||||
{
|
||||
var treeRoot = XamlReader.Load(@"<Page
|
||||
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
|
||||
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""> <!-- Starting Point -->
|
||||
<Grid x:Name=""RootGrid"">
|
||||
<Border x:Name=""A""/>
|
||||
<TextBlock x:Name=""B""/>
|
||||
<StackPanel x:Name=""C"">
|
||||
<TextBox/>
|
||||
<TextBlock/>
|
||||
</StackPanel>
|
||||
<Grid x:Name=""D"">
|
||||
<TextBlock/>
|
||||
<StackPanel>
|
||||
<TextBox/>
|
||||
<TextBlock/>
|
||||
</StackPanel>
|
||||
<TextBlock/>
|
||||
</Grid>
|
||||
<TextBlock x:Name=""E""/>
|
||||
</Grid>
|
||||
</Page>") as Page;
|
||||
|
||||
// Test Setup
|
||||
Assert.IsNotNull(treeRoot, "XAML Failed to Load");
|
||||
|
||||
// Initialize Visual Tree
|
||||
await SetTestContentAsync(treeRoot);
|
||||
|
||||
// Main Test
|
||||
var rootGrid = treeRoot.FindDescendant<Grid>();
|
||||
var childrenOrSelf = rootGrid.FindFirstLevelDescendantsOrSelf().ToArray();
|
||||
|
||||
Assert.AreEqual(6, childrenOrSelf.Length, "Expected to find 6 children or self.");
|
||||
|
||||
Assert.IsTrue(childrenOrSelf.Any(c => ((FrameworkElement)c).Name == "RootGrid"), "Couldn't find self");
|
||||
Assert.IsTrue(childrenOrSelf.Any(c => ((FrameworkElement)c).Name == "A"), "Couldn't find child 'A'");
|
||||
Assert.IsTrue(childrenOrSelf.Any(c => ((FrameworkElement)c).Name == "B"), "Couldn't find child 'B'");
|
||||
Assert.IsTrue(childrenOrSelf.Any(c => ((FrameworkElement)c).Name == "C"), "Couldn't find child 'C'");
|
||||
Assert.IsTrue(childrenOrSelf.Any(c => ((FrameworkElement)c).Name == "D"), "Couldn't find child 'D'");
|
||||
Assert.IsTrue(childrenOrSelf.Any(c => ((FrameworkElement)c).Name == "E"), "Couldn't find child 'E'");
|
||||
});
|
||||
}
|
||||
|
||||
[TestCategory("VisualTree")]
|
||||
[TestMethod]
|
||||
public async Task Test_VisualTree_FindAscendant_Exists()
|
||||
|
@ -780,54 +520,6 @@ namespace UnitTests.Extensions
|
|||
});
|
||||
}
|
||||
|
||||
[TestCategory("VisualTree")]
|
||||
[TestMethod]
|
||||
public async Task Test_VisualTree_IsAscendantOrDescendantOf()
|
||||
{
|
||||
await App.DispatcherQueue.EnqueueAsync(async () =>
|
||||
{
|
||||
var treeRoot = XamlReader.Load(@"<Page
|
||||
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
|
||||
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""> <!-- Starting Point -->
|
||||
<Grid x:Name=""RootGrid"">
|
||||
<Grid>
|
||||
<Border x:Name=""NestedBorder""/>
|
||||
<StackPanel>
|
||||
<TextBox/>
|
||||
<TextBlock x:Name=""TargetElement""/> <!-- Target -->
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>") as Page;
|
||||
|
||||
// Test Setup
|
||||
Assert.IsNotNull(treeRoot, "XAML Failed to Load");
|
||||
|
||||
// Initialize Visual Tree
|
||||
await SetTestContentAsync(treeRoot);
|
||||
|
||||
// Get the root and target elements
|
||||
var rootGrid = treeRoot.FindDescendant("RootGrid");
|
||||
var nestedBorder = treeRoot.FindDescendant("NestedBorder");
|
||||
var textBlock = treeRoot.FindDescendant("TargetElement");
|
||||
|
||||
Assert.IsTrue(rootGrid.IsAscendantOf(nestedBorder));
|
||||
Assert.IsTrue(rootGrid.IsAscendantOf(textBlock));
|
||||
Assert.IsFalse(rootGrid.IsDescendantOf(nestedBorder));
|
||||
Assert.IsFalse(rootGrid.IsDescendantOf(textBlock));
|
||||
|
||||
Assert.IsTrue(nestedBorder.IsDescendantOf(rootGrid));
|
||||
Assert.IsFalse(nestedBorder.IsDescendantOf(textBlock));
|
||||
Assert.IsFalse(nestedBorder.IsAscendantOf(rootGrid));
|
||||
Assert.IsFalse(nestedBorder.IsAscendantOf(textBlock));
|
||||
|
||||
Assert.IsTrue(textBlock.IsDescendantOf(rootGrid));
|
||||
Assert.IsFalse(textBlock.IsDescendantOf(nestedBorder));
|
||||
Assert.IsFalse(textBlock.IsAscendantOf(rootGrid));
|
||||
Assert.IsFalse(textBlock.IsAscendantOf(nestedBorder));
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Add another Ascendants test where we have something like a ListView which creates a container.
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче