c# - 在通知区域附近打开 WPF 窗口,支持多显示器

标签 c# wpf windows tray

我的 wpf 应用程序应该打开一个靠近通知区域的窗口。当用户点击托盘图标时打开一个窗口。所以我需要通知区域所在的同一屏幕上的窗口。现在我刚刚获得任务栏位置:https://stackoverflow.com/a/8581546/1502011 和屏幕上的任务栏矩形 https://stackoverflow.com/a/3677319/1502011然后我用它来定位我的窗口,如:

//xaml.cs
var taskBarLocation = GetTaskBarLocation();
var taskBarPosition = GetTaskbarPosition();

this.Left = taskBarLocation == Location.Left
            ? taskBarPosition.Width
            : SystemParameters.WorkArea.Width - Width;

this.Top = taskBarLocation == Location.Top
            ? taskBarPosition.Height
            : SystemParameters.WorkArea.Height - Height;

仅当通知区域位于主屏幕时才有效。据我所知,我应该使用 WinApi 将我的窗口放在其他显示器上,但我什至不知道如何找到带有通知区域的屏幕。任何帮助将不胜感激。

最佳答案

好的,因为

1) Wpf 窗口位置不关心监视器(它在“控制面板\所有控制面板项\显示\屏幕分辨率”坐标上工作,而不是在当前屏幕坐标上)

2) WinApi 方法 SHAppBarMessage(5, ref data) 也适用于全局坐标

3) 每个屏幕对象都有Bounds表示屏幕在全局坐标中的位置的属性

解决方法很简单:

public static class TaskBarLocationProvider
{
    // P/Invoke goo:
    private const int ABM_GETTASKBARPOS = 5;

    [DllImport("shell32.dll")]
    private static extern IntPtr SHAppBarMessage(int msg, ref AppBarData data);

    /// <summary>
    /// Where is task bar located (at top of the screen, at bottom (default), or at the one of sides)
    /// </summary>
    private enum Dock
    {
        Left = 0,
        Top = 1,
        Right = 2,
        Bottom = 3
    }

    private struct Rect
    {
        public int Left, Top, Right, Bottom;
    }

    private struct AppBarData
    {
        public int cbSize;
        public IntPtr hWnd;
        public int uCallbackMessage;
        public Dock Dock;
        public Rect rc;
        public IntPtr lParam;
    }

    private static Rectangle GetTaskBarCoordinates(Rect rc)
    {
        return new Rectangle(rc.Left, rc.Top,
            rc.Right - rc.Left, rc.Bottom - rc.Top);
    }

    private static AppBarData GetTaskBarLocation()
    {
        var data = new AppBarData();
        data.cbSize = Marshal.SizeOf(data);

        IntPtr retval = SHAppBarMessage(ABM_GETTASKBARPOS, ref data);

        if (retval == IntPtr.Zero)
        {
            throw new Win32Exception("WinAPi Error: does'nt work api method SHAppBarMessage");

        }

        return data;
    }

    private static Screen FindScreenWithTaskBar(Rectangle taskBarCoordinates)
    {
        foreach (var screen in Screen.AllScreens)
        {
            if (screen.Bounds.Contains(taskBarCoordinates))
            {
                return screen;
            }
        }

        return Screen.PrimaryScreen;
    }

    /// <summary>
    /// Calculate wpf window position for place it near to taskbar area
    /// </summary>
    /// <param name="windowWidth">target window height</param>
    /// <param name="windowHeight">target window width</param>
    /// <param name="left">Result left coordinate <see cref="System.Windows.Window.Left"/></param>
    /// <param name="top">Result top coordinate <see cref="System.Windows.Window.Top"/></param>
    public static void CalculateWindowPositionByTaskbar(double windowWidth, double windowHeight, out double left, out double top)
    {
        var taskBarLocation = GetTaskBarLocation();
        var taskBarRectangle = GetTaskBarCoordinates(taskBarLocation.rc);
        var screen = FindScreenWithTaskBar(taskBarRectangle);

        left = taskBarLocation.Dock == Dock.Left
            ? screen.Bounds.X + taskBarRectangle.Width
            : screen.Bounds.X + screen.WorkingArea.Width - windowWidth;

        top = taskBarLocation.Dock == Dock.Top
            ? screen.Bounds.Y + taskBarRectangle.Height
            : screen.Bounds.Y + screen.WorkingArea.Height - windowHeight;
    }

和xaml.cs中的用法

    private void SetWindowPosition()
    {
        double left, right;
        TaskBarLocationProvider.CalculateWindowPositionByTaskbar(this.Width, this.Height, out left, out right);

        Left = left;
        Top = right;
    }

关于c# - 在通知区域附近打开 WPF 窗口,支持多显示器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25508009/

相关文章:

c# - 忽略控制台应用程序中的 Web 浏览器 SSL 安全警报

c# - 网络服务是什么意思?

c# - 如何隐藏没有可见项目的上下文菜单?

python - Boost:在窗口中包含路径

windows - 如何防止控制台窗口在 ghc 应用程序中关闭?

c# - 将 Java 日期字符串转换为 C# 日期时间

c# - 简单的线程测试

c# - 我的 ViewModel 是否具有 Model 的属性和单独的属性?

wpf - 如何将OxyPlot原点设置在左上角?

c++ - 如何使用 C++ 在 Active Directory 的属性中设置值?