使用WindowStyle=None正确最大化WPF窗口

35g0bw71  于 12个月前  发布在  Windows
关注(0)|答案(6)|浏览(164)

当使用WindowStyle=None选项时,WPF窗口有两个问题。
1.窗口最大化时会覆盖任务栏。
1.一旦最大化,窗口不能被向下拖动以取消最大化。
如何纠正这些问题?最好不使用Windows.Forms。

cpjpxq1n

cpjpxq1n1#

在线上还有其他解决这些问题的方法。但是,它们都没有考虑到解决方案在多显示器设置中的执行情况。特别是如果主显示器不是设置中最左边的。
我设计这段代码时考虑到了单显示器和多显示器的设置。
这个解决方案也引入Windows.Forms作为参考,它使用非管理调用。

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>

字符串

代码隐藏

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;
        }
}

kfgdxczn

kfgdxczn2#

我有一个很好的快速和肮脏的解决方案。尝试以下代码时,最大化你的无边框窗口:

if (WindowState == WindowState.Normal)
{
      WindowStyle = WindowStyle.SingleBorderWindow;
      WindowState = WindowState.Maximized;
      WindowStyle = WindowStyle.None;
}

字符串
技巧是将WindowStyle设置为SingleBorderWindow,然后最大化窗口并将其设置回None

sqserrrh

sqserrrh3#

这样一个好代码leebickmtu!
我有一个多个显示器的小问题,在windows 10:因为有一个任务栏在每个屏幕上,如果你最大化你的窗口在辅助屏幕上他的任务栏成为隐藏.
我只是修改了一下这个方法,以便从任何屏幕上获得相对位置:

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);
}

字符串
希望这对你有帮助…

crcmnpdw

crcmnpdw4#

leebickmtu的答案基本上是正确的,但有一些无关的代码,并根据光标所在的位置选择监视器,而不是窗口所在的位置。如果鼠标在不同的监视器上,用户按Win + Up来最大化,那么这将产生错误的行为。我们应该使用MonitorFromWindow来识别要最大化的监视器。
在你的窗口代码中添加以下内容:

protected override void OnSourceInitialized(EventArgs e)
{
    base.OnSourceInitialized(e);
    ((HwndSource)PresentationSource.FromVisual(this)).AddHook(HookProc);
}

public static IntPtr HookProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    if (msg == WM_GETMINMAXINFO)
    {
        // We need to tell the system what our size should be when maximized. Otherwise it will
        // cover the whole screen, including the task bar.
        MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));

        // Adjust the maximized size and position to fit the work area of the correct monitor
        IntPtr monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);

        if (monitor != IntPtr.Zero)
        {
            MONITORINFO monitorInfo = new MONITORINFO();
            monitorInfo.cbSize = Marshal.SizeOf(typeof(MONITORINFO));
            GetMonitorInfo(monitor, ref monitorInfo);
            RECT rcWorkArea = monitorInfo.rcWork;
            RECT rcMonitorArea = monitorInfo.rcMonitor;
            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);
        }

        Marshal.StructureToPtr(mmi, lParam, true);
    }

    return IntPtr.Zero;
}

private const int WM_GETMINMAXINFO = 0x0024;

private const uint MONITOR_DEFAULTTONEAREST = 0x00000002;

[DllImport("user32.dll")]
private static extern IntPtr MonitorFromWindow(IntPtr handle, uint flags);

[DllImport("user32.dll")]
private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);

[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;

    public RECT(int left, int top, int right, int bottom)
    {
        this.Left = left;
        this.Top = top;
        this.Right = right;
        this.Bottom = bottom;
    }
}

[StructLayout(LayoutKind.Sequential)]
public struct MONITORINFO
{
    public int cbSize;
    public RECT rcMonitor;
    public RECT rcWork;
    public uint dwFlags;
}

[Serializable]
[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;
}

字符串

unhi4e5o

unhi4e5o5#

如果只使用一个监视器,另一个简单的方法是设置窗口的最大高度。System.Windows.SystemParameters类提供了一些有用的值,例如PrimaryScreenHeight或MaximizedPrimaryScreenHeight。
在我的示例代码中,我使用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;
    }
}

字符串

8fq7wneg

8fq7wneg6#

基于Dennis的优秀解决方案:

private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    HandleWinMaximized();
    StateChanged += MainWindow_StateChanged;
}

private void MainWindow_StateChanged(object sender, EventArgs e)
{
    HandleWinMaximized();
}

private void HandleWinMaximized()
{
    if (WindowState == WindowState.Maximized)
    {
        WindowStyle = WindowStyle.SingleBorderWindow;
        WindowStyle = WindowStyle.None;
    }
}

字符串

相关问题