【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() >> );
double left = this.WindowState == System.Windows.WindowState.Maximized ? : this.Left;
double top = this.WindowState == System.Windows.WindowState.Maximized ? : 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 = ;
mmi.ptMaxPosition.y = ;
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 = ;
this.WindowState = System.Windows.WindowState.Minimized;
this.WindowState = state;
this.Opacity = ;
}
/// <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();
else
grid.Margin = new Thickness();
if (this.Opacity == )
this.Opacity = ;
}
/// <summary>
/// 初始化
/// </summary>
private void Initialize()
{
this.Opacity = ;
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 = ; //拐角宽度
private readonly int bThickness = ; // 边框宽度
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 = ;
}
/// <summary>
/// 矩形
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = )]
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 = -,
HTTRANSPARENT = -,
HTNOWHERE = ,
HTCLIENT = ,
HTCAPTION = ,
HTSYSMENU = ,
HTGROWBOX = ,
HTSIZE = HTGROWBOX,
HTMENU = ,
HTHSCROLL = ,
HTVSCROLL = ,
HTMINBUTTON = ,
HTMAXBUTTON = ,
HTLEFT = ,
HTRIGHT = ,
HTTOP = ,
HTTOPLEFT = ,
HTTOPRIGHT = ,
HTBOTTOM = ,
HTBOTTOMLEFT = ,
HTBOTTOMRIGHT = ,
HTBORDER = ,
HTREDUCE = HTMINBUTTON,
HTZOOM = HTMAXBUTTON,
HTSIZEFIRST = HTLEFT,
HTSIZELAST = HTBOTTOMRIGHT,
HTOBJECT = ,
HTCLOSE = ,
HTHELP = ,
}
}
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,这个应该可以改进,后期再看看。
【WPF】无边框窗体的更多相关文章
- wpf无边框窗体移动和大小调整
原文:wpf无边框窗体移动和大小调整 using System; using System.Windows; using System.Windows.Interop; namespace Wpf ...
- WPFの无边框窗体以及控件的移动
对于WPF,一旦隐藏了标题栏,就无法移动,这时候需要重写移动方法,下面列举常见的三种方式方式. 方式一:重写OnMouseLeftButtonDown protected override void ...
- 【转】【WPF】 WPF 调用API修改窗体风格实现真正的无边框窗体
WPF中设置无边框窗体似乎是要将WindowStyle设置为None,AllowTransparency=true,这样才能达到WinForm中无边框窗体的样式.但是AllowTransparency ...
- 01.WPF中制作无边框窗体
[引用:]http://blog.csdn.net/johnsuna/article/details/1893319 众所周知,在WinForm中,如果要制作一个无边框窗体,可以将窗体的FormB ...
- C# .net WPF无边框移动窗体
转自 http://download.csdn.net/detail/xiang348352/3095084 WPF无边框移动窗体,先在<Window>里添加 MouseLeftButto ...
- WPF中制作无边框窗体
原文:WPF中制作无边框窗体 众所周知,在WinForm中,如果要制作一个无边框窗体,可以将窗体的FormBorderStyle属性设置为None来完成.如果要制作成异形窗体,则需要使用图片或者使用G ...
- WPF 调用API修改窗体风格实现真正的无边框窗体
原文:WPF 调用API修改窗体风格实现真正的无边框窗体 WPF中设置无边框窗体似乎是要将WindowStyle设置为None,AllowTransparency=true,这样才能达到WinForm ...
- WPF无边框移动窗体
WPF无边框移动窗体,先在<Window>里添加 MouseLeftButtonDown=”Window_MouseLeftButtonDown” 然后导航到事件,在事件里添加 if (e ...
- 利用WPF创建含多种交互特性的无边框窗体
咳咳,标题一口气读下来确实有点累,让我先解释一下.另外文章底部有演示程序的下载. 本文介绍利用WPF创建一个含有以下特性的窗口: 有窗口阴影,比如QQ窗口外围只有几像素的阴影: 支持透明且无边框,为了 ...
随机推荐
- Java 中Comparator 的使用,实现集合排序
目标:实现对Person 对象的年龄,从小到大排序 1.实现排序 package com.app; import java.util.ArrayList; import java.util.Colle ...
- 解决tableViewCell分割线不到左边界的问题
在tableView控制器的.m文件中任何位置加入以下两个方法即可解决 /** * 下面两个方法解决cell分割线不到左边界的问题 */ -(void)viewDidLayoutSubviews { ...
- C++语言-03-类与对象
类 类是面向对象编程中的核心概念,用于定义一个数据类型的蓝图,描述类的对象包括什么,以及可以在这些对象上执行那些操作. 类的成员 数据成员 描述数据的表示方法 class ClassName { ac ...
- IOS之Foundation之探究学习Swift实用基础整理<一>
import Foundation //加载网络数据,查找数据的字符串 let dataurl = "http://api.k780.com:88/?app=weather.city& ...
- abs()函数的返回值问题
转载原文地址:http://www.cnblogs.com/webary/p/4967868.html 在牛客网看到一道关于abs()函数返回值的题目,见下图,当时还没反应过来,第一反应是:自从我开始 ...
- Asp.net MVC 4新项目中创建area的后续操作
Asp.net MVC 4新项目中创建area后,往往HomeController与area的HomeController路由发生混淆,需要手工设置一些地方避免mvc无法识别默认路由的状况. 无废话具 ...
- MyEclipse Workspace 项目文件 .project .classpath .mymetadata解析
<!-- .classpath文件 --> <?xml version="1.0" encoding="UTF-8"?> <cla ...
- C# 日志框架的添加
.NET中 记录日志的比较好的主要是Log4Net和Enterprise Library的Logging 复杂一点的还可以实现自动化Log日志 教程 首先是第二种方式 1.需要添加以下几个DLL 下 ...
- 最短路径之迪杰斯特拉(Dijkstra)算法
迪杰斯特拉(Dijkstra)算法主要是针对没有负值的有向图,求解其中的单一起点到其他顶点的最短路径算法.本文主要总结迪杰斯特拉(Dijkstra)算法的原理和算法流程,最后通过程序实现在一个带权值的 ...
- 问题解决——MFC SDI程序 CFormView中控件随窗口缩放
从来都是做对话框程序,这次想做个SDI的程序,想着用一下带Robbin界面的office2007风格,就不用使用那些花钱的商业控件/UI库了. 如果你不想看我打的文字,可以直接拷走代码,自己声明上定义 ...