【问题标题】:AppBar Multi-MonitorAppBar 多显示器
【发布时间】:2013-01-19 20:40:58
【问题描述】:

我制作了一个简单的 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;
        }
    }

【问题讨论】:

    标签: c# appbar multiple-monitors


    【解决方案1】:

    您可以通过遍历 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;
        }
    }
    

    【讨论】:

    • 所以我基本上必须编写 2 个版本的代码,一个是 SystemInformation.WorkingArea,另一个是 nonPrimaryScreen.WorkingArea?
    • 好吧,你可以使用Rectangle 使其更通用。我将编辑我的答案。
    • 好的,但这只会在一个屏幕或另一个屏幕上,还是两个屏幕上都可以?问题是我不知道我是否在程序运行时将 Rectangle 从监视器 1 更改为监视器 2,如果它甚至会注意到或者 appbar 是否已经创建并且没有注意到监视器 2 的更改。
    • 不.. 我没有用勺子喂过你。我给了你一个例子,你可以把它插入你的代码库的其余部分。我不确切知道您的代码库是什么样的。使用通用函数.. 并在用户每次更改“是否主屏幕”选项时调用它。
    • 我明白了,你的代码很有帮助,但我花了一段时间才在我的程序中实现它,因为我不习惯 Windows Shell 编程。 API 中的示例代码也确实有帮助:msdn.microsoft.com/en-us/library/…。即使它是多线程的,我也无法从一个可执行文件中创建 2 个 appbar,因此如果相同的进程已经在运行,我让它在监视器 2 中运行(大概在监视器一中)。
    【解决方案2】:
     #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
    

    【讨论】:

    • 请在代码示例之外提供额外的描述。
    • 此示例支持更多屏幕显示应用栏。主要变化在这里:this.GetScreenObject(ScreenName) 部分。
    • 只需从选定屏幕定义应用栏位置。当您在垂直屏幕上使用 -1080 时,它会起作用。
    【解决方案3】:
    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或其他,然后在appbar位置使用。
    【解决方案4】:

    您可以计算将 AppBar 移动到第二台显示器的正确公式,而无需使用 PrimaryMonitorSize 以外的任何东西。例如,对于第二台显示器上的左侧 AppBar,您可以使用:

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

    【讨论】:

      猜你喜欢
      • 2016-05-16
      • 2017-09-06
      • 2019-04-15
      • 2020-03-07
      • 1970-01-01
      • 2012-11-12
      • 1970-01-01
      • 2023-03-17
      • 2020-06-11
      相关资源
      最近更新 更多