2014-01-06 19 views
10

Es gibt zwei Probleme mit WPF-Fenstern, wenn die Option WindowStyle = None verwendet wird.Richtiges Maximieren des WPF-Fensters mit WindowStyle = None

  1. Das Fenster bedeckt die Taskleiste, wenn maximiert.
  2. Einmal maximiert, kann das Fenster nicht zu Unmaximierung gezogen werden.

Wie können diese Probleme behoben werden? Vorzugsweise ohne Windows.Forms.

Antwort

26

Es gibt andere Antworten auf diese Probleme online. Jedoch berücksichtigt keiner von ihnen, wie die Lösung bei Setups mit mehreren Monitoren funktioniert. Vor allem, wenn der primäre Monitor nicht der am weitesten links im Setup ist.

Ich entwarf diesen Code unter Berücksichtigung von einzelnen und mehreren Monitoren Setups.

Diese Lösung auch nicht in Windows.Forms als Referenz bringen, verwendet es unmanagaged Anrufe.

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 hinter

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

+1 für nicht beschissen winforms stopfen –

+1

Nice one verwenden, danke, ich den gleichen Code verwendet mein Fenster richtig zum Laufen zu bringen, Schande Microsoft konnte nicht eine Option hinzufügen, dies automatisch zu tun. +1 – JustAPleb

+0

Dieser Ansatz macht MinWidth & MinHeight nutzlos. Irgendeine Problemumgehung? – SepehrM

4

Ich habe eine schöne schnelle und schmutzige Lösung. Versuchen Sie folgenden Code ein, wenn Sie keine umrandete Fenster maximieren:

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

Der Trick, um die WindowStyle-SingleBorderWindow dann maximieren Sie das Fenster setzen und setzen Sie ihn zurück zu None.

+1

Das ist großartig, solange Sie AllowTransparency nicht verwenden = true –

2

So ein schöner Code leebickmtu!

Ich hatte ein kleines Problem mit mehreren Monitoren, in Windows 10: Da es eine Taskleiste auf jedem Bildschirm gibt, wenn Sie Ihr Fenster auf einem zweiten Bildschirm maximieren, wird seine Taskleiste ausgeblendet.

ich ändere nur ein bisschen diese Methode, um von einem beliebigen Bildschirm relative Position zu haben:

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 ...

0

Wenn nur ein Monitor verwendet wird, ein weiterer einfacher Ansatz ist es, Stellen Sie die maximale Höhe des Fensters ein. Die System.Windows.SystemParameters-Klasse stellt einige nützliche Werte bereit, z. PrimaryScreenHeight oder MaximizedPrimaryScreenHeight.

In meinem Beispielcode verwende ich MaximizedPrimaryScreenHeight und subtrahiere die ResizeBorderThickness, die ich in WindowChrome einstelle.

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

Nun habe ich herausgefunden, dass der optimale Wert für MaxHeight nicht von der ResizeBorderThickness abhängt. In meinem Szenario ist der optimale Wert für MaxHeight MaximizedPrimaryScreenHeight - 10. – zznobody