Merge pull request #4791 from CommunityToolkit/revert-4333-feature/extended-tree-helpers

Revert "Feature/extended tree helpers"
This commit is contained in:
Michael Hawker MSFT (XAML Llama) 2022-10-20 16:28:24 -07:00 коммит произвёл GitHub
Родитель b2b1c238e6 7a37ad1f36
Коммит aa39ee5d70
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 47 добавлений и 1016 удалений

Просмотреть файл

@ -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.
}
}