使用 WindowStyle=None 正确最大化 WPF 窗口
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20941443/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Properly maximizing WPF window with WindowStyle=None
提问by leebickmtu
There are two problems with WPF windows when the WindowStyle=None option is used.
使用 WindowStyle=None 选项时,WPF 窗口有两个问题。
- The window covers the Taskbar when maximized.
- Once maximized, the window cannot be dragged down to unmaximize.
- 窗口最大化时覆盖任务栏。
- 窗口一旦最大化,就不能向下拖动以取消最大化。
How can these problems be corrected? Preferably without using Windows.Forms.
如何纠正这些问题?最好不使用 Windows.Forms。
回答by leebickmtu
There are other answers to these problems online. However none of them take into acount how the solution will perform on setups with multiple monitors. Especially if the primary monitor is not the left-most in the setup.
这些问题网上还有其他答案。然而,他们都没有考虑到该解决方案将如何在多台显示器的设置上执行。特别是如果主显示器不是设置中的最左侧。
I designed this code taking into account single and multiple monitors setups.
我设计此代码时考虑了单个和多个显示器设置。
This solution also does notbring in Windows.Forms as a reference, it uses unmanagaged calls.
此解决方案也没有引入 Windows.Forms 作为参考,它使用非托管调用。
XAML
XAML
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Background="AliceBlue" WindowStyle="None" Height="350" Width="525" SourceInitialized="Window_SourceInitialized">
<Grid>
<Rectangle Name="rctHeader" Height="40" VerticalAlignment="Top" Fill="CadetBlue" PreviewMouseLeftButtonDown="rctHeader_PreviewMouseLeftButtonDown" PreviewMouseLeftButtonUp="rctHeader_PreviewMouseLeftButtonUp" PreviewMouseMove="rctHeader_PreviewMouseMove"/>
</Grid>
</Window>
Code Behind
背后的代码
using System.Runtime.InteropServices;
using System.Windows.Interop;
private bool mRestoreIfMove = false;
public MainWindow()
{
InitializeComponent();
}
void Window_SourceInitialized(object sender, EventArgs e)
{
IntPtr mWindowHandle = (new WindowInteropHelper(this)).Handle;
HwndSource.FromHwnd(mWindowHandle).AddHook(new HwndSourceHook(WindowProc));
}
private static System.IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case 0x0024:
WmGetMinMaxInfo(hwnd, lParam);
break;
}
return IntPtr.Zero;
}
private static void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam)
{
POINT lMousePosition;
GetCursorPos(out lMousePosition);
IntPtr lPrimaryScreen = MonitorFromPoint(new POINT(0, 0), MonitorOptions.MONITOR_DEFAULTTOPRIMARY);
MONITORINFO lPrimaryScreenInfo = new MONITORINFO();
if (GetMonitorInfo(lPrimaryScreen, lPrimaryScreenInfo) == false)
{
return;
}
IntPtr lCurrentScreen = MonitorFromPoint(lMousePosition, MonitorOptions.MONITOR_DEFAULTTONEAREST);
MINMAXINFO lMmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));
if (lPrimaryScreen.Equals(lCurrentScreen) == true)
{
lMmi.ptMaxPosition.X = lPrimaryScreenInfo.rcWork.Left;
lMmi.ptMaxPosition.Y = lPrimaryScreenInfo.rcWork.Top;
lMmi.ptMaxSize.X = lPrimaryScreenInfo.rcWork.Right - lPrimaryScreenInfo.rcWork.Left;
lMmi.ptMaxSize.Y = lPrimaryScreenInfo.rcWork.Bottom - lPrimaryScreenInfo.rcWork.Top;
}
else
{
lMmi.ptMaxPosition.X = lPrimaryScreenInfo.rcMonitor.Left;
lMmi.ptMaxPosition.Y = lPrimaryScreenInfo.rcMonitor.Top;
lMmi.ptMaxSize.X = lPrimaryScreenInfo.rcMonitor.Right - lPrimaryScreenInfo.rcMonitor.Left;
lMmi.ptMaxSize.Y = lPrimaryScreenInfo.rcMonitor.Bottom - lPrimaryScreenInfo.rcMonitor.Top;
}
Marshal.StructureToPtr(lMmi, lParam, true);
}
private void SwitchWindowState()
{
switch (WindowState)
{
case WindowState.Normal:
{
WindowState = WindowState.Maximized;
break;
}
case WindowState.Maximized:
{
WindowState = WindowState.Normal;
break;
}
}
}
private void rctHeader_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ClickCount == 2)
{
if ((ResizeMode == ResizeMode.CanResize) || (ResizeMode == ResizeMode.CanResizeWithGrip))
{
SwitchWindowState();
}
return;
}
else if (WindowState == WindowState.Maximized)
{
mRestoreIfMove = true;
return;
}
DragMove();
}
private void rctHeader_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
mRestoreIfMove = false;
}
private void rctHeader_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (mRestoreIfMove)
{
mRestoreIfMove = false;
double percentHorizontal = e.GetPosition(this).X / ActualWidth;
double targetHorizontal = RestoreBounds.Width * percentHorizontal;
double percentVertical = e.GetPosition(this).Y / ActualHeight;
double targetVertical = RestoreBounds.Height * percentVertical;
WindowState = WindowState.Normal;
POINT lMousePosition;
GetCursorPos(out lMousePosition);
Left = lMousePosition.X - targetHorizontal;
Top = lMousePosition.Y - targetVertical;
DragMove();
}
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetCursorPos(out POINT lpPoint);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr MonitorFromPoint(POINT pt, MonitorOptions dwFlags);
enum MonitorOptions : uint
{
MONITOR_DEFAULTTONULL = 0x00000000,
MONITOR_DEFAULTTOPRIMARY = 0x00000001,
MONITOR_DEFAULTTONEAREST = 0x00000002
}
[DllImport("user32.dll")]
static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
public POINT(int x, int y)
{
this.X = x;
this.Y = y;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct MINMAXINFO
{
public POINT ptReserved;
public POINT ptMaxSize;
public POINT ptMaxPosition;
public POINT ptMinTrackSize;
public POINT ptMaxTrackSize;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class MONITORINFO
{
public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));
public RECT rcMonitor = new RECT();
public RECT rcWork = new RECT();
public int dwFlags = 0;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left, Top, Right, Bottom;
public RECT(int left, int top, int right, int bottom)
{
this.Left = left;
this.Top = top;
this.Right = right;
this.Bottom = bottom;
}
}
回答by Dennis
I have a nice quick and dirty solution. Try following code when maximize your none bordered window:
我有一个很好的快速和肮脏的解决方案。在最大化无边框窗口时尝试以下代码:
if (WindowState == WindowState.Normal)
{
WindowStyle = WindowStyle.SingleBorderWindow;
WindowState = WindowState.Maximized;
WindowStyle = WindowStyle.None;
}
The trick is to set the WindowStyleto SingleBorderWindowthen maximize the window and set it back to None.
诀窍是将 设置WindowStyle为SingleBorderWindow然后最大化窗口并将其设置回None。
回答by Leplaidn
Such a nice code leebickmtu!
这么好的代码 leebickmtu!
I had a little issue with multiple monitors, in windows 10 : since there is a taskBar on each screen, if you maximize your window on a secondary screen his taskbar become hidden.
我在 Windows 10 中遇到了多个显示器的小问题:由于每个屏幕上都有一个任务栏,如果您在辅助屏幕上最大化窗口,他的任务栏会隐藏。
I just modify a bit this method, in order to have relative position from any screen :
我只是稍微修改一下这个方法,以便从任何屏幕获得相对位置:
private static void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam)
{
POINT lMousePosition;
GetCursorPos(out lMousePosition);
IntPtr lCurrentScreen = MonitorFromPoint(lMousePosition, MonitorOptions.MONITOR_DEFAULTTONEAREST);
MINMAXINFO lMmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));
MONITORINFO lCurrentScreenInfo = new MONITORINFO();
if (GetMonitorInfo(lCurrentScreen, lCurrentScreenInfo) == false)
{
return;
}
//Position relative pour notre fenêtre
lMmi.ptMaxPosition.X = lCurrentScreenInfo.rcWork.Left - lCurrentScreenInfo.rcMonitor.Left;
lMmi.ptMaxPosition.Y = lCurrentScreenInfo.rcWork.Top - lCurrentScreenInfo.rcMonitor.Top;
lMmi.ptMaxSize.X = lCurrentScreenInfo.rcWork.Right - lCurrentScreenInfo.rcWork.Left;
lMmi.ptMaxSize.Y = lCurrentScreenInfo.rcWork.Bottom - lCurrentScreenInfo.rcWork.Top;
Marshal.StructureToPtr(lMmi, lParam, true);
}
Hope this help...
希望这有助于...
回答by zznobody
If only one monitor is used another simple approach is to set the maximum height of the window. The System.Windows.SystemParameters class provides some usefull values e.g. PrimaryScreenHeight or MaximizedPrimaryScreenHeight.
如果只使用一台显示器,另一种简单的方法是设置窗口的最大高度。System.Windows.SystemParameters 类提供了一些有用的值,例如 PrimaryScreenHeight 或 MaximizedPrimaryScreenHeight。
In my sample code i use MaximizedPrimaryScreenHeight and subtract the ResizeBorderThickness i set in WindowChrome.
在我的示例代码中,我使用 MaximizedPrimaryScreenHeight 并减去我在 WindowChrome 中设置的 ResizeBorderThickness。
using System.Windows;
using System.Windows.Shell;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Thickness resizeBorderThickness = WindowChrome.GetWindowChrome(this).ResizeBorderThickness;
this.MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight - resizeBorderThickness.Top - resizeBorderThickness.Bottom;
}
}

