之前写了一个支持尺寸变换的无边框窗体的一个基窗体,代码如下:
public class LBaseWindow : Window { /// <summary> /// 基窗体 /// </summary> public LBaseWindow() { Initialize(); } /// <summary> /// 是否显示任务栏,如果任务栏不显示,则窗体覆盖整个屏幕 /// </summary> public Visibility TaskbarVisibility { get { return _taskbarVisibility; } set { if (_taskbarVisibility != value) { _taskbarVisibility = value; SetTaskbarChange(); } } } /// <summary> /// 源数据初始化 /// </summary> /// <param name="e"></param> protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource; if (hwndSource != null) { hwndSource.AddHook(new HwndSourceHook(this.WndProc)); _handle = hwndSource.Handle; } } /// <summary> /// 消息截获 /// </summary> /// <param name="hwnd"></param> /// <param name="msg"></param> /// <param name="wParam"></param> /// <param name="lParam"></param> /// <param name="handled"></param> /// <returns></returns> protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { #region[窗体大小修改] case WM_NCHITTEST: this.mousePoint.X = (lParam.ToInt32() & 0xFFFF); this.mousePoint.Y = (lParam.ToInt32() >> 16); double left = this.WindowState == System.Windows.WindowState.Maximized ? 0 : this.Left; double top = this.WindowState == System.Windows.WindowState.Maximized ? 0 : this.Top; // 窗口左上角 if (this.mousePoint.Y - this.Top <= this.agWidth && this.mousePoint.X - left <= this.agWidth) { handled = true; return new IntPtr((int)HitTest.HTTOPLEFT); } // 窗口左下角 else if (this.ActualHeight + top - this.mousePoint.Y <= this.agWidth && this.mousePoint.X - left <= this.agWidth) { handled = true; return new IntPtr((int)HitTest.HTBOTTOMLEFT); } // 窗口右上角 else if (this.mousePoint.Y - top <= this.agWidth && this.ActualWidth + left - this.mousePoint.X <= this.agWidth) { handled = true; return new IntPtr((int)HitTest.HTTOPRIGHT); } // 窗口右下角 else if (this.ActualWidth + left - this.mousePoint.X <= this.agWidth && this.ActualHeight + top - this.mousePoint.Y <= this.agWidth) { handled = true; return new IntPtr((int)HitTest.HTBOTTOMRIGHT); } // 窗口左侧 else if (this.mousePoint.X - left <= this.bThickness) { handled = true; return new IntPtr((int)HitTest.HTLEFT); } // 窗口右侧 else if (this.ActualWidth + left - this.mousePoint.X <= this.bThickness) { handled = true; return new IntPtr((int)HitTest.HTRIGHT); } // 窗口上方 else if (this.mousePoint.Y - top <= this.bThickness) { handled = true; return new IntPtr((int)HitTest.HTTOP); } // 窗口下方 else if (this.ActualHeight + top - this.mousePoint.Y <= this.bThickness) { handled = true; return new IntPtr((int)HitTest.HTBOTTOM); } else { return IntPtr.Zero; //handled = true; //return new IntPtr((int)HitTest.HTCAPTION); } #endregion #region[窗体最大化控制] case WM_GETMINMAXINFO: WMGetMinMaxInfo(hwnd, lParam); handled = true; break; #endregion } return IntPtr.Zero; } /// <summary> /// 控制窗体最大化 /// </summary> /// <param name="hwnd"></param> /// <param name="lParam"></param> protected virtual void WMGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam) { MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO)); // Adjust the maximized size and position to fit the work area of the correct monitor int MONITOR_DEFAULTTONEAREST = 0x00000002; System.IntPtr monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); if (monitor != System.IntPtr.Zero) { MONITORINFO monitorInfo = new MONITORINFO(); GetMonitorInfo(monitor, monitorInfo); RECT rcWorkArea = monitorInfo.rcWork; RECT rcMonitorArea = monitorInfo.rcMonitor; if (TaskbarVisibility == System.Windows.Visibility.Visible) { mmi.ptMaxPosition.x = Math.Abs(rcWorkArea.left - rcMonitorArea.left); mmi.ptMaxPosition.y = Math.Abs(rcWorkArea.top - rcMonitorArea.top); mmi.ptMaxSize.x = Math.Abs(rcWorkArea.right - rcWorkArea.left); mmi.ptMaxSize.y = Math.Abs(rcWorkArea.bottom - rcWorkArea.top); } else { mmi.ptMaxPosition.x = 0; mmi.ptMaxPosition.y = 0; mmi.ptMaxSize.x = rcMonitorArea.right; mmi.ptMaxSize.y = rcMonitorArea.bottom; } } Marshal.StructureToPtr(mmi, lParam, true); } /// <summary> /// 设置修改任务栏变更 /// </summary> private void SetTaskbarChange() { WindowState state = this.WindowState; this.Opacity = 0; this.WindowState = System.Windows.WindowState.Minimized; this.WindowState = state; this.Opacity = 1; } /// <summary> /// 窗体阴影半径修改 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ShadowRadiusChanged() { ControlTemplate template = (ControlTemplate)this.Resources["WindowTemplate"]; if (template == null) return; Grid grid = (Grid)template.FindName("ClientGrid", this); if (grid == null) return; if (this.WindowState != System.Windows.WindowState.Maximized) grid.Margin = new Thickness(10); else grid.Margin = new Thickness(0); if (this.Opacity == 0) this.Opacity = 1; } /// <summary> /// 初始化 /// </summary> private void Initialize() { this.Opacity = 0; this.Loaded += (sender, e) => InitializeEvent(); this.ContentRendered += (sender, e) => ShadowRadiusChanged(); this.SizeChanged += (sender, e) => ShadowRadiusChanged(); } /// <summary> /// 初始化事件 /// </summary> private void InitializeEvent() { ResourceDictionary resource = new ResourceDictionary(); resource.Source = new Uri(@"pack://application:,,,/DepthView;component/View/Styles/WindowStyle.xaml", UriKind.RelativeOrAbsolute); this.Resources.MergedDictionaries.Add(resource); this.Style = (Style)this.Resources["WindowStyleKey"]; } private const int WM_SYSCOMMAND = 0x112; private const int WM_GETMINMAXINFO = 0x0024; private const int SC_CLOSE = 0xF060; private const int SC_MINIMIZE = 0xF020; private const int SC_MAXIMIZE = 0xF030; private const int WM_NCHITTEST = 0x0084; private readonly int agWidth = 12; //拐角宽度 private readonly int bThickness = 4; // 边框宽度 private Point mousePoint = new Point(); //鼠标坐标 private Visibility _taskbarVisibility; private IntPtr _handle; [DllImport("user32.dll")] internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); [DllImport("User32.dll", EntryPoint = "SendMessage")] internal static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); [DllImport("user32")] internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi); [DllImport("User32")] internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public class MONITORINFO { /// <summary> /// </summary> public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); /// <summary> /// </summary> public RECT rcMonitor = new RECT(); /// <summary> /// </summary> public RECT rcWork = new RECT(); /// <summary> /// </summary> public int dwFlags = 0; } /// <summary> /// 矩形 /// </summary> [StructLayout(LayoutKind.Sequential, Pack = 0)] public struct RECT { /// <summary> /// 左边界坐标 /// </summary> public int left; /// <summary> /// 上边界坐标 /// </summary> public int top; /// <summary> /// 右边界坐标 /// </summary> public int right; /// <summary> /// 下边界坐标 /// </summary> public int bottom; } /// <summary> /// 窗体大小信息 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct MINMAXINFO { public POINT ptReserved; public POINT ptMaxSize; public POINT ptMaxPosition; public POINT ptMinTrackSize; public POINT ptMaxTrackSize; }; /// <summary> /// POINT aka POINTAPI /// </summary> [StructLayout(LayoutKind.Sequential)] public struct POINT { /// <summary> /// x coordinate of point. /// </summary> public int x; /// <summary> /// y coordinate of point. /// </summary> public int y; /// <summary> /// Construct a point of coordinates (x,y). /// </summary> public POINT(int x, int y) { this.x = x; this.y = y; } } /// <summary> /// 鼠标点击信息 /// </summary> public enum HitTest : int { HTERROR = -2, HTTRANSPARENT = -1, HTNOWHERE = 0, HTCLIENT = 1, HTCAPTION = 2, HTSYSMENU = 3, HTGROWBOX = 4, HTSIZE = HTGROWBOX, HTMENU = 5, HTHSCROLL = 6, HTVSCROLL = 7, HTMINBUTTON = 8, HTMAXBUTTON = 9, HTLEFT = 10, HTRIGHT = 11, HTTOP = 12, HTTOPLEFT = 13, HTTOPRIGHT = 14, HTBOTTOM = 15, HTBOTTOMLEFT = 16, HTBOTTOMRIGHT = 17, HTBORDER = 18, HTREDUCE = HTMINBUTTON, HTZOOM = HTMAXBUTTON, HTSIZEFIRST = HTLEFT, HTSIZELAST = HTBOTTOMRIGHT, HTOBJECT = 19, HTCLOSE = 20, HTHELP = 21, } }
Xaml:
<ControlTemplate x:Key="WindowTemplate" TargetType="{x:Type Window}"> <Grid x:Name="ClientGrid" Margin="10"> <Border Background="{x:Null}" BorderBrush="{TemplateBinding Background}" BorderThickness="2" CornerRadius="3"> <Border.Effect> <DropShadowEffect x:Name="shadow" BlurRadius="10" ShadowDepth="0"/> </Border.Effect> </Border> <Border Background="{x:Null}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Margin}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" CornerRadius="3"> <ContentPresenter /> </Border> </Grid> </ControlTemplate> <Style x:Key="WindowStyleKey" TargetType="{x:Type Window}"> <Setter Property="Template" Value="{DynamicResource ResourceKey=WindowTemplate}"></Setter> </Style>
有一个问题就是全屏是否显示任务栏,目前是采用最小化后最大化,来触发WndProc,这个应该可以改进,后期再看看。