You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

98 lines
3.2 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Windows;
  5. using System.Windows.Media;
  6. using System.Windows.Media.Media3D;
  7. namespace BPA.UIControl
  8. {
  9. /// <summary>
  10. /// form https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit
  11. /// MaterialDesignThemes.Wpf.Extensions
  12. /// </summary>
  13. public static class Extensions
  14. {
  15. public static IEnumerable<DependencyObject> VisualDepthFirstTraversal(this DependencyObject node)
  16. {
  17. if (node is null) throw new ArgumentNullException(nameof(node));
  18. yield return node;
  19. for (var i = 0; i < VisualTreeHelper.GetChildrenCount(node); i++)
  20. {
  21. var child = VisualTreeHelper.GetChild(node, i);
  22. foreach (var descendant in child.VisualDepthFirstTraversal())
  23. {
  24. yield return descendant;
  25. }
  26. }
  27. }
  28. public static IEnumerable<DependencyObject> VisualBreadthFirstTraversal(this DependencyObject node)
  29. {
  30. if (node is null) throw new ArgumentNullException(nameof(node));
  31. for (var i = 0; i < VisualTreeHelper.GetChildrenCount(node); i++)
  32. {
  33. var child = VisualTreeHelper.GetChild(node, i);
  34. yield return child;
  35. }
  36. for (var i = 0; i < VisualTreeHelper.GetChildrenCount(node); i++)
  37. {
  38. var child = VisualTreeHelper.GetChild(node, i);
  39. foreach (var descendant in child.VisualDepthFirstTraversal())
  40. {
  41. yield return descendant;
  42. }
  43. }
  44. }
  45. public static bool IsAncestorOf(this DependencyObject parent, DependencyObject node)
  46. => node != null && parent.VisualDepthFirstTraversal().Contains(node);
  47. /// <summary>
  48. /// Returns full visual ancestry, starting at the leaf.
  49. /// <para>If element is not of <see cref="Visual"/> or <see cref="Visual3D"/> the
  50. /// logical ancestry is used.</para>
  51. /// </summary>
  52. /// <param name="leaf"></param>
  53. /// <returns></returns>
  54. public static IEnumerable<DependencyObject> GetVisualAncestry(this DependencyObject leaf)
  55. {
  56. while (leaf != null)
  57. {
  58. yield return leaf;
  59. leaf = leaf is Visual || leaf is Visual3D
  60. ? VisualTreeHelper.GetParent(leaf)
  61. : LogicalTreeHelper.GetParent(leaf);
  62. }
  63. }
  64. public static IEnumerable<DependencyObject> GetLogicalAncestry(this DependencyObject leaf)
  65. {
  66. while (leaf != null)
  67. {
  68. yield return leaf;
  69. leaf = LogicalTreeHelper.GetParent(leaf);
  70. }
  71. }
  72. public static bool IsDescendantOf(this DependencyObject leaf, DependencyObject ancestor)
  73. {
  74. DependencyObject parent = null;
  75. foreach (var node in leaf.GetVisualAncestry())
  76. {
  77. if (Equals(node, ancestor))
  78. return true;
  79. parent = node;
  80. }
  81. return parent?.GetLogicalAncestry().Contains(ancestor) == true;
  82. }
  83. }
  84. }