AppBar多显示器

4

我已经创建了一个简单的appBar,只是在屏幕顶部放置了一个标签,可以缩小桌面,但我无法让它显示在我的第二个监视器上。我一直在搜寻,但我找到的所有内容都是针对WPF的。这可能是我犯错的地方,但如果您需要查看任何其他代码,请告诉我。

private void InitializeComponent()
{
    this.ClientSize = new System.Drawing.Size(SystemInformation.WorkingArea.Width, -1);
    this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
    this.Name = "MainForm";
    this.Text = "AppBar";
    this.Closing += new System.ComponentModel.CancelEventHandler(this.OnClosing);
    this.Load += new System.EventHandler(this.OnLoad);
    this.BackColor = Color.Green;
    this.Padding = new Padding(0, 0, 0, 0);
    Label label1 = new Label();
    label1.Text = "TEXT";
    label1.Width = 270;
    label1.Margin = new Padding(0,0,0,0);
    label1.Padding = new Padding(0,0,0,0);
    label1.TextAlign = ContentAlignment.MiddleCenter;
    label1.ForeColor = Color.White;
    label1.Font = new Font(FontFamily.GenericSansSerif, 12,FontStyle.Regular);
    label1.Location = new Point((SystemInformation.WorkingArea.Width - 270) / 2, 0);
    this.Controls.Add(label1);
}

private void ABSetPos()
{
    APPBARDATA abd = new APPBARDATA();
    abd.cbSize = Marshal.SizeOf(abd);
    abd.hWnd = this.Handle;
    abd.uEdge = (int)ABEdge.ABE_TOP;

    if (abd.uEdge == (int)ABEdge.ABE_LEFT || abd.uEdge == (int)ABEdge.ABE_RIGHT)
    {
        abd.rc.top = 0;
        abd.rc.bottom = SystemInformation.PrimaryMonitorSize.Height;
        if (abd.uEdge == (int)ABEdge.ABE_LEFT)
        {
            abd.rc.left = 0;
            abd.rc.right = Size.Width;
        }
        else
        {
            abd.rc.right = SystemInformation.PrimaryMonitorSize.Width;
            abd.rc.left = abd.rc.right - Size.Width;
        }

    }
    else
    {
        abd.rc.left = 0;
        abd.rc.right = SystemInformation.PrimaryMonitorSize.Width;
        if (abd.uEdge == (int)ABEdge.ABE_TOP)
        {
            abd.rc.top = 0;
            abd.rc.bottom = Size.Height;
        }
        else
        {
            abd.rc.bottom = SystemInformation.PrimaryMonitorSize.Height;
            abd.rc.top = abd.rc.bottom - Size.Height;
        }
    }
4个回答

2

您可以通过迭代Screen.AllScreens数组来使用不同的屏幕。例如,以下是获取第一个非主要显示器的方法:

Screen nonPrimaryScreen = Screen.AllScreens.FirstOrDefault(x => !x.Primary);

如果你在任何地方使用 SystemInformation.WorkingArea (它总是使用主屏幕),你可以使用以下代码:

nonPrimaryScreen.WorkingArea

假设nonPrimaryScreen != null ...当然。

编辑:

不要重复代码,使其更加通用:

public static Rectangle GetWorkingArea() {
    if (UseWantsItOnPrimaryScreen) {
        return SystemInformation.WorkingArea;
    }
    else {
        return Screen.AllScreens.FirstOrDefault(x => !x.Primary).WorkingArea;
    }
}

那我基本上需要写两个版本的代码吗?一个使用SystemInformation.WorkingArea,另一个使用nonPrimaryScreen.WorkingArea? - Jim
不是这样的..你可以使用一个“矩形”使它更通用。我会编辑我的答案。 - Simon Whitehead
好的,但这只会显示在一个屏幕上还是两个屏幕上?问题是,我不知道如果我在程序运行时将矩形从监视器1更改为监视器2,它是否会注意到或者应用栏已经被创建并且不会注意到对监视器2的更改。 - Jim
不是的,我没有给你一份成熟的代码,而是提供了一个示例,供你插入到你现有的代码库中。我并不知道你的代码库具体是什么样子的。使用通用函数,并在用户更改主屏幕选项时调用它。 - Simon Whitehead
我已经弄清楚了,你的代码很有帮助,但是由于我不习惯Windows Shell编程,所以我花了一些时间来实现它。此外,API中的示例代码确实很有帮助:http://msdn.microsoft.com/en-us/library/system.windows.forms.screen.aspx。即使是多线程的,我也无法从一个可执行文件中创建2个应用栏,因此如果相同的进程已在监视器1中运行,则将其运行在监视器2中。 - Jim

1
private Screen GetScreenObject(String Name)
{
    logger.Info(GlobalModulename + "@ ScreenList::looking for screen:"+Name);
    if ((Name == "Primary"))
    {
        bool ExpectedParameter = true;
        foreach (var screen in Screen.AllScreens)
        {
            // For each screen, add the screen properties to a list box.
            logger.Info(GlobalModulename + "@ ScreenList::("+screen.DeviceName.ToString()+")Primary Screen: " + screen.Primary.ToString());
            if (screen.Primary==ExpectedParameter)
            {
                return screen;
            }
        }
    }
    if ((Name == "Secondary"))
    {
        bool ExpectedParameter = false;
        foreach (var screen in Screen.AllScreens)
        {
            // For each screen, add the screen properties to a list box.
            logger.Info(GlobalModulename + "@ ScreenList::(" + screen.DeviceName.ToString() + ")Primary Screen: " + screen.Primary.ToString());
            if (screen.Primary == ExpectedParameter)
            {
                return screen;
            }
        }
    }

    // konkretni jmeno obrazovky tak jak je to v systemu
    try
    {
        foreach (var screen in Screen.AllScreens)
        {
            // For each screen, add the screen properties to a list box.
            logger.Info("UEFA_Core @ ScreenList::Device Name: " + screen.DeviceName);
            logger.Info("UEFA_Core @ ScreenList::Bounds: " + screen.Bounds.ToString());
            logger.Info("UEFA_Core @ ScreenList::Type: " + screen.GetType().ToString());
            logger.Info("UEFA_Core @ ScreenList::Working Area: " + screen.WorkingArea.ToString());
            logger.Info("UEFA_Core @ ScreenList::Primary Screen: " + screen.Primary.ToString());
            if (screen.DeviceName == Name) return screen;
        }

    }
    catch { }

    // podobne jmeno obrazovky tak jak je to v systemu
    try
    {
        foreach (var screen in Screen.AllScreens)
        {
            // For each screen, add the screen properties to a list box.
            logger.Info("UEFA_Core @ ScreenList::Device Name: " + screen.DeviceName);
            logger.Info("UEFA_Core @ ScreenList::Bounds: " + screen.Bounds.ToString());
            logger.Info("UEFA_Core @ ScreenList::Type: " + screen.GetType().ToString());
            logger.Info("UEFA_Core @ ScreenList::Working Area: " + screen.WorkingArea.ToString());
            logger.Info("UEFA_Core @ ScreenList::Primary Screen: " + screen.Primary.ToString());
            if (screen.DeviceName.Contains(Name)) return screen;
        }

    }
    catch { }

    logger.Info("UEFA_Core @ ScreenList::No screen found by name");
    return Screen.PrimaryScreen;
}

这是getscreenobject的示例(没有什么特别的),只需返回屏幕对象,如Screen.PrimaryScreen或其他对象,然后在应用程序栏位置中使用。 - Stepan Hlava

1
 #region APPBAR

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

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

    enum ABMsg : int
    {
        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
    }

    enum ABNotify : int
    {
        ABN_STATECHANGE = 0,
        ABN_POSCHANGED,
        ABN_FULLSCREENAPP,
        ABN_WINDOWARRANGE
    }

    enum ABEdge : int
    {
        ABE_LEFT = 0,
        ABE_TOP,
        ABE_RIGHT,
        ABE_BOTTOM
    }

    private bool fBarRegistered = false;

    [DllImport("SHELL32", CallingConvention = CallingConvention.StdCall)]
    static extern uint SHAppBarMessage(int dwMessage, ref APPBARDATA pData);
    [DllImport("USER32")]
    static extern int GetSystemMetrics(int Index);
    [DllImport("User32.dll", ExactSpelling = true,
        CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    private static extern bool MoveWindow
        (IntPtr hWnd, int x, int y, int cx, int cy, bool repaint);
    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    private static extern int RegisterWindowMessage(string msg);
    private int uCallBack;

    private void RegisterBar()
    {
        APPBARDATA abd = new APPBARDATA();
        abd.cbSize = Marshal.SizeOf(abd);
        abd.hWnd = this.Handle;
        if (!fBarRegistered)
        {
            uCallBack = RegisterWindowMessage("AppBarMessage");
            abd.uCallbackMessage = uCallBack;

            uint ret = SHAppBarMessage((int)ABMsg.ABM_NEW, ref abd);
            fBarRegistered = true;

            ABSetPos();
        }
        else
        {
            SHAppBarMessage((int)ABMsg.ABM_REMOVE, ref abd);
            fBarRegistered = false;
        }
    }

    private void ABSetPos()
    {

        APPBARDATA abd = new APPBARDATA();
        abd.cbSize = Marshal.SizeOf(abd);
        abd.hWnd = this.Handle;
        abd.uEdge = (int)ABEdge.ABE_TOP;

        if (abd.uEdge == (int)ABEdge.ABE_LEFT || abd.uEdge == (int)ABEdge.ABE_RIGHT)
        {
            abd.rc.top = this.GetScreenObject(ScreenName).Bounds.Top; //0;
            abd.rc.bottom = this.GetScreenObject(ScreenName).Bounds.Top + this.GetScreenObject(ScreenName).Bounds.Height; //SystemInformation.PrimaryMonitorSize.Height;
            if (abd.uEdge == (int)ABEdge.ABE_LEFT)
            {
                abd.rc.left = this.GetScreenObject(ScreenName).Bounds.Left;//0;
                abd.rc.right = Size.Width;
            }
            else
            {
                abd.rc.right = this.GetScreenObject(ScreenName).Bounds.Left + this.GetScreenObject(ScreenName).Bounds.Width; // SystemInformation.PrimaryMonitorSize.Width;
                abd.rc.left = abd.rc.right - Size.Width;
            }

        }
        else
        {
            abd.rc.left = this.GetScreenObject(ScreenName).Bounds.Left; //0;
            abd.rc.right = this.GetScreenObject(ScreenName).Bounds.Left+this.GetScreenObject(ScreenName).Bounds.Width; //SystemInformation.PrimaryMonitorSize.Width;
            if (abd.uEdge == (int)ABEdge.ABE_TOP)
            {
                abd.rc.top = this.GetScreenObject(ScreenName).Bounds.Top;  //0 nebo -1080                    
                abd.rc.bottom = Size.Height;
            }
            else
            {
                abd.rc.bottom = this.GetScreenObject(ScreenName).Bounds.Top + this.GetScreenObject(ScreenName).Bounds.Height; //SystemInformation.PrimaryMonitorSize.Height;
                abd.rc.top = abd.rc.bottom - Size.Height;
            }
        }

        // Query the system for an approved size and position. 
        SHAppBarMessage((int)ABMsg.ABM_QUERYPOS, ref abd);

        // Adjust the rectangle, depending on the edge to which the 
        // appbar is anchored. 
        switch (abd.uEdge)
        {
            case (int)ABEdge.ABE_LEFT:
                abd.rc.right = abd.rc.left + Size.Width;
                break;
            case (int)ABEdge.ABE_RIGHT:
                abd.rc.left = abd.rc.right - Size.Width;
                break;
            case (int)ABEdge.ABE_TOP:
                abd.rc.bottom = abd.rc.top + Size.Height;
                break;
            case (int)ABEdge.ABE_BOTTOM:
                abd.rc.top = abd.rc.bottom - Size.Height;
                break;
        }

        // Pass the final bounding rectangle to the system. 
        SHAppBarMessage((int)ABMsg.ABM_SETPOS, ref abd);

        // Move and size the appbar so that it conforms to the 
        // bounding rectangle passed to the system. 
        MoveWindow(abd.hWnd, abd.rc.left, abd.rc.top,
            abd.rc.right - abd.rc.left, abd.rc.bottom - abd.rc.top, true);
    }

    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        if (m.Msg == uCallBack)
        {
            switch (m.WParam.ToInt32())
            {
                case (int)ABNotify.ABN_POSCHANGED:
                    ABSetPos();
                    break;
            }
        }

        try
        {
            base.WndProc(ref m);
        }
        catch (Exception E) { }
    }

    protected override System.Windows.Forms.CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.Style &= (~0x00C00000); // WS_CAPTION
            cp.Style &= (~0x00800000); // WS_BORDER
            //cp.ExStyle = 0x00000080 | 0x00000008 | 0x20; // WS_EX_TOOLWINDOW | WS_EX_TOPMOST  
            //cp.ExStyle &= 0x20;
            cp.ExStyle |= 0x00000008 | 0x00000080;
            //cp.ExStyle &= 0x00000080 ; // WS_EX_TOOLWINDOW | WS_EX_TOPMOST  
            return cp;
        }
    }

    private void OnLoad(object sender, System.EventArgs e)
    {
        RegisterBar();
    }

    private void OnClosing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        RegisterBar();
    }

    #endregion

请在代码示例之外提供附加说明。 - Maciej Lach
这个例子支持更多屏幕来显示应用栏。主要的变化在于这里:this.GetScreenObject(ScreenName) 部分。 - Stepan Hlava
只需定义,从选定的屏幕中选择appbar位置。当您在垂直屏幕上使用-1080时,它是功能性的。 - Stepan Hlava

0

你可以仅使用PrimaryMonitorSize计算正确的公式,将你的AppBar移动到第二个监视器上。例如,对于第二个监视器上的左侧AppBar,你可以使用以下代码:

if (abd.uEdge == (int)ABEdge.ABE_LEFT)
{
     abd.rc.left = SystemInformation.PrimaryMonitorSize.Width;
     abd.rc.right = SystemInformation.PrimaryMonitorSize.Width + Size.Width;
}

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