如何使用WPF C#实现全屏模式而不覆盖任务栏

17
我需要在我的WPF应用程序中更改Windows任务栏。为此,我设置WindowStyle="None",这意味着禁用Windows任务栏,并制作自定义任务栏,其中包括还原、最小化和关闭应用程序的按钮。现在我的问题是,如果应用程序处于最大化模式,则无法看到Windows的开始菜单。
我在这里找到了一个类似的问题,但当我尝试这段代码时,它没有编译。full screen mode, but don't cover the taskbar 我该如何创建自己的任务栏并能够在最大化时看到Windows的开始菜单?是否有一个XAML窗口属性可以设置它?
7个回答

26

你可以尝试这个:

MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight;
MaxWidth = SystemParameters.MaximizedPrimaryScreenWidth;

有超过1个屏幕的情况怎么处理? - Valerii
1
@Valerii 在这种情况下,您可以尝试使用Screen.AllScreens集合。您可以循环该集合并访问screen.WorkingArea.Widthscreen.WorkingArea.Height。如果有效,请告诉我,以便我可以编辑我的答案。 - Pikoh
@Pikoh Screen类是System.Windows.Forms的一部分,与WPF不兼容。替代方案是SystemParameters.WorkAreaWidthSystemParameters.WorkAreaHeight,这很有帮助,但在多显示器场景下不太适用。 - tkefauver
这个解决方案对于连接为扩展屏幕的多个屏幕无效。我提供了下面的一个解决方案,适用于任意数量的屏幕,并且每个屏幕都可以完美地工作。我已经测试过它在3个屏幕上(主笔记本屏幕和两个扩展屏幕)。 - Umar

8

您可以通过添加以下内容轻松在XAML中添加高度约束:

MaxHeight="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenHeight}}"

进入 Windows 标签页。


最简单的解决方案!谢谢 - Dairon

5

3
我在以下链接中找到了一个非常好的解决方案,可以解决这里讨论的问题:https://codekong.wordpress.com/2010/11/10/custom-window-style-and-accounting-for-the-taskbar/。 这个解决方案可以直接使用,为了帮助未来的任何人,我在这里添加了参考资料。 这里没有任何现有的解决方案适用于在扩展模式下连接多个屏幕的情况。 以下是提供的解决方案,需要从 XAML 或代码后台绑定 SourceInitialized 事件。
this.SourceInitialized += new EventHandler(Window1_SourceInitialized);

以下是事件回调的源代码:

void Window1_SourceInitialized(object sender, EventArgs e)
{
    WindowSizing.WindowInitialized(this);
}

以下是WindowSizing.cs的代码:
using System;
using System.Runtime.InteropServices;
using System.Windows;

namespace OfficeStyleWindowProject
{
   public static class WindowSizing
   {
    const int MONITOR_DEFAULTTONEAREST = 0x00000002;

    #region DLLImports

    [DllImport("shell32", CallingConvention = CallingConvention.StdCall)]
    public static extern int SHAppBarMessage(int dwMessage, ref APPBARDATA pData);

    [DllImport("user32", SetLastError = true)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32")]
    internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);

    [DllImport("user32")]
    internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);

    #endregion

    private static MINMAXINFO AdjustWorkingAreaForAutoHide(IntPtr monitorContainingApplication, MINMAXINFO mmi)
    {
        IntPtr hwnd = FindWindow("Shell_TrayWnd", null);
        if (hwnd == null) return mmi;
        IntPtr monitorWithTaskbarOnIt = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
        if (!monitorContainingApplication.Equals(monitorWithTaskbarOnIt)) return mmi;
        APPBARDATA abd = new APPBARDATA();
        abd.cbSize = Marshal.SizeOf(abd);
        abd.hWnd = hwnd;
        SHAppBarMessage((int)ABMsg.ABM_GETTASKBARPOS, ref abd);
        int uEdge = GetEdge(abd.rc);
        bool autoHide = System.Convert.ToBoolean(SHAppBarMessage((int)ABMsg.ABM_GETSTATE, ref abd));

        if (!autoHide) return mmi;

        switch (uEdge)
        {
            case (int)ABEdge.ABE_LEFT:
                mmi.ptMaxPosition.x += 2;
                mmi.ptMaxTrackSize.x -= 2;
                mmi.ptMaxSize.x -= 2;
                break;
            case (int)ABEdge.ABE_RIGHT:
                mmi.ptMaxSize.x -= 2;
                mmi.ptMaxTrackSize.x -= 2;
                break;
            case (int)ABEdge.ABE_TOP:
                mmi.ptMaxPosition.y += 2;
                mmi.ptMaxTrackSize.y -= 2;
                mmi.ptMaxSize.y -= 2;
                break;
           case (int)ABEdge.ABE_BOTTOM:
                mmi.ptMaxSize.y -= 2;
                mmi.ptMaxTrackSize.y -= 2;
                break;
            default:
                return mmi;
        }
        return mmi;
    }

    private static int GetEdge(RECT rc)
    {
        int uEdge = -1;
        if (rc.top == rc.left && rc.bottom > rc.right)
            uEdge = (int)ABEdge.ABE_LEFT;
        else if (rc.top == rc.left && rc.bottom < rc.right)
            uEdge = (int)ABEdge.ABE_TOP;
        else if (rc.top > rc.left)
            uEdge = (int)ABEdge.ABE_BOTTOM;
        else
            uEdge = (int)ABEdge.ABE_RIGHT;
        return uEdge;
    }

    public static void WindowInitialized(Window window)
    {
        IntPtr handle = (new System.Windows.Interop.WindowInteropHelper(window)).Handle;
        System.Windows.Interop.HwndSource.FromHwnd(handle).AddHook(new System.Windows.Interop.HwndSourceHook(WindowProc));
    }

    private static IntPtr WindowProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled)
    {
        switch (msg)
        {
           case 0x0024:
                WmGetMinMaxInfo(hwnd, lParam);
                handled = true;
                break;
        }

        return (IntPtr)0;
    }

    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;                                                 //maximum drag X size for the window
            mmi.ptMaxTrackSize.y = mmi.ptMaxSize.y;                                                 //maximum drag Y size for the window
            mmi.ptMinTrackSize.x = 800;                                                             //minimum drag X size for the window
            mmi.ptMinTrackSize.y = 600;                                                             //minimum drag Y size for the window
            mmi = AdjustWorkingAreaForAutoHide(monitorContainingApplication, mmi);                  //need to adjust sizing if taskbar is set to autohide
        }
        Marshal.StructureToPtr(mmi, lParam, true);
    }

    public enum ABEdge
    {
        ABE_LEFT = 0,
        ABE_TOP = 1,
        ABE_RIGHT = 2,
        ABE_BOTTOM = 3
    }

    public enum ABMsg
    {
        ABM_NEW = 0,
        ABM_REMOVE = 1,
        ABM_QUERYPOS = 2,
        ABM_SETPOS = 3,
        ABM_GETSTATE = 4,
        ABM_GETTASKBARPOS = 5,
        ABM_ACTIVATE = 6,
        ABM_GETAUTOHIDEBAR = 7,
        ABM_SETAUTOHIDEBAR = 8,
        ABM_WINDOWPOSCHANGED = 9,
        ABM_SETSTATE = 10
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct APPBARDATA
    {
        public int cbSize;
        public IntPtr hWnd;
        public int uCallbackMessage;
        public int uEdge;
        public RECT rc;
        public bool lParam;
    }

    [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 POINT
    {
        public int x;
        public int y;

        public POINT(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
    }

    [StructLayout(LayoutKind.Sequential, Pack = 0)]
    public struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }
}
}

~乌玛尔


2
WindowStyle="None" 
AllowsTransparency="True"  

并且

this.Top = 0;
this.Left = 0;
this.Width = SystemParameters.WorkArea.Width;
this.Height = SystemParameters.WorkArea.Height;

2

提出的解决方案对我有用,但是仍需要更正像素到dpi设置器的值,以便窗口具有正确的大小,而不受用户设置的影响:

在xaml中:

WindowStyle="None" WindowState="Maximized" ResizeMode="NoResize"

在代码中:

public MainWindow()
{
    InitializeComponent();
    var graphics = System.Drawing.Graphics.FromHwnd(IntPtr.Zero);
    var pixelWidth = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width ;
    var pixelHeight = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height;
    var pixelToDPI = 96.0 / graphics.DpiX ;
    this.Width = pixelWidth * pixelToDPI;
    this.Height = pixelHeight * pixelToDPI;
    this.Left = 0;
    this.Top = 0;
    this.WindowState = WindowState.Normal;
}

对我来说,我需要设置MaxWidth和MaxHeight而不是Width和Height。 - Bora Aydın

1

WPF解决方案

假设我们想要将WPF项目的主窗口放在屏幕的右下角,而不覆盖任务栏。 我们会这样写:

public MainWindow()
    {
        InitializeComponent();
        // set position of window on screen
        this.Left = SystemParameters.PrimaryScreenWidth - this.Width;
        this.Top = SystemParameters.WorkArea.Bottom - this.Height;
    }

这是我们的对象(MainWindow)。 首先,我们需要将左参数放置到主屏幕宽度减去窗口位置(左侧)的位置。 然后,通过从屏幕底部的工作区减去窗口高度来获取最低点。 屏幕的工作区不包括任务栏! 享受吧! Avri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接