WPFMessageBox.xaml.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. using System;
  2. using System.ComponentModel;
  3. using System.Drawing;
  4. using System.Runtime.InteropServices;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Input;
  8. using System.Windows.Interop;
  9. using System.Windows.Media;
  10. using System.Windows.Media.Animation;
  11. using System.Windows.Media.Imaging;
  12. namespace WPF.Themes.UserControls
  13. {
  14. /// <summary>
  15. /// WPFMessageBox.xaml 的交互逻辑
  16. /// </summary>
  17. public partial class WPFMessageBox : INotifyPropertyChanged
  18. {
  19. private bool _animationRan;
  20. public WPFMessageBox(Window owner, string message, string details, MessageBoxButton button, MessageBoxImage icon,
  21. MessageBoxResult defaultResult, MessageBoxOptions options)
  22. {
  23. _animationRan = false;
  24. InitializeComponent();
  25. //Owner = owner ?? Application.Current.MainWindow;
  26. CreateButtons(button, defaultResult);
  27. CreateImage(icon);
  28. MessageText.Text = message;
  29. DetailsExpander.Visibility = string.IsNullOrEmpty(details) ? Visibility.Collapsed : Visibility.Visible;
  30. DetailsText.Text = details;
  31. ApplyOptions(options);
  32. }
  33. public MessageBoxResult MessageBoxResult { get; set; }
  34. #region INotifyPropertyChanged Members
  35. public event PropertyChangedEventHandler PropertyChanged;
  36. #endregion
  37. #region Create Buttons
  38. /// <summary>
  39. /// Create the message box's button according to the user's demand
  40. /// </summary>
  41. /// <param name="button">The user's buttons selection</param>
  42. /// <param name="defaultResult">The default button</param>
  43. private void CreateButtons(MessageBoxButton button, MessageBoxResult defaultResult)
  44. {
  45. switch (button)
  46. {
  47. case MessageBoxButton.OK:
  48. ButtonsPanel.Children.Add(CreateOkButton(defaultResult));
  49. break;
  50. case MessageBoxButton.OKCancel:
  51. ButtonsPanel.Children.Add(CreateOkButton(defaultResult));
  52. ButtonsPanel.Children.Add(CreateCancelButton(defaultResult));
  53. break;
  54. case MessageBoxButton.YesNoCancel:
  55. ButtonsPanel.Children.Add(CreateYesButton(defaultResult));
  56. ButtonsPanel.Children.Add(CreateNoButton(defaultResult));
  57. ButtonsPanel.Children.Add(CreateCancelButton(defaultResult));
  58. break;
  59. case MessageBoxButton.YesNo:
  60. ButtonsPanel.Children.Add(CreateYesButton(defaultResult));
  61. ButtonsPanel.Children.Add(CreateNoButton(defaultResult));
  62. break;
  63. default:
  64. throw new ArgumentOutOfRangeException("button");
  65. }
  66. }
  67. /// <summary>
  68. /// Create the ok button on demand
  69. /// </summary>
  70. /// <param name="defaultResult"></param>
  71. /// <returns></returns>
  72. private Button CreateOkButton(MessageBoxResult defaultResult)
  73. {
  74. var okButton = new Button
  75. {
  76. Name = "okButton",
  77. Content = ((string)Application.Current.Resources["Confirm"]),
  78. IsDefault = defaultResult == MessageBoxResult.OK,
  79. Tag = MessageBoxResult.OK,
  80. };
  81. okButton.Click += ButtonClick;
  82. return okButton;
  83. }
  84. /// <summary>
  85. /// Create the cancel button on demand
  86. /// </summary>
  87. /// <param name="defaultResult"></param>
  88. /// <returns></returns>
  89. private Button CreateCancelButton(MessageBoxResult defaultResult)
  90. {
  91. var cancelButton = new Button
  92. {
  93. Name = "cancelButton",
  94. Content = ((string)Application.Current.Resources["Cancel"]),
  95. IsDefault = defaultResult == MessageBoxResult.Cancel,
  96. IsCancel = true,
  97. Tag = MessageBoxResult.Cancel,
  98. };
  99. cancelButton.Click += ButtonClick;
  100. return cancelButton;
  101. }
  102. /// <summary>
  103. /// Create the yes button on demand
  104. /// </summary>
  105. /// <param name="defaultResult"></param>
  106. /// <returns></returns>
  107. private Button CreateYesButton(MessageBoxResult defaultResult)
  108. {
  109. var yesButton = new Button
  110. {
  111. Name = "yesButton",
  112. Content = ((string)Application.Current.Resources["Yes"]),
  113. IsDefault = defaultResult == MessageBoxResult.Yes,
  114. Tag = MessageBoxResult.Yes,
  115. };
  116. yesButton.Click += ButtonClick;
  117. return yesButton;
  118. }
  119. /// <summary>
  120. /// Create the no button on demand
  121. /// </summary>
  122. /// <param name="defaultResult"></param>
  123. /// <returns></returns>
  124. private Button CreateNoButton(MessageBoxResult defaultResult)
  125. {
  126. var noButton = new Button
  127. {
  128. Name = "noButton",
  129. Content = ((string)Application.Current.Resources["No"]),
  130. IsDefault = defaultResult == MessageBoxResult.No,
  131. Tag = MessageBoxResult.No,
  132. };
  133. noButton.Click += ButtonClick;
  134. return noButton;
  135. }
  136. /// <summary>
  137. /// The event the buttons trigger.
  138. /// Each button hold it's result in the tag, so here it just sets them and close the message box.
  139. /// </summary>
  140. /// <param name="sender"></param>
  141. /// <param name="e"></param>
  142. private void ButtonClick(object sender, RoutedEventArgs e)
  143. {
  144. MessageBoxResult = (MessageBoxResult)(sender as Button).Tag;
  145. Close();
  146. }
  147. #endregion
  148. private void ApplyOptions(MessageBoxOptions options)
  149. {
  150. if ((options & MessageBoxOptions.RightAlign) == MessageBoxOptions.RightAlign)
  151. {
  152. MessageText.TextAlignment = TextAlignment.Right;
  153. DetailsText.TextAlignment = TextAlignment.Right;
  154. }
  155. if ((options & MessageBoxOptions.RtlReading) == MessageBoxOptions.RtlReading)
  156. {
  157. FlowDirection = FlowDirection.RightToLeft;
  158. }
  159. }
  160. /// <summary>
  161. /// Create the image from the system's icons
  162. /// </summary>
  163. /// <param name="icon"></param>
  164. private void CreateImage(MessageBoxImage icon)
  165. {
  166. switch (icon)
  167. {
  168. case MessageBoxImage.None:
  169. ImagePlaceholder.Visibility = Visibility.Collapsed;
  170. break;
  171. case MessageBoxImage.Information:
  172. ImagePlaceholder.Source = SystemIcons.Information.ToImageSource();
  173. break;
  174. case MessageBoxImage.Question:
  175. ImagePlaceholder.Source = SystemIcons.Question.ToImageSource();
  176. break;
  177. case MessageBoxImage.Warning:
  178. ImagePlaceholder.Source = SystemIcons.Warning.ToImageSource();
  179. break;
  180. case MessageBoxImage.Error:
  181. ImagePlaceholder.Source = SystemIcons.Error.ToImageSource();
  182. break;
  183. default:
  184. throw new ArgumentOutOfRangeException("icon");
  185. }
  186. }
  187. public void OnPropertyChanged(string propertyName)
  188. {
  189. PropertyChangedEventHandler temp = PropertyChanged;
  190. if (temp != null)
  191. {
  192. temp(this, new PropertyChangedEventArgs(propertyName));
  193. }
  194. }
  195. /// <summary>
  196. /// Enable dragging
  197. /// </summary>
  198. /// <param name="sender"></param>
  199. /// <param name="e"></param>
  200. private void Window_MouseDown(object sender, MouseButtonEventArgs e)
  201. {
  202. if (e.LeftButton == MouseButtonState.Pressed)
  203. DragMove();
  204. }
  205. /// <summary>
  206. /// Show the startup animation
  207. /// </summary>
  208. /// <param name="sender"></param>
  209. /// <param name="e"></param>
  210. private void Window_Loaded(object sender, RoutedEventArgs e)
  211. {
  212. // This is set here to height after the width has been set
  213. // so the details expander won't stretch the message box when it's opened
  214. SizeToContent = SizeToContent.Height;
  215. var animation = TryFindResource("LoadAnimation") as Storyboard;
  216. animation.Begin(this);
  217. }
  218. /// <summary>
  219. /// Show the closing animation
  220. /// </summary>
  221. /// <param name="sender"></param>
  222. /// <param name="e"></param>
  223. private void MessageBoxWindow_Closing(object sender, CancelEventArgs e)
  224. {
  225. if (!_animationRan)
  226. {
  227. // The animation won't run if the window is allowed to close,
  228. // so here the animation starts, and the window's closing is canceled
  229. e.Cancel = true;
  230. var animation = TryFindResource("UnloadAnimation") as Storyboard;
  231. animation.Completed += AnimationCompleted;
  232. animation.Begin(this);
  233. }
  234. }
  235. /// <summary>
  236. /// Signals the closing animation ran, and close the window (for real this time)
  237. /// </summary>
  238. /// <param name="sender"></param>
  239. /// <param name="e"></param>
  240. private void AnimationCompleted(object sender, EventArgs e)
  241. {
  242. _animationRan = true;
  243. Close();
  244. }
  245. #region Show Information
  246. /// <summary>
  247. /// Display an information message
  248. /// </summary>
  249. /// <param name="message">The message text</param>
  250. /// <param name="details">The details part text</param>
  251. /// <param name="showCancel">Display the cancel</param>
  252. /// <param name="options">Misc options</param>
  253. /// <returns>The user's selected button</returns>
  254. public static MessageBoxResult ShowInformation(string message, string details = "", bool showCancel = false,
  255. MessageBoxOptions options = MessageBoxOptions.None)
  256. {
  257. return ShowInformation(null, message, details, showCancel, options);
  258. }
  259. /// <summary>
  260. /// Display an information message
  261. /// </summary>
  262. /// <param name="owner">The message box's parent window</param>
  263. /// <param name="message">The message text</param>
  264. /// <param name="details">The details part text</param>
  265. /// <param name="showCancel">Display the cancel</param>
  266. /// <param name="options">Misc options</param>
  267. /// <returns>The user's selected button</returns>
  268. public static MessageBoxResult ShowInformation(Window owner, string message, string details = "",
  269. bool showCancel = false,
  270. MessageBoxOptions options = MessageBoxOptions.None)
  271. {
  272. return Show(owner, message, details, showCancel ? MessageBoxButton.OKCancel : MessageBoxButton.OK,
  273. MessageBoxImage.Information, MessageBoxResult.OK, options);
  274. }
  275. #endregion
  276. #region Show Question
  277. /// <summary>
  278. /// Display a question
  279. /// </summary>
  280. /// <param name="message">The message text</param>
  281. /// <param name="details">The details part text</param>
  282. /// <param name="showCancel">Display the cancel</param>
  283. /// <param name="options">Misc options</param>
  284. /// <returns>The user's selected button</returns>
  285. public static MessageBoxResult ShowQuestion(string message, string details = "",
  286. bool showCancel = false,
  287. MessageBoxOptions options = MessageBoxOptions.None)
  288. {
  289. return ShowQuestion(null, message, details, showCancel, options);
  290. }
  291. /// <summary>
  292. /// Display a question
  293. /// </summary>
  294. /// <param name="owner">The message box's parent window</param>
  295. /// <param name="message">The message text</param>
  296. /// <param name="details">The details part text</param>
  297. /// <param name="showCancel">Display the cancel</param>
  298. /// <param name="options">Misc options</param>
  299. /// <returns>The user's selected button</returns>
  300. public static MessageBoxResult ShowQuestion(Window owner, string message, string details = "",
  301. bool showCancel = false,
  302. MessageBoxOptions options = MessageBoxOptions.None)
  303. {
  304. return Show(owner, message, details, showCancel ? MessageBoxButton.YesNoCancel : MessageBoxButton.YesNo,
  305. MessageBoxImage.Question, MessageBoxResult.Yes, options);
  306. }
  307. #endregion
  308. #region Show Warning
  309. /// <summary>
  310. /// Display a warning
  311. /// </summary>
  312. /// <param name="message">The message text</param>
  313. /// <param name="details">The details part text</param>
  314. /// <param name="showCancel">Display the cancel</param>
  315. /// <param name="options">Misc options</param>
  316. /// <returns>The user's selected button</returns>
  317. public static MessageBoxResult ShowWarning(string message, string details = "",
  318. bool showCancel = false,
  319. MessageBoxOptions options = MessageBoxOptions.None)
  320. {
  321. return ShowWarning(null, message, details, showCancel, options);
  322. }
  323. /// <summary>
  324. /// Display a warning
  325. /// </summary>
  326. /// <param name="owner">The message box's parent window</param>
  327. /// <param name="message">The message text</param>
  328. /// <param name="details">The details part text</param>
  329. /// <param name="showCancel">Display the cancel</param>
  330. /// <param name="options">Misc options</param>
  331. /// <returns>The user's selected button</returns>
  332. public static MessageBoxResult ShowWarning(Window owner, string message, string details = "",
  333. bool showCancel = false,
  334. MessageBoxOptions options = MessageBoxOptions.None)
  335. {
  336. return Show(owner, message, details, showCancel ? MessageBoxButton.OKCancel : MessageBoxButton.OK,
  337. MessageBoxImage.Warning, MessageBoxResult.OK, options);
  338. }
  339. #endregion
  340. #region Show Error
  341. /// <summary>
  342. /// Display an Error
  343. /// </summary>
  344. /// <param name="exception">Display the exception's details</param>
  345. /// <param name="message">The message text</param>
  346. /// <param name="options">Misc options</param>
  347. /// <returns>The user's selected button</returns>
  348. public static MessageBoxResult ShowError(Exception exception, string message = "",
  349. MessageBoxOptions options = MessageBoxOptions.None)
  350. {
  351. return ShowError(null, exception, message, options);
  352. }
  353. /// <summary>
  354. /// Display an Error
  355. /// </summary>
  356. /// <param name="message">The message text</param>
  357. /// <param name="details">The details part text</param>
  358. /// <param name="showCancel">Display the cancel</param>
  359. /// <param name="options">Misc options</param>
  360. /// <returns>The user's selected button</returns>
  361. public static MessageBoxResult ShowError(string message, string details = "",
  362. bool showCancel = false,
  363. MessageBoxOptions options = MessageBoxOptions.None)
  364. {
  365. return ShowError(null, message, details, showCancel, options);
  366. }
  367. /// <summary>
  368. /// Display an Error
  369. /// </summary>
  370. /// <param name="owner">The message box's parent window</param>
  371. /// <param name="exception">Display the exception's details</param>
  372. /// <param name="message">The message text</param>
  373. /// <param name="options">Misc options</param>
  374. /// <returns>The user's selected button</returns>
  375. public static MessageBoxResult ShowError(Window owner, Exception exception, string message = "",
  376. MessageBoxOptions options = MessageBoxOptions.None)
  377. {
  378. string details = string.Empty;
  379. #if DEBUG
  380. details = exception.ToString();
  381. #endif
  382. return Show(owner, String.IsNullOrEmpty(message) ? exception.Message : message, details, MessageBoxButton.OK,
  383. MessageBoxImage.Error, MessageBoxResult.OK, options);
  384. }
  385. /// <summary>
  386. /// Display an Error
  387. /// </summary>
  388. /// <param name="owner">The message box's parent window</param>
  389. /// <param name="message">The message text</param>
  390. /// <param name="details">The details part text</param>
  391. /// <param name="showCancel">Display the cancel</param>
  392. /// <param name="options">Misc options</param>
  393. /// <returns>The user's selected button</returns>
  394. public static MessageBoxResult ShowError(Window owner, string message, string details = "",
  395. bool showCancel = false,
  396. MessageBoxOptions options = MessageBoxOptions.None)
  397. {
  398. return Show(owner, message, details, showCancel ? MessageBoxButton.OKCancel : MessageBoxButton.OK,
  399. MessageBoxImage.Error, MessageBoxResult.OK, options);
  400. }
  401. #endregion
  402. #region Show
  403. /// <summary>
  404. /// Show the message box with the specified parameters
  405. /// </summary>
  406. /// <param name="message">The message text</param>
  407. /// <param name="details">The details part text</param>
  408. /// <param name="button">The buttons to be displayed</param>
  409. /// <param name="icon">The message's severity</param>
  410. /// <param name="defaultResult">The default button</param>
  411. /// <param name="options">Misc options</param>
  412. /// <returns>The user's selected button</returns>
  413. public static MessageBoxResult Show(string message, string details = "",
  414. MessageBoxButton button = MessageBoxButton.OK,
  415. MessageBoxImage icon = MessageBoxImage.None,
  416. MessageBoxResult defaultResult = MessageBoxResult.None,
  417. MessageBoxOptions options = MessageBoxOptions.None)
  418. {
  419. return Show(null, message, details, button, icon, defaultResult, options);
  420. }
  421. /// <summary>
  422. /// Show the message box with the specified parameters
  423. /// </summary>
  424. /// <param name="message">The message text</param>
  425. /// <param name="button">The buttons to be displayed</param>
  426. /// <param name="icon">The message's severity</param>
  427. /// <param name="defaultResult">The default button</param>
  428. /// <param name="options">Misc options</param>
  429. /// <returns>The user's selected button</returns>
  430. public static MessageBoxResult Show(string message,
  431. MessageBoxButton button = MessageBoxButton.OK,
  432. MessageBoxImage icon = MessageBoxImage.None,
  433. MessageBoxResult defaultResult = MessageBoxResult.None,
  434. MessageBoxOptions options = MessageBoxOptions.None)
  435. {
  436. return Show(message, string.Empty, button, icon, defaultResult, options);
  437. }
  438. /// <summary>
  439. /// Show the message box with the specified parameters
  440. /// </summary>
  441. /// <param name="owner">The message box's parent window</param>
  442. /// <param name="message">The message text</param>
  443. /// <param name="button">The buttons to be displayed</param>
  444. /// <param name="icon">The message's severity</param>
  445. /// <param name="defaultResult">The default button</param>
  446. /// <param name="options">Misc options</param>
  447. /// <returns>The user's selected button</returns>
  448. public static MessageBoxResult Show(Window owner, string message,
  449. MessageBoxButton button = MessageBoxButton.OK,
  450. MessageBoxImage icon = MessageBoxImage.None,
  451. MessageBoxResult defaultResult = MessageBoxResult.None,
  452. MessageBoxOptions options = MessageBoxOptions.None)
  453. {
  454. return Show(owner, message, string.Empty, button, icon, defaultResult, options);
  455. }
  456. /// <summary>
  457. /// Show the message box with the specified parameters
  458. /// </summary>
  459. /// <param name="owner">The message box's parent window</param>
  460. /// <param name="message">The message text</param>
  461. /// <param name="details">The details part text</param>
  462. /// <param name="button">The buttons to be displayed</param>
  463. /// <param name="icon">The message's severity</param>
  464. /// <param name="defaultResult">The default button</param>
  465. /// <param name="options">Misc options</param>
  466. /// <returns>The user's selected button</returns>
  467. public static MessageBoxResult Show(Window owner, string message, string details = "",
  468. MessageBoxButton button = MessageBoxButton.OK,
  469. MessageBoxImage icon = MessageBoxImage.None,
  470. MessageBoxResult defaultResult = MessageBoxResult.None,
  471. MessageBoxOptions options = MessageBoxOptions.None)
  472. {
  473. var result = Application.Current.Dispatcher.Invoke(new Func<MessageBoxResult>(() =>
  474. {
  475. var messageBox = new WPFMessageBox(owner, message, details, button, icon, defaultResult, options);
  476. messageBox.ShowDialog();
  477. return messageBox.MessageBoxResult;
  478. }));
  479. return (MessageBoxResult)result;
  480. }
  481. #endregion
  482. }
  483. public static class IconHelper
  484. {
  485. [DllImport("gdi32.dll", SetLastError = true)]
  486. private static extern bool DeleteObject(IntPtr hObject);
  487. public static ImageSource ToImageSource(this Icon icon)
  488. {
  489. Bitmap bitmap = icon.ToBitmap();
  490. IntPtr hBitmap = bitmap.GetHbitmap();
  491. ImageSource wpfBitmap = Imaging.CreateBitmapSourceFromHBitmap(
  492. hBitmap,
  493. IntPtr.Zero,
  494. Int32Rect.Empty,
  495. BitmapSizeOptions.FromEmptyOptions());
  496. if (!DeleteObject(hBitmap))
  497. {
  498. throw new Win32Exception();
  499. }
  500. return wpfBitmap.GetAsFrozen() as ImageSource;
  501. }
  502. }
  503. }