Dialog.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using System.Windows;
  4. using System.Windows.Controls;
  5. using System.Windows.Documents;
  6. using System.Windows.Input;
  7. using System.Windows.Media;
  8. using HandyControl.Data;
  9. using HandyControl.Interactivity;
  10. using HandyControl.Tools;
  11. namespace HandyControl.Controls;
  12. [TemplatePart(Name = BackElement, Type = typeof(Border))]
  13. public class Dialog : ContentControl
  14. {
  15. private const string BackElement = "PART_BackElement";
  16. private string _token;
  17. private Border _backElement;
  18. private AdornerContainer _container;
  19. private static readonly Dictionary<string, FrameworkElement> ContainerDict = new();
  20. private static readonly Dictionary<string, Dialog> DialogDict = new();
  21. public static readonly DependencyProperty IsClosedProperty = DependencyProperty.Register(
  22. nameof(IsClosed), typeof(bool), typeof(Dialog), new PropertyMetadata(ValueBoxes.FalseBox));
  23. public bool IsClosed
  24. {
  25. get => (bool) GetValue(IsClosedProperty);
  26. internal set => SetValue(IsClosedProperty, ValueBoxes.BooleanBox(value));
  27. }
  28. public static readonly DependencyProperty MaskCanCloseProperty = DependencyProperty.RegisterAttached(
  29. "MaskCanClose", typeof(bool), typeof(Dialog), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits));
  30. public static void SetMaskCanClose(DependencyObject element, bool value)
  31. => element.SetValue(MaskCanCloseProperty, ValueBoxes.BooleanBox(value));
  32. public static bool GetMaskCanClose(DependencyObject element)
  33. => (bool) element.GetValue(MaskCanCloseProperty);
  34. public static readonly DependencyProperty MaskBrushProperty = DependencyProperty.Register(
  35. nameof(MaskBrush), typeof(Brush), typeof(Dialog), new PropertyMetadata(default(Brush)));
  36. public Brush MaskBrush
  37. {
  38. get => (Brush) GetValue(MaskBrushProperty);
  39. set => SetValue(MaskBrushProperty, value);
  40. }
  41. public static readonly DependencyProperty TokenProperty = DependencyProperty.RegisterAttached(
  42. "Token", typeof(string), typeof(Dialog), new PropertyMetadata(default(string), OnTokenChanged));
  43. private static void OnTokenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  44. {
  45. if (d is FrameworkElement element)
  46. {
  47. if (e.NewValue == null)
  48. {
  49. Unregister(element);
  50. }
  51. else
  52. {
  53. Register(e.NewValue.ToString(), element);
  54. }
  55. }
  56. }
  57. public static void SetToken(DependencyObject element, string value)
  58. => element.SetValue(TokenProperty, value);
  59. public static string GetToken(DependencyObject element)
  60. => (string) element.GetValue(TokenProperty);
  61. public Dialog()
  62. {
  63. CommandBindings.Add(new CommandBinding(ControlCommands.Close, (s, e) => Close()));
  64. }
  65. public static void Register(string token, FrameworkElement element)
  66. {
  67. if (string.IsNullOrEmpty(token) || element == null) return;
  68. ContainerDict[token] = element;
  69. }
  70. public static void Unregister(string token, FrameworkElement element)
  71. {
  72. if (string.IsNullOrEmpty(token) || element == null) return;
  73. if (ContainerDict.ContainsKey(token))
  74. {
  75. if (ReferenceEquals(ContainerDict[token], element))
  76. {
  77. ContainerDict.Remove(token);
  78. }
  79. }
  80. }
  81. public static void Unregister(FrameworkElement element)
  82. {
  83. if (element == null) return;
  84. var first = ContainerDict.FirstOrDefault(item => ReferenceEquals(element, item.Value));
  85. if (!string.IsNullOrEmpty(first.Key))
  86. {
  87. ContainerDict.Remove(first.Key);
  88. }
  89. }
  90. public static void Unregister(string token)
  91. {
  92. if (string.IsNullOrEmpty(token)) return;
  93. if (ContainerDict.ContainsKey(token))
  94. {
  95. ContainerDict.Remove(token);
  96. }
  97. }
  98. public static Dialog Show<T>(string token = "") where T : new() => Show(new T(), token);
  99. public static Dialog Show(object content, string token = "")
  100. {
  101. var dialog = new Dialog
  102. {
  103. _token = token,
  104. Content = content
  105. };
  106. FrameworkElement element;
  107. AdornerDecorator decorator;
  108. if (string.IsNullOrEmpty(token))
  109. {
  110. element = WindowHelper.GetActiveWindow();
  111. decorator = VisualHelper.GetChild<AdornerDecorator>(element);
  112. }
  113. else
  114. {
  115. Close(token);
  116. DialogDict[token] = dialog;
  117. ContainerDict.TryGetValue(token, out element);
  118. decorator = element is System.Windows.Window ?
  119. VisualHelper.GetChild<AdornerDecorator>(element) :
  120. VisualHelper.GetChild<DialogContainer>(element);
  121. }
  122. if (decorator != null)
  123. {
  124. if (decorator.Child != null)
  125. {
  126. decorator.Child.IsEnabled = false;
  127. }
  128. var layer = decorator.AdornerLayer;
  129. if (layer != null)
  130. {
  131. var container = new AdornerContainer(layer)
  132. {
  133. Child = dialog
  134. };
  135. dialog._container = container;
  136. dialog.IsClosed = false;
  137. layer.Add(container);
  138. }
  139. }
  140. return dialog;
  141. }
  142. public static void Close(string token)
  143. {
  144. if (DialogDict.TryGetValue(token, out Dialog dialog))
  145. {
  146. dialog.Close();
  147. }
  148. }
  149. public void Close()
  150. {
  151. if (string.IsNullOrEmpty(_token))
  152. {
  153. Close(WindowHelper.GetActiveWindow());
  154. }
  155. else if (ContainerDict.TryGetValue(_token, out var element))
  156. {
  157. Close(element);
  158. DialogDict.Remove(_token);
  159. }
  160. }
  161. public override void OnApplyTemplate()
  162. {
  163. base.OnApplyTemplate();
  164. _backElement = GetTemplateChild(BackElement) as Border;
  165. }
  166. protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
  167. {
  168. if (GetMaskCanClose(this) && _backElement is { IsMouseDirectlyOver: true })
  169. {
  170. Close();
  171. }
  172. }
  173. private void Close(DependencyObject element)
  174. {
  175. if (element != null && _container != null)
  176. {
  177. var decorator = VisualHelper.GetChild<AdornerDecorator>(element);
  178. if (decorator != null)
  179. {
  180. if (decorator.Child != null)
  181. {
  182. decorator.Child.IsEnabled = true;
  183. }
  184. var layer = decorator.AdornerLayer;
  185. layer?.Remove(_container);
  186. IsClosed = true;
  187. }
  188. }
  189. }
  190. }