【问题标题】:Move apps between monitors - C#在监视器之间移动应用程序 - C#
【发布时间】:2020-11-19 17:33:44
【问题描述】:

我有一个表单引用如下:

MainForm= Form1;

但是在同一个类的另一个方法中;在检测到该系统有超过 1 个监视器后:

int screens = Screen.AllScreens.Length;
if (screens > 1)
{
    model.AddItem((CefMenuCommand)26504, "Switch Screen (Monitor)");
    model.AddSeparator();
}

我需要在这些之间切换:

Screen[] lsScreen = Screen.AllScreens;
Screen myScreen = Screen.FromControl(MainForm);

if(myScreen == lsScreen[1])
{
    MainForm.Location = lsScreen[0].WorkingArea.Location; // Primary Screen
    MainForm.Top = MainForm.Left = 0;
    MainForm.Width = lsScreen[0].WorkingArea.Width;
    MainForm.Height = lsScreen[0].WorkingArea.Height;
}
else
{
    MainForm.Location = lsScreen[1].WorkingArea.Location; // Secondary Screen
    MainForm.Width = lsScreen[1].WorkingArea.Width;
    MainForm.Height = lsScreen[1].WorkingArea.Height;
}

更新

这是 Visual Studio 2019 的展示:

  1. 部分正确;因为我可以将应用程序从主屏幕移动到辅助屏幕;问题是我无法从辅助屏幕移动到主屏幕(返回);在我看来,错误出现在最后一段代码中,我无法确定它是什么。

  2. 另一个限制是它只能在两个屏幕之间工作;初级和次级;如何调整我的代码以改进它,使其支持不确定数量的屏幕...

【问题讨论】:

  • 需要心理调试。也许这个方法被多次调用,订阅事件时常见的错误。设置断点。
  • 该方法只被调用一次。所以添加这行代码(CefMenuCommand)26504,“实际触发功能的切换屏幕(监视器)。
  • @HansPassant 我认为 IF 中的比较不够……if(myScreen == lsScreen[1])

标签: c#


【解决方案1】:

这是我编写的应用程序中的一些代码,该应用程序动态地填充了 ContextMenuStrip,其中包含可以发送内容的所有其他监视器。它可能会给你一些关于如何解决这个问题的想法:

Private Sub ContextMenuStrip1_Opening(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles ContextMenuStrip1.Opening
    If Screen.AllScreens.Count > 1 Then
        SendToToolStripMenuItem.DropDownItems.Clear()
        SendToToolStripMenuItem.Visible = True
        Dim containingScreen As Screen = Screen.FromHandle(Me.Handle)
        For i As Integer = 0 To Screen.AllScreens.Count - 1
            Dim curScreen As Screen = Screen.AllScreens.ElementAt(i)
            If curScreen.DeviceName <> containingScreen.DeviceName Then
                Dim screenMenu As New ToolStripMenuItem(curScreen.DeviceName)
                screenMenu.Tag = i
                AddHandler screenMenu.Click, AddressOf ScreenMenu_Click
                SendToToolStripMenuItem.DropDownItems.Add(screenMenu)
            End If
        Next
    End If
End Sub

Private Sub ScreenMenu_Click(sender As Object, e As EventArgs)
    Dim screenMenu As ToolStripMenuItem = DirectCast(sender, ToolStripMenuItem)
    Dim index As Integer = screenMenu.Tag
    Me.SendToScreen(index)
End Sub

Public Sub SendToScreen(ByVal index As Integer)
    If index < 0 OrElse index > (Screen.AllScreens.Count - 1) Then
        index = 0
    End If

    Dim curScreen As Screen = Screen.FromHandle(Me.Handle)
    Dim destScreen As Screen = Screen.AllScreens.ElementAt(index)

    Dim ptF As New PointF((CDbl(Me.Location.X) - curScreen.Bounds.Left) / curScreen.Bounds.Width,
                          (CDbl(Me.Location.Y) - curScreen.Bounds.Top) / curScreen.Bounds.Height)
    Dim szF As New PointF(CDbl(Me.Width) / curScreen.Bounds.Width,
                          CDbl(Me.Height) / curScreen.Bounds.Height)

    Dim destPt As New Point(destScreen.Bounds.Left + ptF.X * destScreen.Bounds.Width,
                            destScreen.Bounds.Top + ptF.Y * destScreen.Bounds.Height)
    Dim destSz As New Size(destScreen.Bounds.Width * szF.X, destScreen.Bounds.Height * szF.Y)

    Me.Location = destPt
    Me.Size = destSz
End Sub

这是在我的系统上显示菜单时的样子,带有三台显示器(有时我总共连接了四台显示器,而且效果也很好):

【讨论】:

  • 非常感谢您的贡献,使用多台显示器会很好。我看到它不在 C# 中,我将尽快进行实现,因为我必须转换代码并验证一切顺利。
  • @idle-mind 我看到的另一个问题是,正如您所说,它是通过 ContextMenuStrip 完成的;我还需要调整它以使用 CefMenu cefsharp ...
  • 是的,对不起。我最喜欢的语言是 VB.Net。我也用 C# 做了很多工作,但是这个特定的项目是个人项目,所以我用 VB 编写了它。
  • 我从未使用过“CefMenu cefsharp”。我的代码中的关键点...Opening 事件在菜单显示之前触发。在那里,我枚举了监视器并为每个不包含我的表单的监视器添加了一个子菜单。屏幕的索引号存储在子菜单的.Tag 属性中,因此可以在Click 事件中使用,最终在SendToScreen() 中使用。
【解决方案2】:

第一个问题的解答:

替换这个:

if(myScreen == lsScreen[1])

用这个:

if(myScreen.DeviceName == lsScreen[1].DeviceName)

待改进/第二个问题。

【讨论】:

    猜你喜欢
    • 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
    相关资源
    最近更新 更多