65930


WPF で WindowChrome
を適用したウィンドウを最大化すると画面からはみだして最大化されます。こちらを画面サイズにぴったりあわせて最大化させたいです。

この補正をするためにウィンドウの BorderThickness に 8 を指定しているのですが、環境によっては隙間ができてしまうようです。  
このギャップ値(8)をシステムから求める正しい方法はありますでしょうか。もしくはぴったりに最大化する別の方法があるのでしょうか。

### 補足

  * WindowChrome の ResizeBorderThickness の値を使用するという情報を見つけたのですが、この値にかかわらず 8 にしないとぴったり最大化されませんでした。
  * 下記コード例では省略していますが、ギャップ値(8)には DPI を反映させて使用しています。

### 実装例

[code]

    <Window ..省略..>
    
        <WindowChrome.WindowChrome>
            <WindowChrome />
        </WindowChrome.WindowChrome>
    
        <Border BorderBrush="Red" BorderThickness="1">
            <Button Content="Maximize" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="20" Click="MaximizeButton_Click" />
        </Border>
    
    </Window>
    
[/code]

[code]

    using System;
    using System.Windows;
    
    namespace WpfMaximize
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                this.StateChanged += MainWindow_StateChanged;
            }
    
            private void MainWindow_StateChanged(object sender, EventArgs e)
            {
                if (this.WindowState == WindowState.Maximized)
                {
                    this.BorderThickness = new Thickness(8); // この値の求め方は？
                }
                else
                {
                    this.BorderThickness = new Thickness(0);
                }
            }
    
            private void MaximizeButton_Click(object sender, RoutedEventArgs e)
            {
                if (this.WindowState == WindowState.Maximized)
                {
                    this.WindowState = WindowState.Normal;
                }
                else
                {
                    this.WindowState = WindowState.Maximized;
                }
            }
        }
    }
    
[/code]

### 環境

  * Windows7, Windows10
  * VisualStudio 2019
  * .NET Framework 4.7.2

### 問題の発生する環境例

Windows7の個人設定でテーマを Windowsクラッシック に変更すると 8 では隙間ができることを確認しました。この場合は 4
で丁度になるようです。


CC BY-SA 4.0
2019-07-22T06:17:17.327
56806
2020-04-25T04:04:18.677
2019-07-29T11:23:42.740
14817
14817
question
c# .net wpf
WindowChromeを適用したウィンドウを最大化したときに画面サイズぴったりで最大化させたい


かなり強引ですが、このような実装はいかがでしょうか。  
Win32 APIで最大化時の計算を上書きするアイデアです。  
元のアイデアは[WindowChrome ResizeBorderThickness
issue](https://stackoverflow.com/questions/19280016/windowchrome-
resizeborderthickness-issue)です。

１：以下のようなNativeMethods.csを用意します。

[code]

    internal static class NativeMethods
    {
      [DllImport("user32.dll", SetLastError = true)]
      internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);
    
      [DllImport("user32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
      internal static extern bool GetMonitorInfo(IntPtr hMonitor, MonitorInformation lpmi);
    
      [StructLayout(LayoutKind.Sequential)]
      internal struct NativePoint
      {
        internal int X;
        internal int Y;
      }
    
      [Serializable]
      [StructLayout(LayoutKind.Sequential)]
      internal struct MinMaxInformation
      {
        internal NativePoint ptReserved;
        internal NativePoint ptMaxSize;
        internal NativePoint ptMaxPosition;
        internal NativePoint ptMinTrackSize;
        internal NativePoint ptMaxTrackSize;
      }
    
      [Serializable]
      [StructLayout(LayoutKind.Sequential)]
      internal struct Rectangle
      {
        internal int Left;
        internal int Top;
        internal int Right;
        internal int Bottom;
      }
    
      [Serializable]
      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
      internal class MonitorInformation
      {
        internal int cbSize = Marshal.SizeOf(typeof(MonitorInformation));
        internal Rectangle rcMonitor = new Rectangle();
        internal Rectangle rcWork = new Rectangle();
        internal int dwFlags = 0;
      }
    }
    
[/code]

２：Window.WindowStyle="None" を設定します。  
３：Window.SourceInitializedイベントで以下のような処理を実装します。

[code]

    private void Window_SourceInitialized(object sender, EventArgs e)
    {
      IntPtr handle = (new WindowInteropHelper(this)).Handle;
      HwndSource.FromHwnd(handle).AddHook(WinProc);
    }
    
    private IntPtr WinProc(
      IntPtr hwnd,
      int message,
      IntPtr wparam,
      IntPtr lparam,
      ref bool handled)
    {
      switch (message)
      {
        case 0x0024: /* WM_GETMINMAXINFO */
          handled = WmGetMinMaxInfo(hwnd, lparam, this);
          break;
      }
    
      return IntPtr.Zero;
    }
    
    private static bool WmGetMinMaxInfo(IntPtr hwnd, IntPtr lparam, Window window)
    {
      NativeMethods.MinMaxInformation mmi = (NativeMethods.MinMaxInformation)Marshal.PtrToStructure(lparam, typeof(NativeMethods.MinMaxInformation));
    
      IntPtr monitor = NativeMethods.MonitorFromWindow(hwnd, 2);
      if (monitor == IntPtr.Zero)
      {
        return false;
      }
    
      NativeMethods.MonitorInformation monitorInformation = new NativeMethods.MonitorInformation();
      if (!NativeMethods.GetMonitorInfo(monitor, monitorInformation))
      {
        return false;
      }
    
      NativeMethods.Rectangle workArea = monitorInformation.rcWork;
      NativeMethods.Rectangle monitorArea = monitorInformation.rcMonitor;
      mmi.ptMaxPosition.X = Math.Abs(workArea.Left - monitorArea.Left);
      mmi.ptMaxPosition.Y = Math.Abs(workArea.Top - monitorArea.Top);
      mmi.ptMaxSize.X = Math.Abs(workArea.Right - workArea.Left);
      mmi.ptMaxSize.Y = Math.Abs(workArea.Bottom - workArea.Top);
    
      Point magnification = GetDeviceToLogicalCoefficient(window);
    
      if (!double.IsInfinity(window.MinWidth) && !double.IsNaN(window.MinWidth))
      {
        mmi.ptMinTrackSize.X = (int)(window.MinWidth * magnification.X);
      }
    
      if (!double.IsInfinity(window.MinHeight) && !double.IsNaN(window.MinHeight))
      {
        mmi.ptMinTrackSize.Y = (int)(window.MinHeight * magnification.Y);
      }
    
      if (!double.IsInfinity(window.MaxWidth) && !double.IsNaN(window.MaxWidth))
      {
        mmi.ptMaxTrackSize.X = (int)(window.MaxWidth * magnification.X);
      }
    
      if (!double.IsInfinity(window.MaxHeight) && !double.IsNaN(window.MaxHeight))
      {
        mmi.ptMaxTrackSize.Y = (int)(window.MaxHeight * magnification.Y);
      }
    
      Marshal.StructureToPtr(mmi, lparam, true);
      return true;
    }
    
    internal static Point GetDeviceToLogicalCoefficient(Window window)
    {
      PresentationSource presentationSource = PresentationSource.FromVisual(window);
      if (presentationSource == null || presentationSource.CompositionTarget == null)
      {
        return new Point(1.0, 1.0);
      }
    
      return new Point
      {
        X = presentationSource.CompositionTarget.TransformToDevice.M11,
        Y = presentationSource.CompositionTarget.TransformToDevice.M22
      };
    }
    
[/code]


CC BY-SA 4.0
2020-04-24T15:55:20.183
65930
2020-04-25T04:04:18.677
2020-04-25T04:04:18.677
70
70
56806
answer