之前写了一个支持尺寸变换的无边框窗体的一个基窗体,代码如下:
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,这个应该可以改进,后期再看看。