【问题标题】:resize correctly on secondary monitor when clicking on taskbar icon wpf单击任务栏图标 wpf 时在辅助监视器上正确调整大小
【发布时间】:2020-11-03 23:55:52
【问题描述】:

我有一个 wpf 应用程序,我使用 WmGetMinMaxInfo 管理最大尺寸:

private static void WmGetMinMaxInfo(IntPtr hwnd, IntPtr lParam)
{
    MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));
    IntPtr monitorContainingApplication = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);

    if (monitorContainingApplication != System.IntPtr.Zero)
    {
        MONITORINFO monitorInfo = new MONITORINFO();
        GetMonitorInfo(monitorContainingApplication, 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);

        mmi.ptMaxTrackSize.x = mmi.ptMaxSize.x;
        mmi.ptMaxTrackSize.y = mmi.ptMaxSize.y;
        
    }

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

我的窗口设置为:

WindowStyle="None"
ResizeMode="CanResizeWithGrip" 
AllowsTransparency="True"

当我在最大化状态下最小化应用程序以及单击任务栏图标返回以返回最大化窗口应用程序时,我遇到了一个奇怪的问题。

它不占用全屏,它似乎占用了主屏幕分辨率。 当我在主屏幕和辅助屏幕之间没有相同的分辨率时,我遇到了这种情况(显然我的辅助屏幕比第一个大)。

您知道问题出在哪里吗? Windows功能 ? 有什么解决办法吗?

解决方案: 我已经用 Keithernet 的想法解决了我的问题,即在最小化 windowState 时不重新计算。谢谢!

private static void WmGetMinMaxInfo(IntPtr hwnd, IntPtr lParam)
{
    MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));
    IntPtr monitorContainingApplication = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);

    if (monitorContainingApplication != System.IntPtr.Zero)
    {
        MONITORINFO monitorInfo = new MONITORINFO();
        GetMonitorInfo(monitorContainingApplication, monitorInfo);
        RECT rcWorkArea = monitorInfo.rcWork;
        RECT rcMonitorArea = monitorInfo.rcMonitor;

        if (Application.Current.MainWindow.WindowState != WindowState.Minimized)
        {
            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);

            mmi.ptMaxTrackSize.x = mmi.ptMaxSize.x;
            mmi.ptMaxTrackSize.y = mmi.ptMaxSize.y;
            lastGoodMaxTrackSize = mmi.ptMaxTrackSize;
            lastGoodMaxPosition = mmi.ptMaxPosition;
            lastGoodMaxSize = mmi.ptMaxSize;
        }
        else
        {
            mmi.ptMaxPosition = lastGoodMaxPosition;
            mmi.ptMaxSize = lastGoodMaxSize;
            mmi.ptMaxTrackSize = lastGoodMaxTrackSize;
        }
        mmi = AdjustWorkingAreaForAutoHide(monitorContainingApplication, mmi);
    }

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

【问题讨论】:

  • 你能发布你的 WmGetMinMaxInfo 代码吗?
  • WindowStyle="None" WindowState="Maximized" ResizeMode="NoResize" 跟随链接stackoverflow.com/questions/35009880/…
  • 我刚刚编辑了@Keithernet 和 NoResize 参数并没有改变问题

标签: c# wpf


【解决方案1】:

我有一个多年前编写的自定义窗口控件。它仍在积极使用中。无论窗口在哪个显示器上以及单个 DPI 是多少,都可以正确处理窗口。

这是我对WmGetMinMaxInfo 的实现。

我希望这会有所帮助。

private void WmGetMinMaxInfo(IntPtr hwnd, IntPtr lParam)
{
    var mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));
    var hMonitor = Win32.MonitorFromWindow(hwnd, 1);
    
    if (hMonitor != IntPtr.Zero)
    {
        var monitorInfo = new Win32.MONITORINFO();
        
        Win32.GetMonitorInfo(hMonitor, monitorInfo);
        
        var rcWorkArea = monitorInfo.rcWork;
        var 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);
        
        mmi.ptMinTrackSize.x = (int)(minWidth * hidpiX);
        mmi.ptMinTrackSize.y = (int)(minHeight * hidpiY);

        var window = (Window)HwndSource.FromHwnd(hwnd)?.RootVisual;

        if (window != null)
        {
            if (window.WindowState != WindowState.Minimized)
            {
                mmi.ptMaxTrackSize.x = Win32.GetSystemMetrics(Win32.SystemMetric.SM_CXVIRTUALSCREEN);
                mmi.ptMaxTrackSize.y = Win32.GetSystemMetrics(Win32.SystemMetric.SM_CYVIRTUALSCREEN);
                
                lastGoodMaxTrackSize = mmi.ptMaxTrackSize;
            }
            else if (lastGoodMaxTrackSize.x > 0 && lastGoodMaxTrackSize.y > 0)
            {
                mmi.ptMaxTrackSize = lastGoodMaxTrackSize;
            }
        }
    
        mmi = AdjustWorkingAreaForAutoHide(hMonitor, mmi);
    }

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

对于 hidpiX 和 hidpiY,我将它们放在 OnSourceInitialized 事件的处理程序中。

private void OnSourceInitialized(object sender, EventArgs e)
{
    ...

    var source = PresentationSource.FromVisual((Visual)sender);

    if (source == null) return;

    // Get the X and Y HiDPI factors from the media matrix
    if (source.CompositionTarget != null)
    {
        hidpiX = source.CompositionTarget.TransformToDevice.M11;
        hidpiY = source.CompositionTarget.TransformToDevice.M22;
    }

    ...
}

【讨论】:

  • 嗨 Keithernet,刚刚尝试了您的解决方案,问题始终存在。当我在辅助屏幕上最大化窗口时,它会占用所有屏幕,而不仅仅是辅助分辨率,因为我们使用虚拟屏幕。当您使用我的解决方案时,它可以在辅助屏幕上使用。但是,当您单击任务栏图标以最小化并再次单击该图标时。窗口不会以最大尺寸备份。只是具有固定的宽度和高度。
  • 我已经解决了我的问题并在那里编辑了我的问题。感谢您对@Keithernet 的支持。
  • 嗨@Keithernet,我只是将我的解决方案(针对 HiDpi)与您的解决方案相适应,现在可以正常工作了。谢谢你
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多