├── .gitattributes ├── .gitignore ├── Arthas.Demo ├── App.manifest ├── App.xaml ├── App.xaml.cs ├── Arthas.Demo.csproj ├── Properties │ └── AssemblyInfo.cs ├── Resources │ ├── editIcon.png │ ├── icon.png │ ├── iconMove.png │ ├── pic.jpg │ ├── tabIcon.png │ └── titleMuenIcon.png └── Views │ ├── Caption.xaml │ ├── Caption.xaml.cs │ ├── Caption_Model.cs │ ├── ControlGallery.xaml │ ├── ControlGallery.xaml.cs │ ├── ControlGallery_Model.cs │ ├── ExpanderDemo.xaml │ ├── ExpanderDemo.xaml.cs │ ├── ExpanderDemo_Model.cs │ ├── Main.xaml │ ├── Main.xaml.cs │ └── Main_Model.cs ├── Arthas.Shell ├── Arthas.Shell.csproj ├── Extensions.cs ├── Interop │ ├── GWL.cs │ ├── HT.cs │ ├── POINT.cs │ ├── RECT.cs │ ├── SW.cs │ ├── SWP.cs │ ├── WINDOWPLACEMENT.cs │ ├── WM.cs │ ├── WS.cs │ ├── WVR.cs │ └── Win32.cs ├── MetroWindowBase.cs ├── MetroWindowChrome.cs └── ScreenHelper.cs ├── Arthas.sln ├── Arthas ├── Arthas.csproj ├── Binder │ ├── MetroDialogModel.cs │ └── MetroWindowModel.cs ├── Controls │ ├── MetroBorder.cs │ ├── MetroBorder.xaml │ ├── MetroButton.cs │ ├── MetroButton.xaml │ ├── MetroButtonState.cs │ ├── MetroCaptionMenu.cs │ ├── MetroCaptionMenu.xaml │ ├── MetroCaptionMenuItem.cs │ ├── MetroCaptionMenuItem.xaml │ ├── MetroContextMenu.cs │ ├── MetroContextMenu.xaml │ ├── MetroExpander.cs │ ├── MetroExpander.xaml │ ├── MetroFocusButton.cs │ ├── MetroFocusButton.xaml │ ├── MetroGridTile.cs │ ├── MetroGridTile.xaml │ ├── MetroGroup.cs │ ├── MetroGroup.xaml │ ├── MetroMenuItem.cs │ ├── MetroMenuItem.xaml │ ├── MetroMenuSeparator.cs │ ├── MetroMenuSeparator.xaml │ ├── MetroProgressBar.cs │ ├── MetroProgressBar.xaml │ ├── MetroScrollViewer.cs │ ├── MetroScrollViewer.xaml │ ├── MetroSwitch.cs │ ├── MetroSwitch.xaml │ ├── MetroTabControl.cs │ ├── MetroTabControl.xaml │ ├── MetroTabItem.cs │ ├── MetroTabItem.xaml │ ├── MetroTextBlock.cs │ ├── MetroTextBlock.xaml │ ├── MetroTextBox.cs │ ├── MetroTextBox.xaml │ ├── MetroTextButton.cs │ ├── MetroTextButton.xaml │ ├── MetroTile.cs │ ├── MetroTile.xaml │ ├── MetroWaterfallFlow.cs │ ├── MetroWindow.cs │ ├── MetroWindow.xaml │ └── ProgressBarState.cs ├── Converter │ ├── CornerRadiusToDouble.cs │ ├── DoubleToCornerRadius.cs │ └── DoubleToThickness.cs ├── Properties │ └── AssemblyInfo.cs ├── Resource.cs ├── ThemeBrush.cs ├── ThemeKey.cs └── Themes │ └── Generic.xaml ├── Build.bat ├── Directory.Build.props ├── LICENSE ├── README.md └── Screenshots └── 1.png /.gitattributes: -------------------------------------------------------------------------------- 1 | *.exe filter=lfs diff=lfs merge=lfs -text 2 | *.dll filter=lfs diff=lfs merge=lfs -text 3 | *.png filter=lfs diff=lfs merge=lfs -text 4 | *.jpg filter=lfs diff=lfs merge=lfs -text 5 | *.ico filter=lfs diff=lfs merge=lfs -text 6 | *.zip filter=lfs diff=lfs merge=lfs -text 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vs 3 | bin 4 | obj 5 | 6 | *.user 7 | -------------------------------------------------------------------------------- /Arthas.Demo/App.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Arthas.Demo/App.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | -------------------------------------------------------------------------------- /Arthas.Demo/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using Arthas.Demo.Views; 3 | 4 | namespace Arthas.Demo; 5 | 6 | public partial class App 7 | { 8 | protected override void OnStartup(StartupEventArgs e) 9 | { 10 | base.OnStartup(e); 11 | 12 | var mainModel = new Main_Model(); 13 | var window = mainModel.CreateWindow(); 14 | MainWindow = window; 15 | MainWindow.Show(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Arthas.Demo/Arthas.Demo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | WinExe 4 | App.manifest 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Arthas.Demo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] 4 | -------------------------------------------------------------------------------- /Arthas.Demo/Resources/editIcon.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:7e046688a6f9b00755ef306296470277accda111c9779e57e80a329619453068 3 | size 17869 4 | -------------------------------------------------------------------------------- /Arthas.Demo/Resources/icon.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:ba3763f810ff8d6768b87f27c26fa3163ae21458a71c461248d404d0c868f964 3 | size 18153 4 | -------------------------------------------------------------------------------- /Arthas.Demo/Resources/iconMove.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:f90643ff930631d47f6a6802f1d861e7183949707117b5db51ada2a80a9832a8 3 | size 18206 4 | -------------------------------------------------------------------------------- /Arthas.Demo/Resources/pic.jpg: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:73c0f860410d171b35567575ae0c9b5eb7a65645837390f944f5758c7212e67c 3 | size 119761 4 | -------------------------------------------------------------------------------- /Arthas.Demo/Resources/tabIcon.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:bdd5248ccbcb58948cc2e4d9c6ecfff66de7620e87e5865c7dbe75cf65808fea 3 | size 18307 4 | -------------------------------------------------------------------------------- /Arthas.Demo/Resources/titleMuenIcon.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:6d747940e0141f989c13c37c7bcde0d1d70fac127b7afc9f9b9af917eca58cc5 3 | size 18299 4 | -------------------------------------------------------------------------------- /Arthas.Demo/Views/Caption.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Arthas.Demo/Views/Caption.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Arthas.Demo.Views; 2 | 3 | public partial class Caption 4 | { 5 | public Caption() 6 | { 7 | InitializeComponent(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Arthas.Demo/Views/Caption_Model.cs: -------------------------------------------------------------------------------- 1 | using OpenView; 2 | 3 | namespace Arthas.Demo.Views; 4 | 5 | public class Caption_Model : ViewModel 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /Arthas.Demo/Views/ControlGallery.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /Arthas.Demo/Views/ControlGallery.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Arthas.Demo.Views; 2 | 3 | public partial class ControlGallery 4 | { 5 | public ControlGallery() 6 | { 7 | InitializeComponent(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Arthas.Demo/Views/ControlGallery_Model.cs: -------------------------------------------------------------------------------- 1 | using OpenView; 2 | 3 | namespace Arthas.Demo.Views; 4 | 5 | public class ControlGallery_Model : ViewModel 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /Arthas.Demo/Views/ExpanderDemo.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Arthas.Demo/Views/ExpanderDemo.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Arthas.Demo.Views; 2 | 3 | public partial class ExpanderDemo 4 | { 5 | public ExpanderDemo() 6 | { 7 | InitializeComponent(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Arthas.Demo/Views/ExpanderDemo_Model.cs: -------------------------------------------------------------------------------- 1 | using OpenView; 2 | 3 | namespace Arthas.Demo.Views; 4 | 5 | public class ExpanderDemo_Model : ViewModel 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /Arthas.Demo/Views/Main.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | -------------------------------------------------------------------------------- /Arthas.Demo/Views/Main.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Arthas.Demo.Views; 2 | 3 | public partial class Main 4 | { 5 | public Main() 6 | { 7 | InitializeComponent(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Arthas.Demo/Views/Main_Model.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using Arthas.Binder; 3 | using Arthas.Controls; 4 | 5 | namespace Arthas.Demo.Views; 6 | 7 | public class Main_Model : MetroWindowModel
8 | { 9 | public override string Title => "Arthas.Demo"; 10 | 11 | protected override void OnWindowInitialized(Window window) 12 | { 13 | base.OnWindowInitialized(window); 14 | 15 | window.Width = 1200; 16 | window.Height = 860; 17 | 18 | if (window is MetroWindow metroWindow) 19 | metroWindow.CaptionContent = new Caption_Model().CreateView(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Arthas.Shell/Arthas.Shell.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | disable 4 | true 5 | 6 | 7 | -------------------------------------------------------------------------------- /Arthas.Shell/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace Arthas.Shell; 4 | 5 | public static class Extensions 6 | { 7 | public static void BringToFront(this Window? window) 8 | { 9 | if (window is null) 10 | return; 11 | 12 | try 13 | { 14 | if (!window.IsVisible) 15 | return; 16 | 17 | window.Activate(); 18 | window.Focus(); 19 | } 20 | catch 21 | { 22 | // ignored 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Arthas.Shell/Interop/GWL.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | namespace Arthas.Shell.Interop; 4 | 5 | /// 6 | /// GetWindowLongPtr values, GWL_* 7 | /// 8 | [SuppressMessage("ReSharper", "InconsistentNaming")] 9 | enum GWL 10 | { 11 | STYLE = -16 12 | } 13 | -------------------------------------------------------------------------------- /Arthas.Shell/Interop/HT.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | namespace Arthas.Shell.Interop; 4 | 5 | [SuppressMessage("ReSharper", "InconsistentNaming")] 6 | enum HT 7 | { 8 | CAPTION = 2 9 | } 10 | -------------------------------------------------------------------------------- /Arthas.Shell/Interop/POINT.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace Arthas.Shell.Interop; 6 | 7 | [Serializable] 8 | [StructLayout(LayoutKind.Sequential)] 9 | [SuppressMessage("ReSharper", "InconsistentNaming")] 10 | struct POINT 11 | { 12 | public int X { get; set; } 13 | public int Y { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Arthas.Shell/Interop/RECT.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace Arthas.Shell.Interop; 6 | 7 | [StructLayout(LayoutKind.Sequential, Pack = 0)] 8 | [Serializable] 9 | [SuppressMessage("ReSharper", "InconsistentNaming")] 10 | struct RECT 11 | { 12 | public int Left { get; set; } 13 | 14 | public int Top { get; set; } 15 | 16 | public int Right { get; set; } 17 | 18 | public int Bottom { get; set; } 19 | 20 | public int Width => Right - Left; 21 | 22 | public int Height => Bottom - Top; 23 | 24 | public void Offset(int dx, int dy) 25 | { 26 | Left += dx; 27 | Top += dy; 28 | Right += dx; 29 | Bottom += dy; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Arthas.Shell/Interop/SW.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | namespace Arthas.Shell.Interop; 4 | 5 | /// 6 | /// ShowWindow options 7 | /// 8 | [SuppressMessage("ReSharper", "InconsistentNaming")] 9 | enum SW 10 | { 11 | SHOWMINIMIZED = 2, 12 | SHOWMAXIMIZED = 3 13 | } 14 | -------------------------------------------------------------------------------- /Arthas.Shell/Interop/SWP.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | 4 | namespace Arthas.Shell.Interop; 5 | 6 | /// 7 | /// SetWindowPos options 8 | /// 9 | [Flags] 10 | [SuppressMessage("ReSharper", "InconsistentNaming")] 11 | enum SWP : uint 12 | { 13 | /// 14 | /// Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to the window, even if 15 | /// the 16 | /// window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE is sent only when the window's 17 | /// size is 18 | /// being changed. 19 | /// 20 | FRAMECHANGED = 0x0020, 21 | 22 | /// 23 | /// Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the 24 | /// topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter). 25 | /// 26 | NOACTIVATE = 0x0010, 27 | 28 | /// 29 | /// Retains the current position (ignores X and Y parameters). 30 | /// 31 | NOMOVE = 0x0002, 32 | 33 | /// 34 | /// Does not change the owner window's position in the Z order. 35 | /// 36 | NOOWNERZORDER = 0x0200, 37 | 38 | /// 39 | /// Retains the current size (ignores the cx and cy parameters). 40 | /// 41 | NOSIZE = 0x0001, 42 | 43 | /// 44 | /// Retains the current Z order (ignores the hWndInsertAfter parameter). 45 | /// 46 | NOZORDER = 0x0004, 47 | 48 | /// 49 | /// Displays the window. 50 | /// 51 | SHOWWINDOW = 0x0040 52 | } 53 | -------------------------------------------------------------------------------- /Arthas.Shell/Interop/WINDOWPLACEMENT.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace Arthas.Shell.Interop; 6 | 7 | [Serializable] 8 | [StructLayout(LayoutKind.Sequential)] 9 | [SuppressMessage("ReSharper", "InconsistentNaming")] 10 | class WINDOWPLACEMENT 11 | { 12 | public int length = Marshal.SizeOf(typeof(WINDOWPLACEMENT)); 13 | public int flags; 14 | public SW showCmd; 15 | public POINT minPosition; 16 | public POINT maxPosition; 17 | public RECT normalPosition; 18 | } 19 | -------------------------------------------------------------------------------- /Arthas.Shell/Interop/WM.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | namespace Arthas.Shell.Interop; 4 | 5 | /// 6 | /// Window message values, WM_* 7 | /// 8 | [SuppressMessage("ReSharper", "InconsistentNaming")] 9 | enum WM 10 | { 11 | NCCALCSIZE = 0x0083, 12 | NCPAINT = 0x0085, 13 | NCLBUTTONDOWN = 0x00A1, 14 | DPICHANGED = 0x02E0 15 | } 16 | -------------------------------------------------------------------------------- /Arthas.Shell/Interop/WS.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | 4 | namespace Arthas.Shell.Interop; 5 | 6 | /// 7 | /// WindowStyle values, WS_* 8 | /// 9 | [Flags] 10 | [SuppressMessage("ReSharper", "InconsistentNaming")] 11 | enum WS : uint 12 | { 13 | CHILD = 0x40000000, 14 | CLIPCHILDREN = 0x02000000, 15 | BORDER = 0x00800000, 16 | DLGFRAME = 0x00400000, 17 | CAPTION = BORDER | DLGFRAME 18 | } 19 | -------------------------------------------------------------------------------- /Arthas.Shell/Interop/WVR.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | 4 | namespace Arthas.Shell.Interop; 5 | 6 | [Flags] 7 | [SuppressMessage("ReSharper", "InconsistentNaming")] 8 | enum WVR 9 | { 10 | HREDRAW = 0x0100, 11 | VREDRAW = 0x0200, 12 | VALIDRECTS = 0x0400, 13 | REDRAW = HREDRAW | VREDRAW 14 | } 15 | -------------------------------------------------------------------------------- /Arthas.Shell/Interop/Win32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace Arthas.Shell.Interop; 7 | 8 | static class Win32 9 | { 10 | [DllImport("dwmapi.dll", EntryPoint = "DwmIsCompositionEnabled", PreserveSig = false)] 11 | [return: MarshalAs(UnmanagedType.Bool)] 12 | static extern bool _DwmIsCompositionEnabled(); 13 | 14 | static readonly bool _isOsVistaOrNewer = new Version(6, 0) <= Environment.OSVersion.Version; 15 | 16 | public static bool DwmIsCompositionEnabled() 17 | { 18 | return _isOsVistaOrNewer && _DwmIsCompositionEnabled(); 19 | } 20 | 21 | public static WS GetWindowStyle(IntPtr hWnd) 22 | { 23 | return (WS)GetWindowLongPtr(hWnd, GWL.STYLE); 24 | } 25 | 26 | public static WS SetWindowStyle(IntPtr hWnd, WS dwNewLong) 27 | { 28 | return (WS)SetWindowLongPtr(hWnd, GWL.STYLE, (IntPtr)dwNewLong); 29 | } 30 | 31 | [MethodImpl(MethodImplOptions.NoInlining)] 32 | public static IntPtr GetWindowLongPtr(IntPtr hwnd, GWL nIndex) 33 | { 34 | var ret = IntPtr.Size == 8 35 | ? GetWindowLongPtr64(hwnd, nIndex) 36 | : GetWindowLongPtr32(hwnd, nIndex); 37 | 38 | if (ret == IntPtr.Zero) 39 | throw new Win32Exception(); 40 | 41 | return ret; 42 | } 43 | 44 | [DllImport("user32.dll", EntryPoint = "GetWindowLong", SetLastError = true)] 45 | static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, GWL nIndex); 46 | 47 | [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", SetLastError = true)] 48 | static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, GWL nIndex); 49 | 50 | [DllImport("user32.dll", SetLastError = true)] 51 | [return: MarshalAs(UnmanagedType.Bool)] 52 | static extern bool GetWindowPlacement(IntPtr hwnd, [In] [Out] WINDOWPLACEMENT lpwndpl); 53 | 54 | [MethodImpl(MethodImplOptions.NoInlining)] 55 | public static WINDOWPLACEMENT GetWindowPlacement(IntPtr hwnd) 56 | { 57 | WINDOWPLACEMENT wndpl = new(); 58 | 59 | if (GetWindowPlacement(hwnd, wndpl)) 60 | return wndpl; 61 | 62 | throw new Win32Exception(); 63 | } 64 | 65 | [MethodImpl(MethodImplOptions.NoInlining)] 66 | public static IntPtr SetWindowLongPtr(IntPtr hwnd, GWL nIndex, IntPtr dwNewLong) 67 | { 68 | if (IntPtr.Size == 8) 69 | return SetWindowLongPtr64(hwnd, nIndex, dwNewLong); 70 | 71 | return new(SetWindowLongPtr32(hwnd, nIndex, dwNewLong.ToInt32())); 72 | } 73 | 74 | [DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)] 75 | static extern int SetWindowLongPtr32(IntPtr hWnd, GWL nIndex, int dwNewLong); 76 | 77 | [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)] 78 | static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, GWL nIndex, IntPtr dwNewLong); 79 | 80 | [DllImport("user32.dll", EntryPoint = "SetWindowPos", SetLastError = true)] 81 | [return: MarshalAs(UnmanagedType.Bool)] 82 | static extern bool _SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP uFlags); 83 | 84 | [MethodImpl(MethodImplOptions.NoInlining)] 85 | public static void SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP uFlags) 86 | { 87 | if (!_SetWindowPos(hWnd, hWndInsertAfter, x, y, cx, cy, uFlags)) 88 | throw new Win32Exception(); 89 | } 90 | 91 | [DllImport("user32.dll", SetLastError = true)] 92 | public static extern IntPtr SendMessage(IntPtr hWnd, WM msg, IntPtr wParam, IntPtr lParam); 93 | } 94 | -------------------------------------------------------------------------------- /Arthas.Shell/MetroWindowBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | using System.Windows.Interop; 4 | using Arthas.Shell.Interop; 5 | 6 | namespace Arthas.Shell; 7 | 8 | public class MetroWindowBase : Window 9 | { 10 | readonly MetroWindowChrome _chrome; 11 | 12 | protected MetroWindowBase() 13 | { 14 | _chrome = new(this); 15 | 16 | WindowStartupLocation = WindowStartupLocation.CenterScreen; 17 | 18 | CommandBindings.Add(new(SystemCommands.MinimizeWindowCommand, delegate 19 | { 20 | SystemCommands.MinimizeWindow(this); 21 | })); 22 | 23 | CommandBindings.Add(new(SystemCommands.MaximizeWindowCommand, delegate 24 | { 25 | ChangWindowState(); 26 | })); 27 | 28 | CommandBindings.Add(new(SystemCommands.RestoreWindowCommand, delegate 29 | { 30 | ChangWindowState(); 31 | })); 32 | 33 | CommandBindings.Add(new(SystemCommands.CloseWindowCommand, delegate 34 | { 35 | SystemCommands.CloseWindow(this); 36 | })); 37 | 38 | ContentRendered += OnContentRendered; 39 | } 40 | 41 | void OnContentRendered(object? sender, EventArgs e) 42 | { 43 | ContentRendered -= OnContentRendered; 44 | Activate(); 45 | } 46 | 47 | protected void ChangWindowState() 48 | { 49 | switch (ResizeMode) 50 | { 51 | case ResizeMode.CanResize: 52 | case ResizeMode.CanResizeWithGrip: 53 | 54 | break; 55 | 56 | default: 57 | 58 | return; 59 | } 60 | 61 | switch (WindowState) 62 | { 63 | case WindowState.Normal: 64 | 65 | SystemCommands.MaximizeWindow(this); 66 | 67 | break; 68 | 69 | case WindowState.Maximized: 70 | 71 | SystemCommands.RestoreWindow(this); 72 | 73 | break; 74 | } 75 | } 76 | 77 | public IntPtr Handle { get; private set; } 78 | public IntPtr OwnerHandle { get; private set; } 79 | public HwndSource? HwndSource { get; private set; } 80 | 81 | protected override void OnSourceInitialized(EventArgs e) 82 | { 83 | var windowInteropHelper = new WindowInteropHelper(this); 84 | windowInteropHelper.EnsureHandle(); 85 | 86 | Handle = windowInteropHelper.Handle; 87 | OwnerHandle = windowInteropHelper.Owner; 88 | HwndSource = HwndSource.FromHwnd(Handle); 89 | 90 | _chrome.OnSourceInitialized(); 91 | 92 | base.OnSourceInitialized(e); 93 | } 94 | 95 | protected override void OnStateChanged(EventArgs e) 96 | { 97 | base.OnStateChanged(e); 98 | _chrome.OnStateChanged(); 99 | } 100 | 101 | public bool IsClosed { get; private set; } 102 | 103 | protected override void OnClosed(EventArgs e) 104 | { 105 | base.OnClosed(e); 106 | IsClosed = true; 107 | Owner.BringToFront(); 108 | _chrome.OnClosed(); 109 | } 110 | 111 | protected override void OnDeactivated(EventArgs e) 112 | { 113 | base.OnDeactivated(e); 114 | TopMostHack(); 115 | } 116 | 117 | protected override void OnLostFocus(RoutedEventArgs e) 118 | { 119 | base.OnLostFocus(e); 120 | TopMostHack(); 121 | } 122 | 123 | void TopMostHack() 124 | { 125 | if (!Topmost) 126 | return; 127 | 128 | SetCurrentValue(TopmostProperty, false); 129 | SetCurrentValue(TopmostProperty, true); 130 | } 131 | 132 | protected void SendCaptionMessage() 133 | { 134 | Win32.SendMessage(Handle, WM.NCLBUTTONDOWN, (IntPtr)HT.CAPTION, IntPtr.Zero); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /Arthas.Shell/MetroWindowChrome.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Runtime.InteropServices; 4 | using System.Security; 5 | using System.Windows; 6 | using System.Windows.Shell; 7 | using Arthas.Shell.Interop; 8 | 9 | namespace Arthas.Shell; 10 | 11 | [SuppressMessage("ReSharper", "InconsistentNaming")] 12 | class MetroWindowChrome 13 | { 14 | readonly MetroWindowBase window; 15 | 16 | [SecuritySafeCritical] 17 | public MetroWindowChrome(MetroWindowBase window) 18 | { 19 | this.window = window; 20 | 21 | window.SetCurrentValue(Window.AllowsTransparencyProperty, false); 22 | window.SetCurrentValue(Window.WindowStyleProperty, WindowStyle.None); 23 | } 24 | 25 | public void OnSourceInitialized() 26 | { 27 | WindowChrome.SetWindowChrome(window, new() 28 | { 29 | CaptionHeight = 0, 30 | CornerRadius = new(0), 31 | GlassFrameThickness = new(1), 32 | NonClientFrameEdges = NonClientFrameEdges.None, 33 | ResizeBorderThickness = new(6), 34 | UseAeroCaptionButtons = false 35 | }); 36 | 37 | if (window.SizeToContent != SizeToContent.Manual && window.WindowState == WindowState.Normal) 38 | window.InvalidateMeasure(); 39 | 40 | window.HwndSource?.AddHook(WindowProc); 41 | 42 | UpdateFrameState(true); 43 | HandleMaximize(); 44 | } 45 | 46 | bool isCleanedUp; 47 | 48 | public void OnClosed() 49 | { 50 | if (isCleanedUp) 51 | return; 52 | 53 | isCleanedUp = true; 54 | 55 | window.HwndSource?.RemoveHook(WindowProc); 56 | } 57 | 58 | public void OnStateChanged() 59 | { 60 | HandleMaximize(); 61 | } 62 | 63 | static IntPtr HWND_NOTOPMOST { get; } = new(-2); 64 | 65 | void HandleMaximize() 66 | { 67 | if (window.WindowState != WindowState.Maximized) 68 | return; 69 | 70 | if (window.SizeToContent != SizeToContent.Manual) 71 | window.SetCurrentValue(Window.SizeToContentProperty, SizeToContent.Manual); 72 | 73 | if (window.Handle == IntPtr.Zero) 74 | return; 75 | 76 | var workingArea = ScreenHelper.FormWindow(window).WorkingArea; 77 | Win32.SetWindowPos(window.Handle, HWND_NOTOPMOST, workingArea.Left, workingArea.Top, workingArea.Width, 78 | workingArea.Height, SWP.SHOWWINDOW); 79 | } 80 | 81 | [SecurityCritical] 82 | IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) 83 | { 84 | return (WM)msg switch 85 | { 86 | WM.NCPAINT => HandleNCPAINT(out handled), 87 | WM.DPICHANGED => HandleDPICHANGED(lParam, out handled), 88 | WM.NCCALCSIZE => HandleNCCALCSIZE(wParam, lParam, out handled), 89 | _ => IntPtr.Zero 90 | }; 91 | } 92 | 93 | [SecurityCritical] 94 | static IntPtr HandleNCPAINT(out bool handled) 95 | { 96 | handled = false; 97 | 98 | return IntPtr.Zero; 99 | } 100 | 101 | static bool MinimizeAnimation => SystemParameters.MinimizeAnimation && Win32.DwmIsCompositionEnabled(); 102 | 103 | bool dpiChanged; 104 | 105 | [SecurityCritical] 106 | IntPtr HandleDPICHANGED(IntPtr lParam, out bool handled) 107 | { 108 | dpiChanged = true; 109 | 110 | if (_GetHwndState() == WindowState.Normal) 111 | { 112 | var rect = (RECT)Marshal.PtrToStructure(lParam, typeof(RECT))!; 113 | rect.Bottom += 1; 114 | Marshal.StructureToPtr(rect, lParam, true); 115 | } 116 | 117 | handled = false; 118 | 119 | return IntPtr.Zero; 120 | } 121 | 122 | [SecurityCritical] 123 | IntPtr HandleNCCALCSIZE(IntPtr wParam, IntPtr lParam, out bool handled) 124 | { 125 | // lParam is an [in, out] that can be either a RECT* (wParam == FALSE) or an NCCALCSIZE_PARAMS*. 126 | // Since the first field of NCCALCSIZE_PARAMS is a RECT and is the only field we care about 127 | // we can unconditionally treat it as a RECT. 128 | 129 | if (dpiChanged) 130 | { 131 | dpiChanged = false; 132 | handled = true; 133 | 134 | return IntPtr.Zero; 135 | } 136 | 137 | if (MinimizeAnimation 138 | && _GetHwndState() == WindowState.Maximized) 139 | { 140 | var workingArea = ScreenHelper.FormWindow(window).WorkingArea; 141 | 142 | var rc = (RECT)Marshal.PtrToStructure(lParam, typeof(RECT))!; 143 | rc.Left = workingArea.Left; 144 | rc.Top = workingArea.Top; 145 | rc.Right = workingArea.Right; 146 | rc.Bottom = workingArea.Bottom; 147 | 148 | Marshal.StructureToPtr(rc, lParam, true); 149 | } 150 | 151 | handled = true; 152 | 153 | // Per MSDN for NCCALCSIZE, always return 0 when wParam == FALSE 154 | // 155 | // Returning 0 when wParam == TRUE is not appropriate - it will preserve 156 | // the old client area and align it with the upper-left corner of the new 157 | // client area. So we simply ask for a redraw (WVR_REDRAW) 158 | 159 | var retVal = IntPtr.Zero; 160 | 161 | if (wParam.ToInt32() != 0) // wParam == TRUE 162 | // Using the combination of WVR.VALIDRECTS and WVR.REDRAW gives the smoothest 163 | // resize behavior we can achieve here. 164 | retVal = new((int)(WVR.VALIDRECTS | WVR.REDRAW)); 165 | 166 | return retVal; 167 | } 168 | 169 | [SecurityCritical] 170 | void UpdateFrameState(bool force) 171 | { 172 | if (window.Handle == IntPtr.Zero || window.HwndSource?.IsDisposed != false) 173 | return; 174 | 175 | if (!force) 176 | return; 177 | 178 | if (window.HwndSource.IsDisposed) // If the window got closed very early 179 | return; 180 | 181 | if (MinimizeAnimation) 182 | ModifyStyle(0, WS.CAPTION); 183 | else 184 | ModifyStyle(WS.CAPTION, 0); 185 | 186 | Win32.SetWindowPos(window.Handle, IntPtr.Zero, 0, 0, 0, 0, 187 | SWP.FRAMECHANGED | SWP.NOSIZE | SWP.NOMOVE | SWP.NOZORDER | SWP.NOOWNERZORDER | SWP.NOACTIVATE); 188 | } 189 | 190 | /// 191 | /// Get the WindowState as the native HWND knows it to be. This isn't necessarily the same as what Window thinks. 192 | /// 193 | [SecurityCritical] 194 | WindowState _GetHwndState() 195 | { 196 | var wpl = Win32.GetWindowPlacement(window.Handle); 197 | 198 | return wpl.showCmd switch 199 | { 200 | SW.SHOWMINIMIZED => WindowState.Minimized, 201 | SW.SHOWMAXIMIZED => WindowState.Maximized, 202 | _ => WindowState.Normal 203 | }; 204 | } 205 | 206 | /// Add and remove a native WindowStyle from the HWND. 207 | /// The styles to be removed. These can be bitwise combined. 208 | /// The styles to be added. These can be bitwise combined. 209 | /// Whether the styles of the HWND were modified as a result of this call. 210 | /// 211 | /// Critical : Calls critical methods 212 | /// 213 | [SecurityCritical] 214 | void ModifyStyle(WS removeStyle, WS addStyle) 215 | { 216 | var dwStyle = Win32.GetWindowStyle(window.Handle); 217 | var dwNewStyle = (dwStyle & ~removeStyle) | addStyle; 218 | 219 | if (dwStyle == dwNewStyle) 220 | return; 221 | 222 | Win32.SetWindowStyle(window.Handle, dwNewStyle); 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /Arthas.Shell/ScreenHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Forms; 2 | 3 | namespace Arthas.Shell; 4 | 5 | static class ScreenHelper 6 | { 7 | public static Screen FormWindow(MetroWindowBase window) 8 | { 9 | return Screen.FromHandle(window.Handle); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Arthas.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.28516.95 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arthas.Demo", "Arthas.Demo\Arthas.Demo.csproj", "{20827429-E998-4EA3-BB34-DB49CBD0FCC0}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arthas", "Arthas\Arthas.csproj", "{F5DBBC65-F7D3-4A0D-8A9F-3DAFD3DEB7ED}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_", "_", "{FE8A96FA-DB1E-45FA-A623-0C222B8B6ACC}" 11 | ProjectSection(SolutionItems) = preProject 12 | Build.bat = Build.bat 13 | Directory.Build.props = Directory.Build.props 14 | README.md = README.md 15 | .gitignore = .gitignore 16 | EndProjectSection 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arthas.Shell", "Arthas.Shell\Arthas.Shell.csproj", "{CDE22618-45CA-45DE-ABDD-2FE46F3EAE6B}" 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Any CPU = Debug|Any CPU 23 | Debug|x86 = Debug|x86 24 | Release|Any CPU = Release|Any CPU 25 | Release|x86 = Release|x86 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {20827429-E998-4EA3-BB34-DB49CBD0FCC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {20827429-E998-4EA3-BB34-DB49CBD0FCC0}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {20827429-E998-4EA3-BB34-DB49CBD0FCC0}.Debug|x86.ActiveCfg = Debug|Any CPU 31 | {20827429-E998-4EA3-BB34-DB49CBD0FCC0}.Debug|x86.Build.0 = Debug|Any CPU 32 | {20827429-E998-4EA3-BB34-DB49CBD0FCC0}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {20827429-E998-4EA3-BB34-DB49CBD0FCC0}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {20827429-E998-4EA3-BB34-DB49CBD0FCC0}.Release|x86.ActiveCfg = Release|Any CPU 35 | {20827429-E998-4EA3-BB34-DB49CBD0FCC0}.Release|x86.Build.0 = Release|Any CPU 36 | {F5DBBC65-F7D3-4A0D-8A9F-3DAFD3DEB7ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {F5DBBC65-F7D3-4A0D-8A9F-3DAFD3DEB7ED}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {F5DBBC65-F7D3-4A0D-8A9F-3DAFD3DEB7ED}.Debug|x86.ActiveCfg = Debug|Any CPU 39 | {F5DBBC65-F7D3-4A0D-8A9F-3DAFD3DEB7ED}.Debug|x86.Build.0 = Debug|Any CPU 40 | {F5DBBC65-F7D3-4A0D-8A9F-3DAFD3DEB7ED}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {F5DBBC65-F7D3-4A0D-8A9F-3DAFD3DEB7ED}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {F5DBBC65-F7D3-4A0D-8A9F-3DAFD3DEB7ED}.Release|x86.ActiveCfg = Release|Any CPU 43 | {F5DBBC65-F7D3-4A0D-8A9F-3DAFD3DEB7ED}.Release|x86.Build.0 = Release|Any CPU 44 | {CDE22618-45CA-45DE-ABDD-2FE46F3EAE6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {CDE22618-45CA-45DE-ABDD-2FE46F3EAE6B}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {CDE22618-45CA-45DE-ABDD-2FE46F3EAE6B}.Debug|x86.ActiveCfg = Debug|Any CPU 47 | {CDE22618-45CA-45DE-ABDD-2FE46F3EAE6B}.Debug|x86.Build.0 = Debug|Any CPU 48 | {CDE22618-45CA-45DE-ABDD-2FE46F3EAE6B}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {CDE22618-45CA-45DE-ABDD-2FE46F3EAE6B}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {CDE22618-45CA-45DE-ABDD-2FE46F3EAE6B}.Release|x86.ActiveCfg = Release|Any CPU 51 | {CDE22618-45CA-45DE-ABDD-2FE46F3EAE6B}.Release|x86.Build.0 = Release|Any CPU 52 | EndGlobalSection 53 | GlobalSection(SolutionProperties) = preSolution 54 | HideSolutionNode = FALSE 55 | EndGlobalSection 56 | GlobalSection(ExtensibilityGlobals) = postSolution 57 | SolutionGuid = {7C504695-968E-4B6B-9812-AD4D7B1EB6EC} 58 | EndGlobalSection 59 | EndGlobal 60 | -------------------------------------------------------------------------------- /Arthas/Arthas.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Arthas/Binder/MetroDialogModel.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using Arthas.Controls; 3 | using OpenView; 4 | 5 | namespace Arthas.Binder; 6 | 7 | public abstract class MetroDialogModel : DialogModel where TUserControl : View, new() 8 | { 9 | protected override Window CreateWindowOverride() 10 | { 11 | return new MetroWindow(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Arthas/Binder/MetroWindowModel.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using Arthas.Controls; 3 | using OpenView; 4 | 5 | namespace Arthas.Binder; 6 | 7 | public abstract class MetroWindowModel : WindowModel where TUserControl : View, new() 8 | { 9 | protected override Window CreateWindowOverride() 10 | { 11 | return new MetroWindow(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroBorder.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Arthas.Controls; 5 | 6 | public class MetroBorder : Border 7 | { 8 | static MetroBorder() 9 | { 10 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroBorder), new FrameworkPropertyMetadata(typeof(MetroBorder))); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroBorder.xaml: -------------------------------------------------------------------------------- 1 |  6 | 9 | 10 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroButton.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Arthas.Controls; 5 | 6 | public class MetroButton : Button 7 | { 8 | static MetroButton() 9 | { 10 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroButton), new FrameworkPropertyMetadata(typeof(MetroButton))); 11 | } 12 | 13 | public static readonly DependencyProperty ButtonStateProperty = DependencyProperty.Register(nameof(ButtonState), typeof(MetroButtonState), typeof(MetroButton), new(MetroButtonState.None)); 14 | 15 | public MetroButtonState ButtonState 16 | { 17 | get => (MetroButtonState)GetValue(ButtonStateProperty); 18 | set => SetValue(ButtonStateProperty, value); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroButton.xaml: -------------------------------------------------------------------------------- 1 |  6 | 70 | 71 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroButtonState.cs: -------------------------------------------------------------------------------- 1 | namespace Arthas.Controls; 2 | 3 | public enum MetroButtonState 4 | { 5 | None, 6 | Red, 7 | Green 8 | } 9 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroCaptionMenu.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Arthas.Controls; 5 | 6 | public class MetroCaptionMenu : Menu 7 | { 8 | static MetroCaptionMenu() 9 | { 10 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroCaptionMenu), new FrameworkPropertyMetadata(typeof(MetroCaptionMenu))); 11 | } 12 | 13 | protected override DependencyObject GetContainerForItemOverride() 14 | { 15 | return new MetroCaptionMenuItem(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroCaptionMenu.xaml: -------------------------------------------------------------------------------- 1 |  5 | 14 | 15 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroCaptionMenuItem.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Arthas.Controls; 5 | 6 | public class MetroCaptionMenuItem : MenuItem 7 | { 8 | static MetroCaptionMenuItem() 9 | { 10 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroCaptionMenuItem), new FrameworkPropertyMetadata(typeof(MetroCaptionMenuItem))); 11 | } 12 | 13 | protected override DependencyObject GetContainerForItemOverride() 14 | { 15 | return new MetroMenuItem(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroCaptionMenuItem.xaml: -------------------------------------------------------------------------------- 1 |  5 | 68 | 69 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroContextMenu.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Arthas.Controls; 5 | 6 | public class MetroContextMenu : ContextMenu 7 | { 8 | static MetroContextMenu() 9 | { 10 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroContextMenu), new FrameworkPropertyMetadata(typeof(MetroContextMenu))); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroContextMenu.xaml: -------------------------------------------------------------------------------- 1 |  6 | 25 | 26 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroExpander.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | using System.Windows.Media; 4 | 5 | namespace Arthas.Controls; 6 | 7 | public class MetroExpander : ContentControl 8 | { 9 | public static readonly DependencyProperty IsExpandedProperty = ElementBase.Property(nameof(IsExpandedProperty)); 10 | public static readonly DependencyProperty CanHideProperty = ElementBase.Property(nameof(CanHideProperty)); 11 | public static readonly DependencyProperty HeaderProperty = ElementBase.Property(nameof(HeaderProperty)); 12 | public static readonly DependencyProperty HintProperty = ElementBase.Property(nameof(HintProperty)); 13 | public static readonly DependencyProperty HintBackgroundProperty = ElementBase.Property(nameof(HintBackgroundProperty)); 14 | public static readonly DependencyProperty HintForegroundProperty = ElementBase.Property(nameof(HintForegroundProperty)); 15 | public static readonly DependencyProperty IconProperty = ElementBase.Property(nameof(IconProperty), null); 16 | 17 | public bool IsExpanded 18 | { 19 | get => (bool)GetValue(IsExpandedProperty); 20 | set 21 | { 22 | SetValue(IsExpandedProperty, value); 23 | VisualStateManager.GoToState(this, IsExpanded ? "Expand" : "Normal", false); 24 | } 25 | } 26 | 27 | public bool CanHide 28 | { 29 | get => (bool)GetValue(CanHideProperty); 30 | set => SetValue(CanHideProperty, value); 31 | } 32 | 33 | public string Header 34 | { 35 | get => (string)GetValue(HeaderProperty); 36 | set => SetValue(HeaderProperty, value); 37 | } 38 | 39 | public string Hint 40 | { 41 | get => (string)GetValue(HintProperty); 42 | set => SetValue(HintProperty, value); 43 | } 44 | 45 | public Brush HintBackground 46 | { 47 | get => (Brush)GetValue(HintBackgroundProperty); 48 | set => SetValue(HintBackgroundProperty, value); 49 | } 50 | 51 | public Brush HintForeground 52 | { 53 | get => (Brush)GetValue(HintForegroundProperty); 54 | set => SetValue(HintForegroundProperty, value); 55 | } 56 | 57 | public ImageSource Icon 58 | { 59 | get => (ImageSource)GetValue(IconProperty); 60 | set => SetValue(IconProperty, value); 61 | } 62 | 63 | public MetroExpander() 64 | { 65 | Loaded += delegate 66 | { 67 | if (Content == null) 68 | IsExpanded = false; 69 | else if (!CanHide) 70 | IsExpanded = true; 71 | 72 | VisualStateManager.GoToState(this, IsExpanded ? "StartExpand" : "StartNormal", false); 73 | }; 74 | } 75 | 76 | static MetroExpander() 77 | { 78 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroExpander), new FrameworkPropertyMetadata(typeof(MetroExpander))); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroExpander.xaml: -------------------------------------------------------------------------------- 1 |  5 | 139 | 140 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroFocusButton.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | using System.Windows.Media; 4 | 5 | namespace Arthas.Controls; 6 | 7 | public class MetroFocusButton : Button 8 | { 9 | public static readonly DependencyProperty MouseMoveForegroundProperty = ElementBase.Property(nameof(MouseMoveForegroundProperty)); 10 | public static readonly DependencyProperty MouseMoveBorderBrushProperty = ElementBase.Property(nameof(MouseMoveBorderBrushProperty)); 11 | public new static readonly DependencyProperty BorderThicknessProperty = ElementBase.Property(nameof(BorderThicknessProperty)); 12 | public static readonly DependencyProperty MouseMoveBorderThicknessProperty = ElementBase.Property(nameof(MouseMoveBorderThicknessProperty)); 13 | public static readonly DependencyProperty StrokeDashArrayProperty = ElementBase.Property(nameof(StrokeDashArrayProperty)); 14 | public static readonly DependencyProperty MouseMoveStrokeDashArrayProperty = ElementBase.Property(nameof(MouseMoveStrokeDashArrayProperty)); 15 | public static readonly DependencyProperty CornerRadiusProperty = ElementBase.Property(nameof(CornerRadiusProperty)); 16 | 17 | public Brush MouseMoveForeground 18 | { 19 | get => (Brush)GetValue(MouseMoveForegroundProperty); 20 | set => SetValue(MouseMoveForegroundProperty, value); 21 | } 22 | 23 | public Brush MouseMoveBorderBrush 24 | { 25 | get => (Brush)GetValue(MouseMoveBorderBrushProperty); 26 | set => SetValue(MouseMoveBorderBrushProperty, value); 27 | } 28 | 29 | public new double BorderThickness 30 | { 31 | get => (double)GetValue(BorderThicknessProperty); 32 | set => SetValue(BorderThicknessProperty, value); 33 | } 34 | 35 | public double MouseMoveBorderThickness 36 | { 37 | get => (double)GetValue(MouseMoveBorderThicknessProperty); 38 | set => SetValue(MouseMoveBorderThicknessProperty, value); 39 | } 40 | 41 | public DoubleCollection StrokeDashArray 42 | { 43 | get => (DoubleCollection)GetValue(StrokeDashArrayProperty); 44 | set => SetValue(StrokeDashArrayProperty, value); 45 | } 46 | 47 | public DoubleCollection MouseMoveStrokeDashArray 48 | { 49 | get => (DoubleCollection)GetValue(MouseMoveStrokeDashArrayProperty); 50 | set => SetValue(MouseMoveStrokeDashArrayProperty, value); 51 | } 52 | 53 | public double CornerRadius 54 | { 55 | get => (double)GetValue(CornerRadiusProperty); 56 | set => SetValue(CornerRadiusProperty, value); 57 | } 58 | 59 | static MetroFocusButton() 60 | { 61 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroFocusButton), new FrameworkPropertyMetadata(typeof(MetroFocusButton))); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroFocusButton.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 63 | 64 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroGridTile.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Arthas.Controls; 5 | 6 | public class MetroGridTile : ContentControl 7 | { 8 | static MetroGridTile() 9 | { 10 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroGridTile), 11 | new FrameworkPropertyMetadata(typeof(MetroGridTile))); 12 | } 13 | 14 | public static readonly DependencyProperty TileSizeProperty = 15 | DependencyProperty.Register(nameof(TileSize), typeof(Size), typeof(MetroGridTile)); 16 | 17 | public Size TileSize 18 | { 19 | get => (Size)GetValue(TileSizeProperty); 20 | set => SetValue(TileSizeProperty, value); 21 | } 22 | 23 | public static readonly DependencyProperty TileOpacityProperty = 24 | DependencyProperty.Register(nameof(TileOpacity), typeof(double), typeof(MetroGridTile)); 25 | 26 | public double TileOpacity 27 | { 28 | get => (double)GetValue(TileOpacityProperty); 29 | set => SetValue(TileOpacityProperty, value); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroGridTile.xaml: -------------------------------------------------------------------------------- 1 |  5 | 36 | 37 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroGroup.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Arthas.Controls; 5 | 6 | public class MetroGroup : GroupBox 7 | { 8 | static MetroGroup() 9 | { 10 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroGroup), new FrameworkPropertyMetadata(typeof(MetroGroup))); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroGroup.xaml: -------------------------------------------------------------------------------- 1 |  6 | 29 | 30 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroMenuItem.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Arthas.Controls; 5 | 6 | public class MetroMenuItem : MenuItem 7 | { 8 | static MetroMenuItem() 9 | { 10 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroMenuItem), new FrameworkPropertyMetadata(typeof(MetroMenuItem))); 11 | } 12 | 13 | protected override DependencyObject GetContainerForItemOverride() 14 | { 15 | return new MetroMenuItem(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroMenuItem.xaml: -------------------------------------------------------------------------------- 1 |  6 | 78 | 79 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroMenuSeparator.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Arthas.Controls; 5 | 6 | public class MetroMenuSeparator : Separator 7 | { 8 | static MetroMenuSeparator() 9 | { 10 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroMenuSeparator), new FrameworkPropertyMetadata(typeof(MetroMenuSeparator))); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroMenuSeparator.xaml: -------------------------------------------------------------------------------- 1 |  5 | 11 | 12 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroProgressBar.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Arthas.Controls; 5 | 6 | public class MetroProgressBar : ProgressBar 7 | { 8 | static MetroProgressBar() 9 | { 10 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroProgressBar), new FrameworkPropertyMetadata(typeof(MetroProgressBar))); 11 | } 12 | 13 | public static readonly DependencyProperty ProgressBarStateProperty = ElementBase.Property(nameof(ProgressBarStateProperty)); 14 | public static readonly DependencyProperty CornerRadiusProperty = ElementBase.Property(nameof(CornerRadiusProperty)); 15 | public static readonly DependencyProperty TitleProperty = ElementBase.Property(nameof(TitleProperty)); 16 | public static readonly DependencyProperty TextHorizontalAlignmentProperty = ElementBase.Property(nameof(TextHorizontalAlignmentProperty)); 17 | 18 | public ProgressBarState ProgressBarState 19 | { 20 | get => (ProgressBarState)GetValue(ProgressBarStateProperty); 21 | set => SetValue(ProgressBarStateProperty, value); 22 | } 23 | 24 | public CornerRadius CornerRadius 25 | { 26 | get => (CornerRadius)GetValue(CornerRadiusProperty); 27 | set => SetValue(CornerRadiusProperty, value); 28 | } 29 | 30 | public string Title 31 | { 32 | get => (string)GetValue(TitleProperty); 33 | set => SetValue(TitleProperty, value); 34 | } 35 | 36 | public HorizontalAlignment TextHorizontalAlignment 37 | { 38 | get => (HorizontalAlignment)GetValue(TextHorizontalAlignmentProperty); 39 | set => SetValue(TextHorizontalAlignmentProperty, value); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroProgressBar.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 103 | 104 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroScrollViewer.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Arthas.Controls; 5 | 6 | public class MetroScrollViewer : ScrollViewer 7 | { 8 | static MetroScrollViewer() 9 | { 10 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroScrollViewer), new FrameworkPropertyMetadata(typeof(MetroScrollViewer))); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroScrollViewer.xaml: -------------------------------------------------------------------------------- 1 |  6 | 15 | 54 | 93 | 115 | 137 | 169 | 170 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroSwitch.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls.Primitives; 3 | 4 | namespace Arthas.Controls; 5 | 6 | public class MetroSwitch : ToggleButton 7 | { 8 | public static readonly DependencyProperty TextHorizontalAlignmentProperty = DependencyProperty.Register(nameof(TextHorizontalAlignment), typeof(HorizontalAlignment), typeof(MetroSwitch), new(HorizontalAlignment.Left)); 9 | 10 | public HorizontalAlignment TextHorizontalAlignment 11 | { 12 | get => (HorizontalAlignment)GetValue(TextHorizontalAlignmentProperty); 13 | set => SetValue(TextHorizontalAlignmentProperty, value); 14 | } 15 | 16 | public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(nameof(CornerRadius), typeof(CornerRadius), typeof(MetroSwitch), new(new CornerRadius(10))); 17 | 18 | public CornerRadius CornerRadius 19 | { 20 | get => (CornerRadius)GetValue(CornerRadiusProperty); 21 | set => SetValue(CornerRadiusProperty, value); 22 | } 23 | 24 | public static readonly DependencyProperty BorderCornerRadiusProperty = DependencyProperty.Register(nameof(BorderCornerRadius), typeof(CornerRadius), typeof(MetroSwitch), new(new CornerRadius(12))); 25 | 26 | public CornerRadius BorderCornerRadius 27 | { 28 | get => (CornerRadius)GetValue(BorderCornerRadiusProperty); 29 | set => SetValue(BorderCornerRadiusProperty, value); 30 | } 31 | 32 | public MetroSwitch() 33 | { 34 | Loaded += delegate 35 | { 36 | VisualStateManager.GoToState(this, IsChecked is true ? "OpenLoaded" : "CloseLoaded", false); 37 | }; 38 | } 39 | 40 | protected override void OnChecked(RoutedEventArgs e) 41 | { 42 | base.OnChecked(e); 43 | VisualStateManager.GoToState(this, "Open", false); 44 | } 45 | 46 | protected override void OnUnchecked(RoutedEventArgs e) 47 | { 48 | base.OnChecked(e); 49 | VisualStateManager.GoToState(this, "Close", false); 50 | } 51 | 52 | static MetroSwitch() 53 | { 54 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroSwitch), new FrameworkPropertyMetadata(typeof(MetroSwitch))); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroSwitch.xaml: -------------------------------------------------------------------------------- 1 |  5 | 68 | 69 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroTabControl.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Arthas.Controls; 5 | 6 | public class MetroTabControl : TabControl 7 | { 8 | void SelectionState() 9 | { 10 | VisualStateManager.GoToState(this, "SelectionStart", false); 11 | VisualStateManager.GoToState(this, "SelectionEnd", false); 12 | } 13 | 14 | protected override DependencyObject GetContainerForItemOverride() 15 | { 16 | return new MetroTabItem(); 17 | } 18 | 19 | public MetroTabControl() 20 | { 21 | Loaded += delegate 22 | { 23 | VisualStateManager.GoToState(this, "SelectionLoaded", false); 24 | }; 25 | SelectionChanged += delegate(object _, SelectionChangedEventArgs e) 26 | { 27 | if (e.Source is MetroTabControl) 28 | SelectionState(); 29 | }; 30 | } 31 | 32 | static MetroTabControl() 33 | { 34 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroTabControl), new FrameworkPropertyMetadata(typeof(MetroTabControl))); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroTabControl.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 62 | 63 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroTabItem.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | using System.Windows.Media; 4 | 5 | namespace Arthas.Controls; 6 | 7 | public class MetroTabItem : TabItem 8 | { 9 | public static readonly DependencyProperty IconProperty = DependencyProperty.Register(nameof(Icon), typeof(ImageSource), typeof(MetroTabItem), new(null)); 10 | 11 | public ImageSource? Icon 12 | { 13 | get => (ImageSource?)GetValue(IconProperty); 14 | set => SetValue(IconProperty, value); 15 | } 16 | 17 | static MetroTabItem() 18 | { 19 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroTabItem), new FrameworkPropertyMetadata(typeof(MetroTabItem))); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroTabItem.xaml: -------------------------------------------------------------------------------- 1 |  5 | 54 | 55 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroTextBlock.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace Arthas.Controls; 4 | 5 | public class MetroTextBlock : TextBlock 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroTextBlock.xaml: -------------------------------------------------------------------------------- 1 |  5 | 32 | 35 | 36 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroTextBox.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | using System.Windows.Input; 4 | using System.Windows.Media; 5 | 6 | namespace Arthas.Controls; 7 | 8 | public class MetroTextBox : TextBox 9 | { 10 | public static readonly DependencyProperty TitleProperty = ElementBase.Property(nameof(TitleProperty), ""); 11 | public static readonly DependencyProperty TitleMinWidthProperty = ElementBase.Property(nameof(TitleMinWidthProperty)); 12 | public static readonly DependencyProperty TitleForegroundProperty = ElementBase.Property(nameof(TitleForegroundProperty)); 13 | public static readonly DependencyProperty MouseMoveBackgroundProperty = ElementBase.Property(nameof(MouseMoveBackgroundProperty)); 14 | public static readonly DependencyProperty InputHintProperty = ElementBase.Property(nameof(InputHintProperty), ""); 15 | public static readonly DependencyProperty ButtonTitleProperty = ElementBase.Property(nameof(ButtonTitleProperty), ""); 16 | public static readonly DependencyProperty IconProperty = ElementBase.Property(nameof(IconProperty), null); 17 | public static readonly DependencyProperty StateProperty = ElementBase.Property(nameof(StateProperty), ""); 18 | public static readonly DependencyProperty MultipleLineProperty = ElementBase.Property(nameof(MultipleLineProperty), false); 19 | public static readonly DependencyProperty CornerRadiusProperty = ElementBase.Property(nameof(CornerRadiusProperty)); 20 | 21 | public static RoutedUICommand ButtonClickCommand = ElementBase.Command(nameof(ButtonClickCommand)); 22 | 23 | public string Title 24 | { 25 | get => (string)GetValue(TitleProperty); 26 | set => SetValue(TitleProperty, value); 27 | } 28 | 29 | public double TitleMinWidth 30 | { 31 | get => (double)GetValue(TitleMinWidthProperty); 32 | set => SetValue(TitleMinWidthProperty, value); 33 | } 34 | 35 | public Brush TitleForeground 36 | { 37 | get => (Brush)GetValue(TitleForegroundProperty); 38 | set => SetValue(TitleForegroundProperty, value); 39 | } 40 | 41 | public Brush MouseMoveBackground 42 | { 43 | get => (Brush)GetValue(MouseMoveBackgroundProperty); 44 | set => SetValue(MouseMoveBackgroundProperty, value); 45 | } 46 | 47 | public string InputHint 48 | { 49 | get => (string)GetValue(InputHintProperty); 50 | set => SetValue(InputHintProperty, value); 51 | } 52 | 53 | public string ButtonTitle 54 | { 55 | get => (string)GetValue(ButtonTitleProperty); 56 | set => SetValue(ButtonTitleProperty, value); 57 | } 58 | 59 | public ImageSource Icon 60 | { 61 | get => (ImageSource)GetValue(IconProperty); 62 | set => SetValue(IconProperty, value); 63 | } 64 | 65 | public string State 66 | { 67 | get => (string)GetValue(StateProperty); 68 | set => SetValue(StateProperty, value); 69 | } 70 | 71 | public bool MultipleLine 72 | { 73 | get => (bool)GetValue(MultipleLineProperty); 74 | set => SetValue(MultipleLineProperty, value); 75 | } 76 | 77 | public CornerRadius CornerRadius 78 | { 79 | get => (CornerRadius)GetValue(CornerRadiusProperty); 80 | set => SetValue(CornerRadiusProperty, value); 81 | } 82 | 83 | public Func? ErrorCheckAction { get; set; } 84 | 85 | public event EventHandler? ButtonClick; 86 | 87 | public MetroTextBox() 88 | { 89 | ContextMenu = null; 90 | Loaded += delegate 91 | { 92 | ErrorCheck(); 93 | }; 94 | TextChanged += delegate 95 | { 96 | ErrorCheck(); 97 | }; 98 | CommandBindings.Add(new(ButtonClickCommand, delegate 99 | { 100 | ButtonClick?.Invoke(this, EventArgs.Empty); 101 | })); 102 | } 103 | 104 | void ErrorCheck() 105 | { 106 | // if (PopupHint == null || PopupHint == "") { PopupHint = InputHint; } 107 | if (ErrorCheckAction != null) 108 | State = ErrorCheckAction(Text) ? "true" : "false"; 109 | } 110 | 111 | static MetroTextBox() 112 | { 113 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroTextBox), new FrameworkPropertyMetadata(typeof(MetroTextBox))); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroTextBox.xaml: -------------------------------------------------------------------------------- 1 |  6 | 33 | 139 | 140 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroTextButton.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace Arthas.Controls; 5 | 6 | public class MetroTextButton : Button 7 | { 8 | static MetroTextButton() 9 | { 10 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroTextButton), new FrameworkPropertyMetadata(typeof(MetroTextButton))); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroTextButton.xaml: -------------------------------------------------------------------------------- 1 |  5 | 42 | 43 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroTile.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | using System.Windows.Media; 4 | 5 | #pragma warning disable 1591 6 | 7 | namespace Arthas.Controls; 8 | 9 | public class MetroTile : ContentControl 10 | { 11 | static MetroTile() 12 | { 13 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroTile), new FrameworkPropertyMetadata(typeof(MetroTile))); 14 | } 15 | 16 | public static readonly DependencyProperty TileBackgroundProperty = 17 | DependencyProperty.Register(nameof(TileBackground), typeof(VisualBrush), typeof(MetroTile)); 18 | 19 | public VisualBrush TileBackground 20 | { 21 | get => (VisualBrush)GetValue(TileBackgroundProperty); 22 | private set => SetValue(TileBackgroundProperty, value); 23 | } 24 | 25 | public static readonly DependencyProperty TileProperty = 26 | DependencyProperty.Register(nameof(Tile), typeof(FrameworkElement), typeof(MetroTile), 27 | new FrameworkPropertyMetadata(null, OnTileChanged)); 28 | 29 | public FrameworkElement? Tile 30 | { 31 | get => (FrameworkElement)GetValue(TileProperty); 32 | set => SetValue(TileProperty, value); 33 | } 34 | 35 | public static readonly DependencyProperty TileSizeProperty = 36 | DependencyProperty.Register(nameof(TileSize), typeof(Size), typeof(MetroTile), 37 | new FrameworkPropertyMetadata(new Size(100, 100), OnTileChanged)); 38 | 39 | public Size TileSize 40 | { 41 | get => (Size)GetValue(TileSizeProperty); 42 | set => SetValue(TileSizeProperty, value); 43 | } 44 | 45 | static void OnTileChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 46 | { 47 | ((MetroTile)d).OnTileChanged(); 48 | } 49 | 50 | void OnTileChanged() 51 | { 52 | if (Tile is null) 53 | return; 54 | 55 | Tile.Width = TileSize.Width; 56 | Tile.Height = TileSize.Height; 57 | 58 | TileBackground = new() 59 | { 60 | TileMode = TileMode.Tile, 61 | ViewportUnits = BrushMappingMode.Absolute, 62 | Visual = Tile, 63 | Viewport = new(TileSize) 64 | }; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroTile.xaml: -------------------------------------------------------------------------------- 1 | 5 | 16 | 17 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroWaterfallFlow.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | using System.Windows.Controls.Primitives; 4 | 5 | namespace Arthas.Controls; 6 | 7 | public class MetroWaterfallFlow : Panel 8 | { 9 | public static readonly DependencyProperty SizeProperty = 10 | DependencyProperty.Register(nameof(Size), typeof(double), typeof(MetroWaterfallFlow), 11 | new FrameworkPropertyMetadata(double.NaN, 12 | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | 13 | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange)); 14 | 15 | public double Size 16 | { 17 | get => (double)GetValue(SizeProperty); 18 | set => SetValue(SizeProperty, value); 19 | } 20 | 21 | protected override Size MeasureOverride(Size availableSize) 22 | { 23 | return Layout(this, availableSize, true); 24 | } 25 | 26 | protected override Size ArrangeOverride(Size finalSize) 27 | { 28 | return Layout(this, finalSize, false); 29 | } 30 | 31 | IEnumerable GetChildren() 32 | { 33 | foreach (UIElement child in InternalChildren) 34 | { 35 | if (child is Popup) 36 | continue; 37 | 38 | if (child.Visibility == Visibility.Collapsed) 39 | continue; 40 | 41 | yield return child; 42 | } 43 | } 44 | 45 | double GetValue(double num, double defVal = 0.0) 46 | { 47 | return double.IsNaN(num) || double.IsNegativeInfinity(num) || double.IsPositiveInfinity(num) ? defVal : num; 48 | } 49 | 50 | void ForEach(int column, Action action) 51 | { 52 | var elements = GetChildren().ToList(); 53 | var count = elements.Count; 54 | 55 | var items = new List(); 56 | var row = 0; 57 | 58 | for (var i = 0; i < count; i++) 59 | { 60 | var child = elements[i]; 61 | 62 | items.Add(child); 63 | 64 | if (items.Count != column) 65 | continue; 66 | 67 | action(count, row++, items.ToArray()); 68 | items.Clear(); 69 | } 70 | 71 | if (items.Count == 0) 72 | return; 73 | 74 | action(count, ++row, items.ToArray()); 75 | items.Clear(); 76 | } 77 | 78 | double GetSize() 79 | { 80 | return GetValue(Size, 100d); 81 | } 82 | 83 | int GetColumn(double width) 84 | { 85 | var size = GetSize(); 86 | var value = GetValue(width); 87 | var column = value / size; 88 | 89 | return (int)Math.Max(column, 1); 90 | } 91 | 92 | static Size Layout(MetroWaterfallFlow layout, Size size, bool isMeasure) 93 | { 94 | var result = default(Size); 95 | 96 | var column = layout.GetColumn(size.Width); 97 | var itemSize = layout.GetValue(size.Width / column); 98 | 99 | var bottoms = new Dictionary(); 100 | 101 | for (var i = 0; i < column; i++) 102 | bottoms[i] = 0.0; 103 | 104 | layout.ForEach(column, (_, index, items) => 105 | { 106 | for (var i = 0; i < items.Length; i++) 107 | { 108 | var child = items[i]; 109 | 110 | if (isMeasure) 111 | child.Measure(new(itemSize, double.PositiveInfinity)); 112 | 113 | var newIndex = i; 114 | 115 | if (index >= column) 116 | { 117 | var current = bottoms[0]; 118 | newIndex = 0; 119 | 120 | for (var n = 1; n < bottoms.Count; n++) 121 | if (bottoms[n] < current) 122 | { 123 | current = bottoms[n]; 124 | newIndex = n; 125 | } 126 | } 127 | 128 | if (!isMeasure) 129 | child.Arrange(new(newIndex * itemSize, bottoms[newIndex], itemSize, 130 | child.DesiredSize.Height)); 131 | 132 | bottoms[newIndex] += child.DesiredSize.Height; 133 | } 134 | }); 135 | 136 | result.Width = layout.GetValue(size.Width); 137 | 138 | foreach (var bottom in bottoms) 139 | result.Height = Math.Max(result.Height, bottom.Value); 140 | 141 | return result; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroWindow.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | using System.Windows.Input; 4 | using System.Windows.Media; 5 | using Arthas.Shell; 6 | 7 | namespace Arthas.Controls; 8 | 9 | public class MetroWindow : MetroWindowBase 10 | { 11 | static MetroWindow() 12 | { 13 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroWindow), new FrameworkPropertyMetadata(typeof(MetroWindow))); 14 | } 15 | 16 | public static readonly DependencyProperty CaptionBackgroundProperty = DependencyProperty.Register(nameof(CaptionBackground), typeof(Brush), typeof(MetroWindow)); 17 | 18 | public Brush? CaptionBackground 19 | { 20 | get => (Brush?)GetValue(CaptionBackgroundProperty); 21 | set => SetValue(CaptionBackgroundProperty, value); 22 | } 23 | 24 | public static readonly DependencyProperty CaptionForegroundProperty = DependencyProperty.Register(nameof(CaptionForeground), typeof(Brush), typeof(MetroWindow)); 25 | 26 | public Brush? CaptionForeground 27 | { 28 | get => (Brush?)GetValue(CaptionForegroundProperty); 29 | set => SetValue(CaptionForegroundProperty, value); 30 | } 31 | 32 | public static readonly DependencyProperty CaptionContentProperty = DependencyProperty.Register(nameof(CaptionContent), typeof(object), typeof(MetroWindow)); 33 | 34 | public object? CaptionContent 35 | { 36 | get => GetValue(CaptionContentProperty); 37 | set => SetValue(CaptionContentProperty, value); 38 | } 39 | 40 | Grid? PART_Caption; 41 | 42 | public override void OnApplyTemplate() 43 | { 44 | base.OnApplyTemplate(); 45 | 46 | PART_Caption = GetTemplateChild(nameof(PART_Caption)) as Grid; 47 | 48 | if (PART_Caption is null) 49 | return; 50 | 51 | PART_Caption.MouseLeftButtonDown += ElementOnMouseLeftButtonDown; 52 | } 53 | 54 | void ElementOnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 55 | { 56 | if (Handle == IntPtr.Zero) 57 | return; 58 | 59 | if (e.ClickCount == 2) 60 | ChangWindowState(); 61 | 62 | else 63 | SendCaptionMessage(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Arthas/Controls/MetroWindow.xaml: -------------------------------------------------------------------------------- 1 |  6 | 39 | 126 | 127 | -------------------------------------------------------------------------------- /Arthas/Controls/ProgressBarState.cs: -------------------------------------------------------------------------------- 1 | namespace Arthas.Controls; 2 | 3 | public enum ProgressBarState 4 | { 5 | None, 6 | Error, 7 | Wait 8 | } 9 | -------------------------------------------------------------------------------- /Arthas/Converter/CornerRadiusToDouble.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows; 3 | using System.Windows.Data; 4 | 5 | namespace Arthas.Converter; 6 | 7 | public class CornerRadiusToDouble : IValueConverter 8 | { 9 | public object Convert(object value, Type targetType, object? parameter, CultureInfo culture) 10 | { 11 | if (parameter != null) 12 | return ((CornerRadius)value).TopLeft * System.Convert.ToDouble(parameter); 13 | return ((CornerRadius)value).TopLeft; 14 | } 15 | 16 | public object ConvertBack(object value, Type targetType, object? parameter, CultureInfo culture) 17 | { 18 | if (parameter != null) 19 | return new CornerRadius((double)value / System.Convert.ToDouble(parameter)); 20 | return new CornerRadius((double)value); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Arthas/Converter/DoubleToCornerRadius.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows; 3 | using System.Windows.Data; 4 | 5 | namespace Arthas.Converter; 6 | 7 | public class DoubleToCornerRadius : IValueConverter 8 | { 9 | public object Convert(object value, Type targetType, object? parameter, CultureInfo culture) 10 | { 11 | if (parameter != null) 12 | return new CornerRadius((double)value / System.Convert.ToDouble(parameter)); 13 | return new CornerRadius((double)value); 14 | } 15 | 16 | public object ConvertBack(object value, Type targetType, object? parameter, CultureInfo culture) 17 | { 18 | if (parameter != null) 19 | return ((CornerRadius)value).TopLeft * System.Convert.ToDouble(parameter); 20 | return ((CornerRadius)value).TopLeft; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Arthas/Converter/DoubleToThickness.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows; 3 | using System.Windows.Data; 4 | 5 | namespace Arthas.Converter; 6 | 7 | public class DoubleToThickness : IValueConverter 8 | { 9 | public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 10 | { 11 | if (value != null) 12 | { 13 | if (parameter != null) 14 | switch (parameter.ToString()) 15 | { 16 | case "Left": 17 | return new Thickness(System.Convert.ToDouble(value), 0, 0, 0); 18 | 19 | case "Top": 20 | return new Thickness(0, System.Convert.ToDouble(value), 0, 0); 21 | 22 | case "Right": 23 | return new Thickness(0, 0, System.Convert.ToDouble(value), 0); 24 | 25 | case "Buttom": 26 | return new Thickness(0, 0, 0, System.Convert.ToDouble(value)); 27 | 28 | case "LeftTop": 29 | return new Thickness(System.Convert.ToDouble(value), System.Convert.ToDouble(value), 0, 0); 30 | 31 | case "LeftButtom": 32 | return new Thickness(System.Convert.ToDouble(value), 0, 0, System.Convert.ToDouble(value)); 33 | 34 | case "RightTop": 35 | return new Thickness(0, System.Convert.ToDouble(value), System.Convert.ToDouble(value), 0); 36 | 37 | case "RigthButtom": 38 | return new Thickness(0, 0, System.Convert.ToDouble(value), System.Convert.ToDouble(value)); 39 | 40 | case "LeftRight": 41 | return new Thickness(System.Convert.ToDouble(value), 0, System.Convert.ToDouble(value), 0); 42 | 43 | case "TopButtom": 44 | return new Thickness(0, System.Convert.ToDouble(value), 0, System.Convert.ToDouble(value)); 45 | 46 | default: 47 | return new Thickness(System.Convert.ToDouble(value)); 48 | } 49 | 50 | return new Thickness(System.Convert.ToDouble(value)); 51 | } 52 | 53 | return new Thickness(0); 54 | } 55 | 56 | public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) 57 | { 58 | if (value != null) 59 | { 60 | if (parameter != null) 61 | switch (parameter.ToString()) 62 | { 63 | case "Left": 64 | return ((Thickness)value).Left; 65 | 66 | case "Top": 67 | return ((Thickness)value).Top; 68 | 69 | case "Right": 70 | return ((Thickness)value).Right; 71 | 72 | case "Buttom": 73 | return ((Thickness)value).Bottom; 74 | 75 | default: 76 | return ((Thickness)value).Left; 77 | } 78 | 79 | return ((Thickness)value).Left; 80 | } 81 | 82 | return 0.0; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Arthas/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Markup; 3 | 4 | [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] 5 | [assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Arthas.Controls")] 6 | -------------------------------------------------------------------------------- /Arthas/Resource.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Reflection; 3 | using System.Windows; 4 | using System.Windows.Media.Imaging; 5 | 6 | namespace Arthas; 7 | 8 | public static class Resource 9 | { 10 | public static BitmapImage? AsBitmapImage(Uri uri) 11 | { 12 | using var stream = AsStream(uri); 13 | 14 | return Stream2BitmapImage(stream); 15 | } 16 | 17 | public static BitmapImage? AsBitmapImage(string path, Assembly? assembly = null) 18 | { 19 | var callingAssembly = assembly ?? Assembly.GetCallingAssembly(); 20 | 21 | return AsBitmapImage(AsUri(path, callingAssembly)); 22 | } 23 | 24 | public static Stream? AsStream(Uri uri) 25 | { 26 | return Application.GetResourceStream(uri)?.Stream; 27 | } 28 | 29 | public static Stream? AsStream(string path, Assembly? assembly = null) 30 | { 31 | var callingAssembly = assembly ?? Assembly.GetCallingAssembly(); 32 | 33 | return AsStream(AsUri(path, callingAssembly)); 34 | } 35 | 36 | public static Uri AsUri(string path, Assembly? assembly = null) 37 | { 38 | var callingAssembly = assembly ?? Assembly.GetCallingAssembly(); 39 | 40 | return new($"pack://application:,,,/{callingAssembly.GetName().Name};component/{path}"); 41 | } 42 | 43 | static BitmapImage? Stream2BitmapImage(Stream? stream) 44 | { 45 | if (stream is null) 46 | return null; 47 | 48 | var bitmapImage = new BitmapImage 49 | { 50 | CacheOption = BitmapCacheOption.OnLoad 51 | }; 52 | 53 | bitmapImage.BeginInit(); 54 | bitmapImage.StreamSource = stream; 55 | bitmapImage.EndInit(); 56 | bitmapImage.Freeze(); 57 | 58 | return bitmapImage; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Arthas/ThemeBrush.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Markup; 2 | using System.Windows.Media; 3 | 4 | namespace Arthas; 5 | 6 | public class ThemeBrushExtension : MarkupExtension 7 | { 8 | readonly ThemeKey _key; 9 | 10 | public ThemeBrushExtension(ThemeKey key) 11 | { 12 | _key = key; 13 | } 14 | 15 | public override object ProvideValue(IServiceProvider serviceProvider) 16 | { 17 | return _key switch 18 | { 19 | ThemeKey.Primary => new SolidColorBrush(Color.FromRgb(92, 90, 238)), 20 | 21 | ThemeKey.Background => new(Color.FromRgb(247, 247, 247)), 22 | ThemeKey.BorderBrush => new(Color.FromArgb((byte)(255 * 0.1), 38, 38, 38)), 23 | ThemeKey.Foreground => new(Color.FromRgb(38, 38, 38)), 24 | 25 | ThemeKey.CaptionBackground => new(Color.FromRgb(92, 90, 238)), 26 | ThemeKey.CaptionForeground => new(Color.FromRgb(255, 255, 255)), 27 | 28 | _ => throw new ArgumentOutOfRangeException() 29 | }; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Arthas/ThemeKey.cs: -------------------------------------------------------------------------------- 1 | namespace Arthas; 2 | 3 | public enum ThemeKey 4 | { 5 | Primary, 6 | 7 | Background, 8 | BorderBrush, 9 | Foreground, 10 | 11 | CaptionBackground, 12 | CaptionForeground 13 | } 14 | -------------------------------------------------------------------------------- /Arthas/Themes/Generic.xaml: -------------------------------------------------------------------------------- 1 |  3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | dotnet clean --nologo -c Release 3 | dotnet pack --nologo -c Release -o ./Output -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | net7.0-windows 4 | enable 5 | latest 6 | enable 7 | true 8 | true 9 | 1.0.0 10 | 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 ONEO 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arthas 2 | 3 | > 一个 WPF 控件库,在学习 WPF 开发时创作 4 | 5 | ## 开发计划 6 | 7 | - 目前在 [develop](https://github.com/oneo-me/Arthas-WPFUI/tree/develop) 分支创作 8 | - MVVM 框架使用我另一个库 [OpenView](https://github.com/oneo-me/OpenView) 9 | - 我会尽可能的把这个库的全部问题修复 10 | - 不会增加新功能 11 | - 如果时间允许,我会开发一个基于 [Avalonia](https://avaloniaui.net/) 的界面库(与 WPF 写法类似,但可以跨主流平台) 12 | 13 | ## 截屏 14 | 15 | ![](Screenshots/1.png) 16 | 17 | ## 支持 18 | 19 | - .Net 7.0 Windows Desktop 20 | 21 | ## 食用方法 22 | 23 | - Clone 代码到本地 24 | - 打开项目 25 | -------------------------------------------------------------------------------- /Screenshots/1.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:f0227d2a9b3effe6f729bd514c9e701551ec1bb17f587ff3e4027f1d546548df 3 | size 122772 4 | --------------------------------------------------------------------------------