MessageWindow.xaml.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. using InABox.Clients;
  2. using InABox.Core;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Collections.ObjectModel;
  6. using System.ComponentModel;
  7. using System.Diagnostics.CodeAnalysis;
  8. using System.Linq;
  9. using System.Runtime.CompilerServices;
  10. using System.Windows;
  11. using System.Windows.Controls;
  12. using System.IO;
  13. using System.Windows.Media;
  14. using System.Windows.Media.Imaging;
  15. using InABox.WPF;
  16. namespace InABox.Wpf;
  17. public enum MessageWindowButtonPosition
  18. {
  19. Left,
  20. Right
  21. }
  22. public enum MessageWindowResult
  23. {
  24. None,
  25. OK,
  26. Cancel,
  27. Other
  28. }
  29. public class MessageWindowButton : INotifyPropertyChanged
  30. {
  31. public delegate void MessageWindowButtonDelegate(MessageWindow window, MessageWindowButton button);
  32. public MessageWindowButtonPosition Position { get; set; }
  33. private string _content;
  34. public string Content
  35. {
  36. get => _content;
  37. [MemberNotNull(nameof(_content))]
  38. set
  39. {
  40. _content = value;
  41. OnPropertyChanged();
  42. }
  43. }
  44. public MessageWindowButtonDelegate Action { get; set; }
  45. public MessageWindowButton(string content, MessageWindowButtonDelegate action, MessageWindowButtonPosition position)
  46. {
  47. Content = content;
  48. Action = action;
  49. Position = position;
  50. }
  51. public event PropertyChangedEventHandler? PropertyChanged;
  52. protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
  53. {
  54. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  55. }
  56. }
  57. /// <summary>
  58. /// Interaction logic for MessageWindow.xaml
  59. /// </summary>
  60. public partial class MessageWindow : Window, INotifyPropertyChanged
  61. {
  62. public ObservableCollection<MessageWindowButton> Buttons { get; private set; } = new();
  63. public IEnumerable<MessageWindowButton> LeftButtons => Buttons.Where(x => x.Position == MessageWindowButtonPosition.Left);
  64. public IEnumerable<MessageWindowButton> RightButtons => Buttons.Where(x => x.Position == MessageWindowButtonPosition.Right);
  65. private string _message = "";
  66. public string Message
  67. {
  68. get => _message;
  69. set
  70. {
  71. _message = value;
  72. OnPropertyChanged();
  73. }
  74. }
  75. public ImageSource? _image = null;
  76. public ImageSource? Image
  77. {
  78. get => _image;
  79. set
  80. {
  81. _image = value;
  82. OnPropertyChanged();
  83. }
  84. }
  85. private string _details = "";
  86. public string Details
  87. {
  88. get => _details;
  89. set
  90. {
  91. _details = value;
  92. OnPropertyChanged();
  93. }
  94. }
  95. public static readonly DependencyProperty ShowDetailsProperty = DependencyProperty.Register(nameof(ShowDetails), typeof(bool), typeof(MessageWindow));
  96. public bool ShowDetails
  97. {
  98. get => (bool)GetValue(ShowDetailsProperty);
  99. set => SetValue(ShowDetailsProperty, value);
  100. }
  101. public MessageWindowResult Result { get; set; } = MessageWindowResult.None;
  102. public object? OtherResult { get; set; }
  103. public MessageWindow()
  104. {
  105. InitializeComponent();
  106. Buttons.CollectionChanged += Buttons_CollectionChanged;
  107. }
  108. private void Button_Click(object sender, RoutedEventArgs e)
  109. {
  110. if (sender is not Button button || button.Tag is not MessageWindowButton winButton) return;
  111. winButton.Action(this, winButton);
  112. }
  113. private void Buttons_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
  114. {
  115. OnPropertyChanged(nameof(LeftButtons));
  116. OnPropertyChanged(nameof(RightButtons));
  117. }
  118. public void AddButton(MessageWindowButton button)
  119. {
  120. Buttons.Add(button);
  121. }
  122. public void AddOKButton(string content = "OK")
  123. {
  124. Buttons.Add(new MessageWindowButton(content, OKButton_Click, MessageWindowButtonPosition.Right));
  125. }
  126. public void AddCancelButton(string content = "Cancel")
  127. {
  128. Buttons.Add(new MessageWindowButton(content, CancelButton_Click, MessageWindowButtonPosition.Right));
  129. }
  130. private void CancelButton_Click(MessageWindow window, MessageWindowButton button)
  131. {
  132. Result = MessageWindowResult.Cancel;
  133. Close();
  134. }
  135. private void OKButton_Click(MessageWindow window, MessageWindowButton button)
  136. {
  137. Result = MessageWindowResult.OK;
  138. Close();
  139. }
  140. public event PropertyChangedEventHandler? PropertyChanged;
  141. protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
  142. {
  143. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  144. }
  145. #region Static Constructors
  146. public static readonly BitmapImage _warning = InABox.Wpf.Resources.warning.AsBitmapImage();
  147. public static void ShowMessage(string message, string title, ImageSource? image = null)
  148. {
  149. var window = new MessageWindow
  150. {
  151. Message = message,
  152. Title = title,
  153. Image = image
  154. };
  155. window.AddOKButton();
  156. window.ShowDialog();
  157. }
  158. public static bool ShowOKCancel(string message, string title, ImageSource? image = null)
  159. {
  160. var window = new MessageWindow
  161. {
  162. Message = message,
  163. Title = title,
  164. Image = image
  165. };
  166. window.AddOKButton();
  167. window.AddCancelButton();
  168. window.ShowDialog();
  169. return window.Result == MessageWindowResult.OK;
  170. }
  171. public static bool ShowYesNo(string message, string title, ImageSource? image = null)
  172. {
  173. var window = new MessageWindow
  174. {
  175. Message = message,
  176. Title = title,
  177. Image = image
  178. };
  179. window.AddOKButton("Yes");
  180. window.AddCancelButton("No");
  181. window.ShowDialog();
  182. return window.Result == MessageWindowResult.OK;
  183. }
  184. /// <summary>
  185. /// Display a message box for an exception, giving options to view the logs.
  186. /// </summary>
  187. /// <param name="message">The message to display. Set to <see langword="null"/> to default to the exception message.</param>
  188. /// <param name="exception"></param>
  189. /// <param name="title"></param>
  190. /// <param name="shouldLog">If <see langword="true"/>, also logs the exception.</param>
  191. public static void ShowError(string? message, Exception exception, string title = "Error", bool shouldLog = true, ImageSource? image = null)
  192. {
  193. if (shouldLog)
  194. {
  195. CoreUtils.LogException(ClientFactory.UserID, exception);
  196. }
  197. var window = new MessageWindow
  198. {
  199. Message = message ?? exception.Message,
  200. Title = title,
  201. Details = CoreUtils.FormatException(exception),
  202. Image = image ?? _warning
  203. };
  204. window.AddButton(new MessageWindowButton("Show Logs", ShowLogs_Click, MessageWindowButtonPosition.Left));
  205. var showDetailsButton = new MessageWindowButton("Show Details", (win, button) =>
  206. {
  207. win.ShowDetails = !win.ShowDetails;
  208. button.Content = win.ShowDetails
  209. ? "Hide Details"
  210. : "Show Details";
  211. }, MessageWindowButtonPosition.Left);
  212. window.AddButton(showDetailsButton);
  213. window.AddOKButton();
  214. window.ShowDialog();
  215. }
  216. private static void ShowLogs_Click(MessageWindow window, MessageWindowButton button)
  217. {
  218. var console = new MessageWindowConsole("Logs", Path.Combine(CoreUtils.GetPath(), string.Format("{0:yyyy-MM-dd}.log", DateTime.Today)));
  219. console.ShowDialog();
  220. }
  221. #endregion
  222. }
  223. public class MessageWindowConsole : Console.Console
  224. {
  225. public string FileName { get; set; }
  226. public MessageWindowConsole(string description, string file) : base(description)
  227. {
  228. FileName = file;
  229. ConsoleControl.AllowLoadLogButton = false;
  230. }
  231. protected override void OnLoaded()
  232. {
  233. base.OnLoaded();
  234. if (File.Exists(FileName))
  235. {
  236. var lines = File.ReadLines(FileName);
  237. ConsoleControl.LoadLogEntries(lines);
  238. }
  239. }
  240. protected override string GetLogDirectory()
  241. {
  242. return CoreUtils.GetPath();
  243. }
  244. }