WPFUtils.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Windows;
  5. using System.Windows.Controls;
  6. using System.Windows.Media;
  7. using Image = System.Windows.Controls.Image;
  8. namespace InABox.WPF
  9. {
  10. public static class WPFUtils
  11. {
  12. public static T? FindLogicalParent<T>(this DependencyObject dependencyObject)
  13. where T : DependencyObject
  14. {
  15. DependencyObject? parent = dependencyObject;
  16. do
  17. {
  18. parent = LogicalTreeHelper.GetParent(parent);
  19. } while(parent != null && parent is not T);
  20. return parent as T;
  21. }
  22. public static int GetRow(this Grid grid, DependencyObject dependencyObject)
  23. {
  24. while (true)
  25. {
  26. var parent = LogicalTreeHelper.GetParent(dependencyObject);
  27. if (parent == null)
  28. return -1;
  29. if (parent == grid)
  30. return Grid.GetRow(dependencyObject as UIElement);
  31. dependencyObject = parent;
  32. }
  33. }
  34. public static int GetRowSpan(this Grid grid, DependencyObject dependencyObject)
  35. {
  36. while (true)
  37. {
  38. var parent = LogicalTreeHelper.GetParent(dependencyObject);
  39. if (parent == null)
  40. return -1;
  41. if (parent == grid)
  42. return Grid.GetRowSpan(dependencyObject as UIElement);
  43. dependencyObject = parent;
  44. }
  45. }
  46. public static int GetColumn(this Grid grid, DependencyObject dependencyObject)
  47. {
  48. while (true)
  49. {
  50. var parent = LogicalTreeHelper.GetParent(dependencyObject);
  51. if (parent == null)
  52. return -1;
  53. if (parent == grid)
  54. return Grid.GetColumn(dependencyObject as UIElement);
  55. dependencyObject = parent;
  56. }
  57. }
  58. public static int GetColumnSpan(this Grid grid, DependencyObject dependencyObject)
  59. {
  60. while (true)
  61. {
  62. var parent = LogicalTreeHelper.GetParent(dependencyObject);
  63. if (parent == null)
  64. return -1;
  65. if (parent == grid)
  66. return Grid.GetColumnSpan(dependencyObject as UIElement);
  67. dependencyObject = parent;
  68. }
  69. }
  70. public static void SetGridPosition(this FrameworkElement element, int row, int column, int rowspan = 1, int colspan = 1)
  71. {
  72. element.SetValue(Grid.ColumnProperty, column);
  73. element.SetValue(Grid.ColumnSpanProperty, Math.Max(1, colspan));
  74. element.SetValue(Grid.RowProperty, row);
  75. element.SetValue(Grid.RowSpanProperty, Math.Max(1, rowspan));
  76. }
  77. public static IEnumerable<T> FindVisualChildren<T>(this DependencyObject depObj)
  78. {
  79. if (depObj != null)
  80. //ContentControl cc = depObj as ContentControl;
  81. //if (cc != null)
  82. //{
  83. // if (cc.Content == null)
  84. // yield return null;
  85. // if (cc.Content is T)
  86. // yield return cc.Content as T;
  87. // foreach (var child in FindVisualChildren<T>(cc.Content as DependencyObject))
  88. // yield return child;
  89. //}
  90. //else
  91. for (var i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
  92. {
  93. var child = VisualTreeHelper.GetChild(depObj, i);
  94. if (child is null)
  95. continue;
  96. if (child is T t)
  97. yield return t;
  98. foreach (var childOfChild in FindVisualChildren<T>(child))
  99. yield return childOfChild;
  100. }
  101. }
  102. #region Menu Utils
  103. private static void ItemsControlInsert(ItemsControl menu, FrameworkElement item, int index)
  104. {
  105. if (index != -1)
  106. {
  107. menu.Items.Insert(index, item);
  108. }
  109. else
  110. {
  111. menu.Items.Add(item);
  112. }
  113. }
  114. private static MenuItem DoAddMenuItem(ItemsControl menu, string caption, Bitmap? image, bool enabled, int index = -1)
  115. {
  116. var item = new MenuItem { Header = caption, IsEnabled = enabled };
  117. if (image != null)
  118. item.Icon = new Image() { Source = enabled ? image.AsBitmapImage(24, 24) : image.AsGrayScale().AsBitmapImage(24, 24) };
  119. ItemsControlInsert(menu, item, index);
  120. return item;
  121. }
  122. private static MenuItem DoAddMenuItem(ItemsControl menu, string caption, Bitmap? image, Action? click, bool enabled, int index = -1)
  123. {
  124. var item = DoAddMenuItem(menu, caption, image, enabled, index);
  125. if (click != null)
  126. {
  127. item.Click += (o, e) =>
  128. {
  129. click();
  130. };
  131. }
  132. return item;
  133. }
  134. private static MenuItem DoAddMenuItem<T>(ItemsControl menu, string caption, Bitmap? image, T tag, Action<T> click, bool enabled, int index = -1)
  135. {
  136. var item = DoAddMenuItem(menu, caption, image, enabled, index);
  137. item.Tag = tag;
  138. item.Click += (o, e) =>
  139. {
  140. click((T)(o as MenuItem)!.Tag);
  141. };
  142. return item;
  143. }
  144. public delegate void CheckToggleAction<T>(T tag, bool isChecked);
  145. private static MenuItem DoAddCheckItem<T>(ItemsControl menu, string caption, T tag, CheckToggleAction<T> click, bool isChecked, bool enabled, int index = -1)
  146. {
  147. var item = new MenuItem { Header = caption, IsEnabled = enabled, IsCheckable = true, IsChecked = isChecked };
  148. item.Tag = tag;
  149. item.Click += (o, e) =>
  150. {
  151. click((T)(o as MenuItem)!.Tag, item.IsChecked);
  152. };
  153. ItemsControlInsert(menu, item, index);
  154. return item;
  155. }
  156. private static Separator DoAddSeparator(ItemsControl menu, int index)
  157. {
  158. var separator = new Separator();
  159. ItemsControlInsert(menu, separator, index);
  160. return separator;
  161. }
  162. private static Separator DoAddSeparatorIfNeeded(ItemsControl menu, int index)
  163. {
  164. if (menu.Items.Count == 0) return null;
  165. var lastIndex = index != -1 ? index - 1 : menu.Items.Count - 1;
  166. if (lastIndex < 0 || lastIndex >= menu.Items.Count) return null;
  167. var last = menu.Items[lastIndex];
  168. if (last is Separator) return null;
  169. var separator = new Separator();
  170. ItemsControlInsert(menu, separator, index);
  171. return separator;
  172. }
  173. private static void DoRemoveUnnecessarySeparators(ItemsControl menu)
  174. {
  175. while(menu.Items.Count > 0 && menu.Items[0] is Separator)
  176. {
  177. menu.Items.RemoveAt(0);
  178. }
  179. while(menu.Items.Count > 0 && menu.Items[^1] is Separator)
  180. {
  181. menu.Items.RemoveAt(menu.Items.Count - 1);
  182. }
  183. }
  184. public static Separator AddSeparator(this ContextMenu menu, int index = -1) => DoAddSeparator(menu, index);
  185. public static Separator AddSeparator(this MenuItem menu, int index = -1) => DoAddSeparator(menu, index);
  186. public static Separator? AddSeparatorIfNeeded(this ContextMenu menu, int index = -1) => DoAddSeparatorIfNeeded(menu, index);
  187. public static Separator? AddSeparatorIfNeeded(this MenuItem menu, int index = -1) => DoAddSeparatorIfNeeded(menu, index);
  188. public static void RemoveUnnecessarySeparators(this ContextMenu menu) => DoRemoveUnnecessarySeparators(menu);
  189. public static void RemoveUnnecessarySeparators(this MenuItem menu) => DoRemoveUnnecessarySeparators(menu);
  190. public static MenuItem AddItem(this ContextMenu menu, string caption, Bitmap? image, Action? click, bool enabled = true, int index = -1)
  191. => DoAddMenuItem(menu, caption, image, click, enabled, index);
  192. public static MenuItem AddItem(this MenuItem menu, string caption, Bitmap? image, Action? click, bool enabled = true, int index = -1)
  193. => DoAddMenuItem(menu, caption, image, click, enabled, index);
  194. public static MenuItem AddItem<T>(this ContextMenu menu, string caption, Bitmap? image, T tag, Action<T> click, bool enabled = true, int index = -1)
  195. => DoAddMenuItem(menu, caption, image, tag, click, enabled, index);
  196. public static MenuItem AddItem<T>(this MenuItem menu, string caption, Bitmap? image, T tag, Action<T> click, bool enabled = true, int index = -1)
  197. => DoAddMenuItem(menu, caption, image, tag, click, enabled, index);
  198. public static MenuItem AddCheckItem<T>(this ContextMenu menu, string caption, T tag, CheckToggleAction<T> click, bool isChecked = false, bool enabled = true, int index = -1)
  199. => DoAddCheckItem<T>(menu, caption, tag, click, isChecked, enabled, index);
  200. #endregion
  201. }
  202. }