WPFUtils.cs 9.2 KB

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