MainWindow.xaml.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. using Microsoft.Win32;
  2. using NTMiner.Views.Ucs;
  3. using NTMiner.Vms;
  4. using System;
  5. using System.ComponentModel;
  6. using System.Windows;
  7. using System.Windows.Controls;
  8. using System.Windows.Input;
  9. using System.Windows.Interop;
  10. using System.Windows.Media;
  11. namespace NTMiner.Views {
  12. public partial class MainWindow : Window, IMaskWindow {
  13. private bool mRestoreIfMove = false;
  14. public MainWindowViewModel Vm { get; private set; }
  15. private HwndSource hwndSource;
  16. private readonly GridLength _leftDrawerGripWidth;
  17. private readonly Brush _btnOverClockBackground;
  18. public MainWindow() {
  19. if (WpfUtil.IsInDesignMode) {
  20. return;
  21. }
  22. if (!NTMinerConsole.IsEnabled) {
  23. NTMinerConsole.Enable();
  24. }
  25. this.Vm = new MainWindowViewModel();
  26. this.DataContext = Vm;
  27. this.MinHeight = 430;
  28. this.MinWidth = 640;
  29. this.Width = AppRoot.MainWindowWidth;
  30. this.Height = AppRoot.MainWindowHeight;
  31. #if DEBUG
  32. NTStopwatch.Start();
  33. #endif
  34. ConsoleWindow.Instance.MouseDown += (sender, e) => {
  35. MoveConsoleWindow();
  36. };
  37. SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
  38. this.Loaded += (sender, e) => {
  39. ConsoleTabItemTopBorder.Margin = new Thickness(0, ConsoleTabItem.ActualHeight - 1, 0, 0);
  40. MoveConsoleWindow();
  41. hwndSource = PresentationSource.FromVisual((Visual)sender) as HwndSource;
  42. hwndSource.AddHook(new HwndSourceHook(Win32Proc.WindowProc));
  43. };
  44. InitializeComponent();
  45. _leftDrawerGripWidth = LeftDrawerGrip.Width;
  46. _btnOverClockBackground = BtnOverClock.Background;
  47. // 下面几行是为了看见设计视图
  48. this.ResizeCursors.Visibility = Visibility.Visible;
  49. this.HideLeftDrawerGrid();
  50. // 上面几行是为了看见设计视图
  51. DateTime lastGetServerMessageOn = DateTime.MinValue;
  52. // 切换了主界面上的Tab时
  53. this.MainTabControl.SelectionChanged += (sender, e) => {
  54. // 延迟创建,以加快主界面的启动
  55. #region
  56. var selectedItem = MainTabControl.SelectedItem;
  57. if (selectedItem == TabItemSpeedTable) {
  58. if (SpeedTableContainer.Child == null) {
  59. SpeedTableContainer.Child = GetSpeedTable();
  60. }
  61. }
  62. else if (selectedItem == TabItemMessage) {
  63. if (MessagesContainer.Child == null) {
  64. MessagesContainer.Child = new Messages();
  65. }
  66. }
  67. else if (selectedItem == TabItemToolbox) {
  68. if (ToolboxContainer.Child == null) {
  69. ToolboxContainer.Child = new Toolbox();
  70. }
  71. }
  72. else if (selectedItem == TabItemMinerProfileOption) {
  73. if (MinerProfileOptionContainer.Child == null) {
  74. MinerProfileOptionContainer.Child = new MinerProfileOption();
  75. }
  76. }
  77. RpcRoot.SetIsServerMessagesVisible(selectedItem == TabItemMessage);
  78. if (selectedItem == TabItemMessage) {
  79. if (lastGetServerMessageOn.AddSeconds(10) < DateTime.Now) {
  80. lastGetServerMessageOn = DateTime.Now;
  81. VirtualRoot.Execute(new LoadNewServerMessageCommand());
  82. }
  83. }
  84. if (selectedItem == ConsoleTabItem) {
  85. ConsoleTabItemTopBorder.Visibility = Visibility.Visible;
  86. }
  87. else {
  88. ConsoleTabItemTopBorder.Visibility = Visibility.Collapsed;
  89. }
  90. #endregion
  91. };
  92. this.IsVisibleChanged += (sender, e) => {
  93. #region
  94. if (this.IsVisible) {
  95. NTMinerContext.IsUiVisible = true;
  96. }
  97. else {
  98. NTMinerContext.IsUiVisible = false;
  99. }
  100. MoveConsoleWindow();
  101. #endregion
  102. };
  103. this.StateChanged += (s, e) => {
  104. #region
  105. if (Vm.MinerProfile.IsShowInTaskbar) {
  106. ShowInTaskbar = true;
  107. }
  108. else {
  109. if (WindowState == WindowState.Minimized) {
  110. ShowInTaskbar = false;
  111. }
  112. else {
  113. ShowInTaskbar = true;
  114. }
  115. }
  116. if (WindowState == WindowState.Maximized) {
  117. ResizeCursors.Visibility = Visibility.Collapsed;
  118. }
  119. else {
  120. ResizeCursors.Visibility = Visibility.Visible;
  121. }
  122. MoveConsoleWindow();
  123. #endregion
  124. };
  125. this.ConsoleRectangle.IsVisibleChanged += (sender, e) => {
  126. MoveConsoleWindow();
  127. };
  128. this.ConsoleRectangle.SizeChanged += (s, e) => {
  129. MoveConsoleWindow();
  130. };
  131. if (this.Width < 860) {
  132. NTMinerConsole.UserWarn("左侧面板已折叠,可点击侧边的'开始挖矿'按钮展开。");
  133. }
  134. this.SizeChanged += (s, e) => {
  135. #region
  136. if (this.Width < 860) {
  137. this.CloseLeftDrawer();
  138. this.BtnAboutNTMiner.Visibility = Visibility.Collapsed;
  139. }
  140. else {
  141. this.OpenLeftDrawer();
  142. this.BtnAboutNTMiner.Visibility = Visibility.Visible;
  143. }
  144. if (!this.ConsoleRectangle.IsVisible) {
  145. if (e.WidthChanged) {
  146. ConsoleWindow.Instance.Width = e.NewSize.Width;
  147. }
  148. if (e.HeightChanged) {
  149. ConsoleWindow.Instance.Height = e.NewSize.Height;
  150. }
  151. }
  152. #endregion
  153. };
  154. NotiCenterWindow.Bind(this, ownerIsTopmost: true);
  155. this.LocationChanged += (sender, e) => {
  156. MoveConsoleWindow();
  157. };
  158. VirtualRoot.BuildCmdPath<TopmostCommand>(path: message => {
  159. UIThread.Execute(() => {
  160. if (!this.Topmost) {
  161. this.Topmost = true;
  162. }
  163. });
  164. }, this.GetType());
  165. VirtualRoot.BuildCmdPath<UnTopmostCommand>(path: message => {
  166. UIThread.Execute(() => {
  167. if (this.Topmost) {
  168. this.Topmost = false;
  169. }
  170. });
  171. }, this.GetType());
  172. VirtualRoot.BuildCmdPath<CloseMainWindowCommand>(path: message => {
  173. UIThread.Execute(() => {
  174. if (message.IsAutoNoUi) {
  175. SwitchToNoUi();
  176. }
  177. else {
  178. this.Close();
  179. }
  180. });
  181. }, location: this.GetType());
  182. this.BuildEventPath<Per1MinuteEvent>("挖矿中时自动切换为无界面模式", LogEnum.DevConsole,
  183. path: message => {
  184. if (NTMinerContext.IsUiVisible && NTMinerContext.Instance.MinerProfile.IsAutoNoUi && NTMinerContext.Instance.IsMining) {
  185. if (NTMinerContext.MainWindowRendedOn.AddMinutes(NTMinerContext.Instance.MinerProfile.AutoNoUiMinutes) < message.BornOn) {
  186. VirtualRoot.ThisLocalInfo(nameof(MainWindow), $"挖矿中界面展示{NTMinerContext.Instance.MinerProfile.AutoNoUiMinutes}分钟后自动切换为无界面模式,可在选项页调整配置");
  187. VirtualRoot.Execute(new CloseMainWindowCommand(isAutoNoUi: true));
  188. }
  189. }
  190. }, location: this.GetType());
  191. #if DEBUG
  192. var elapsedMilliseconds = NTStopwatch.Stop();
  193. if (elapsedMilliseconds.ElapsedMilliseconds > NTStopwatch.ElapsedMilliseconds) {
  194. NTMinerConsole.DevTimeSpan($"耗时{elapsedMilliseconds} {this.GetType().Name}.ctor");
  195. }
  196. #endif
  197. }
  198. private void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e) {
  199. MoveConsoleWindow();
  200. }
  201. #region 改变下面的控制台窗口的尺寸和位置
  202. private void MoveConsoleWindow() {
  203. if (!this.IsLoaded) {
  204. return;
  205. }
  206. ConsoleWindow consoleWindow = ConsoleWindow.Instance;
  207. if (!this.IsVisible || this.WindowState == WindowState.Minimized) {
  208. consoleWindow.Hide();
  209. return;
  210. }
  211. if (!consoleWindow.IsVisible) {
  212. consoleWindow.Show();
  213. }
  214. if (consoleWindow.WindowState != this.WindowState) {
  215. consoleWindow.WindowState = this.WindowState;
  216. }
  217. // -2 -1是因为主窗口有圆角,但下层的控制台窗口不能透明所以不能圆角,把下层的控制台窗口的宽高缩小一点点从而避免看见下层控制台窗口的棱角
  218. if (consoleWindow.Width != this.Width - 2) {
  219. consoleWindow.Width = this.Width - 2;
  220. }
  221. if (consoleWindow.Height != this.Height - 2) {
  222. consoleWindow.Height = this.Height - 2;
  223. }
  224. if (this.WindowState == WindowState.Normal) {
  225. if (consoleWindow.Left != this.Left + 1) {
  226. consoleWindow.Left = this.Left + 1;
  227. }
  228. if (consoleWindow.Top != this.Top + 1) {
  229. consoleWindow.Top = this.Top + 1;
  230. }
  231. }
  232. if (ConsoleRectangle != null && ConsoleRectangle.IsVisible) {
  233. Point point = ConsoleRectangle.TransformToAncestor(this).Transform(new Point(0, 0));
  234. const int paddingLeft = 4;
  235. const int paddingRight = 5;
  236. int marginLeft = paddingLeft + (int)point.X;
  237. int width = (int)this.ActualWidth - marginLeft - paddingRight;
  238. consoleWindow.MoveWindow(marginLeft: marginLeft, marginTop: (int)point.Y, width, height: (int)ConsoleRectangle.ActualHeight);
  239. }
  240. }
  241. #endregion
  242. #region 显示或隐藏半透明遮罩层
  243. // 因为挖矿端主界面是透明的,遮罩方法和普通窗口不同,如果按照通用的方法遮罩的话会导致能透过窗口看见windows桌面或者下面的窗口。
  244. public void ShowMask() {
  245. MaskLayer.Visibility = Visibility.Visible;
  246. }
  247. public void HideMask() {
  248. MaskLayer.Visibility = Visibility.Collapsed;
  249. }
  250. #endregion
  251. #region 主界面左侧的抽屉
  252. // 点击pin按钮
  253. public void BtnLeftDrawerPin_Click(object sender, RoutedEventArgs e) {
  254. if (LeftDrawerGrip.Width != _leftDrawerGripWidth) {
  255. CloseLeftDrawer();
  256. }
  257. else {
  258. OpenLeftDrawer();
  259. }
  260. }
  261. // 点击x按钮
  262. private void BtnLeftDrawerClose_Click(object sender, RoutedEventArgs e) {
  263. CloseLeftDrawer();
  264. }
  265. private void BtnLeftDrawerGrip_Click(object sender, RoutedEventArgs e) {
  266. if (leftDrawer.Visibility == Visibility.Collapsed) {
  267. leftDrawer.Visibility = Visibility.Visible;
  268. }
  269. else {
  270. leftDrawer.Visibility = Visibility.Collapsed;
  271. }
  272. }
  273. private void BtnLeftDrawerGrip_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
  274. OpenLeftDrawer();
  275. }
  276. // 打开左侧抽屉
  277. private void CloseLeftDrawer() {
  278. if (leftDrawer.Visibility == Visibility.Collapsed) {
  279. return;
  280. }
  281. leftDrawer.Visibility = Visibility.Collapsed;
  282. this.ShowLeftDrawerGrid();
  283. PinRotateTransform.Angle = 90;
  284. mainLayer.ColumnDefinitions.Remove(MinerProfileColumn);
  285. MainTabControl.SetValue(Grid.ColumnProperty, mainLayer.ColumnDefinitions.Count - 1);
  286. }
  287. private void ShowLeftDrawerGrid() {
  288. LeftDrawerGrip.Width = _leftDrawerGripWidth;
  289. }
  290. // 关闭左侧抽屉
  291. private void OpenLeftDrawer() {
  292. if (LeftDrawerGrip.Width != _leftDrawerGripWidth) {
  293. return;
  294. }
  295. leftDrawer.Visibility = Visibility.Visible;
  296. this.HideLeftDrawerGrid();
  297. PinRotateTransform.Angle = 0;
  298. if (!mainLayer.ColumnDefinitions.Contains(MinerProfileColumn)) {
  299. mainLayer.ColumnDefinitions.Insert(0, MinerProfileColumn);
  300. }
  301. MainTabControl.SetValue(Grid.ColumnProperty, mainLayer.ColumnDefinitions.Count - 1);
  302. }
  303. private void HideLeftDrawerGrid() {
  304. LeftDrawerGrip.Width = new GridLength(0);
  305. }
  306. #endregion
  307. protected override void OnClosing(CancelEventArgs e) {
  308. if (NTMinerContext.Instance.MinerProfile.IsCloseMeanExit) {
  309. VirtualRoot.Execute(new CloseNTMinerCommand("手动操作,关闭主界面意为退出"));
  310. }
  311. else {
  312. e.Cancel = true;
  313. SwitchToNoUi();
  314. }
  315. }
  316. private void SwitchToNoUi() {
  317. AppRoot.Disable();
  318. this.Hide();
  319. VirtualRoot.Out.ShowSuccess("已切换为无界面模式运行");
  320. }
  321. protected override void OnClosed(EventArgs e) {
  322. base.OnClosed(e);
  323. SystemEvents.SessionSwitch -= SystemEvents_SessionSwitch;
  324. Application.Current.Shutdown();
  325. }
  326. private void Window_MouseDown(object sender, MouseButtonEventArgs e) {
  327. if (e.LeftButton == MouseButtonState.Pressed) {
  328. this.DragMove();
  329. }
  330. }
  331. private void ScrollViewer_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
  332. WpfUtil.ScrollViewer_PreviewMouseDown(sender, e);
  333. }
  334. private void BtnOverClockVisible_Click(object sender, RoutedEventArgs e) {
  335. var speedTableUc = this.GetSpeedTable();
  336. if (MainTabControl.SelectedItem == TabItemSpeedTable) {
  337. speedTableUc.ShowOrHideOverClock(isShow: speedTableUc.IsOverClockVisible == Visibility.Collapsed);
  338. }
  339. else {
  340. speedTableUc.ShowOrHideOverClock(isShow: true);
  341. }
  342. MainTabControl.SelectedItem = TabItemSpeedTable;
  343. IconOverClockEyeClosed.Visibility = speedTableUc.IsOverClockVisible == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
  344. if (IconOverClockEyeClosed.Visibility == Visibility.Visible) {
  345. BtnOverClock.Background = _btnOverClockBackground;
  346. }
  347. else {
  348. BtnOverClock.Background = WpfUtil.WhiteBrush;
  349. }
  350. }
  351. private void BtnOuterUserShowOption_Click(object sender, RoutedEventArgs e) {
  352. MainTabControl.SelectedItem = TabItemMinerProfileOption;
  353. ((MinerProfileOption)MinerProfileOptionContainer.Child).HighlightOuterUser();
  354. }
  355. private void BtnAutomationShowOption_Click(object sender, RoutedEventArgs e) {
  356. MainTabControl.SelectedItem = TabItemMinerProfileOption;
  357. ((MinerProfileOption)MinerProfileOptionContainer.Child).HighlightAutomation();
  358. }
  359. private SpeedTable _speedTable;
  360. private SpeedTable GetSpeedTable() {
  361. if (_speedTable == null) {
  362. _speedTable = new SpeedTable();
  363. }
  364. return _speedTable;
  365. }
  366. private void SwitchWindowState() {
  367. switch (WindowState) {
  368. case WindowState.Normal:
  369. Microsoft.Windows.Shell.SystemCommands.MaximizeWindow(this);
  370. break;
  371. case WindowState.Maximized:
  372. Microsoft.Windows.Shell.SystemCommands.RestoreWindow(this);
  373. break;
  374. }
  375. }
  376. #region 拖动窗口头部
  377. private void RctHeader_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
  378. if (e.ClickCount == 2) {
  379. SwitchWindowState();
  380. return;
  381. }
  382. else if (WindowState == WindowState.Maximized) {
  383. mRestoreIfMove = true;
  384. return;
  385. }
  386. DragMove();
  387. }
  388. private void RctHeader_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
  389. mRestoreIfMove = false;
  390. }
  391. private void RctHeader_PreviewMouseMove(object sender, MouseEventArgs e) {
  392. if (mRestoreIfMove && e.LeftButton == MouseButtonState.Pressed) {
  393. mRestoreIfMove = false;
  394. double percentHorizontal = e.GetPosition(this).X / ActualWidth;
  395. double targetHorizontal = RestoreBounds.Width * percentHorizontal;
  396. double percentVertical = e.GetPosition(this).Y / ActualHeight;
  397. double targetVertical = RestoreBounds.Height * percentVertical;
  398. WindowState = WindowState.Normal;
  399. SafeNativeMethods.GetCursorPos(out SafeNativeMethods.POINT lMousePosition);
  400. Left = lMousePosition.X - targetHorizontal;
  401. Top = lMousePosition.Y - targetVertical;
  402. DragMove();
  403. }
  404. }
  405. #endregion
  406. private void Menu_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
  407. VirtualRoot.Execute(new TopmostCommand());
  408. }
  409. private void Menu_PreviewMouseUp(object sender, MouseButtonEventArgs e) {
  410. VirtualRoot.Execute(new UnTopmostCommand());
  411. }
  412. }
  413. }