zoukankan      html  css  js  c++  java
  • 【WPF】无边框窗体

    之前写了一个支持尺寸变换的无边框窗体的一个基窗体,代码如下:

    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,这个应该可以改进,后期再看看。

  • 相关阅读:
    MiracleSnow网页设计HTML5+CSS3+JS全套视频教程
    Java开发者应该列入年度计划的5件事
    大爱HTML5 9款超炫HTML5最新动画源码
    10个PHP代码片段
    斯坦福大学即将上线10门公开课
    如何成为一个偷懒又高效的Android开发人员
    github版本库使用详细教程
    PHP5中PDO的简单使用
    Github 已经托管超过 1000 万个项目库
    DIOCP转发型中间网关
  • 原文地址:https://www.cnblogs.com/mqxs/p/5784220.html
Copyright © 2011-2022 走看看