C# 在双监视器设置中关闭和打开同一监视器上的窗体

C# 在双监视器设置中关闭和打开同一监视器上的窗体,c#,winforms,C#,Winforms,我一直在四处寻找,发现了以下两篇文章: 问题是,这些文章只是我的问题的一部分,但我不能像我所看到的那样使用它们(除非我将我的解决方案变得非常复杂)。虽然本文讨论的是在完全关闭应用程序后恢复表单,但这并不是我想要实现的目标 我所做的是在同一个正在运行的应用程序中关闭和打开同一个表单。当这种情况发生时,我希望它的确切位置、状态和大小与我关闭时的位置、状态和大小相同。这是直截了当的,因为我可以保存表单对象的位置、状态和大小,处理它并将旧值应用到我的新表单。这是可行的,但是如果我在监视器2上有一

我一直在四处寻找,发现了以下两篇文章:

问题是,这些文章只是我的问题的一部分,但我不能像我所看到的那样使用它们(除非我将我的解决方案变得非常复杂)。虽然本文讨论的是在完全关闭应用程序后恢复表单,但这并不是我想要实现的目标

我所做的是在同一个正在运行的应用程序中关闭和打开同一个表单。当这种情况发生时,我希望它的确切位置、状态和大小与我关闭时的位置、状态和大小相同。这是直截了当的,因为我可以保存表单对象的位置、状态和大小,处理它并将旧值应用到我的新表单。这是可行的,但是如果我在监视器2上有一个最大化窗口,并且关闭/打开函数运行,它会在监视器1上打开最大化窗体


在上面的情况下,有没有一种简单的方法可以在监视器2上保存,或者我必须跳进复杂的库吗?

如果我是你,我会认为你的问题是那些链接问题的简单扩展,唯一的改变是你的应用程序没有被关闭-只有窗口是(因此,您不需要将这些信息持久保存到磁盘,只需将其保存在内存中即可)

原因是,当应用程序运行时(例如,笔记本电脑用户拔下外部屏幕),用户可以(最终其中一人可能会)更改显示器配置(显示器数量、显示器位置等)。,因此,如果您不考虑这一点,您最终会将窗口定位在用户无法访问的屏幕外。

试试这个

(Form2是您要定位的表单。请根据需要进行修改。)

使用系统;
使用系统图;
使用System.Windows.Forms;
命名空间Windows窗体应用程序1
{
公共部分类表单2:表单
{
静态System.Drawing.Point _位置=新点();
静态系统.图纸.尺寸_尺寸;
静态窗体窗口状态_状态;
公共表格2()
{
初始化组件();
this.Load+=新的EventHandler(Form2_Load);
this.FormClosing+=新FormClosingEventHandler(Form2\u FormClosing);
}
void Form2\u加载(对象发送方、事件参数e)
{
//恢复窗体的位置。
//
//处理我们以前的屏幕位置不再有效的可能性
//当前显示环境(即多->单显示系统)。
//
点位置=_位置;
如果(位置==新点(0,0)| |!IsScreenLocationValid(位置))
{
if(null!=此.Parent)
this.StartPosition=FormStartPosition.CenterParent;
其他的
this.StartPosition=FormStartPosition.CenterScreen;
}
其他的
{
这个位置=位置;
//确保表单的大小不小于允许的最小值。
//
大小=_大小;
size.Width=System.Math.Max(size.Width,this.MinimumSize.Width);
size.Height=System.Math.Max(size.Height,this.MinimumSize.Height);
这个。大小=大小;
}
//仅当窗体未最小化时才恢复窗体的窗口状态。
//(如果我们将其还原为最小化,用户将看不到它)。
//
if(_state==FormWindowsState.Normal |||_state==FormWindowsState.Maximized)
{
this.WindowState=\u状态;
}
}
/// 
///确定给定屏幕位置对于当前显示系统是否有效。
/// 
///描述位置的点对象
///如果位置有效,则为True;否则为false
静态布尔值IsScreenLocationValid(点位置)
{
矩形screenBounds=System.Windows.Forms.Screen.GetBounds(位置);
返回screenBounds.Contains(位置);
}
void Form2\u FormClosing(对象发送方,FormClosingEventArgs e)
{
_state=this.WindowState;
如果(_state==formWindowsState.Normal)
{
_位置=此位置;
_大小=这个。大小;
}
其他的
{
_位置=this.RestoreBounds.location;
_大小=this.RestoreBounds.size;
}
}
}
}

按照Hans Passant在原始帖子评论中的说明,并正确设置值,解决了问题。我现在在Forms OnLoad事件中这样做:

if(使用给定的定位值)
{
位置=覆盖位置;
if(OverrideWindowState==FormWindowState.Normal)
大小=覆盖;
WindowState=覆盖WindowState;
UseGivenPositionValues=false;
}

首先是位置,然后是状态。正如Justin在回答中指出的那样,这不是一个完美的解决方案,因为用户可以更改其设置,然后如果用户更改其设置,表单可能会显示在屏幕外。但是在我的特定情况下,这不是一个问题。

我创建了一个扩展方法,无论您是关闭应用程序还是只有当前窗口。我在form_load事件中调用RestoreLastLocation,在form_closing事件中调用SaveLastLocation。这是旧代码,如果有点粗糙,我深表歉意

    public static void SaveLastLocation(this Form form, string UniqueName)
    {
        FormWindowState CurState = form.WindowState;
        if (CurState == FormWindowState.Minimized)
            CurState = FormWindowState.Normal;

        form.WindowState = FormWindowState.Normal;

        if (Properties.Settings.Default.WindowSettings == null)
            Properties.Settings.Default.WindowSettings = new System.Collections.Specialized.StringCollection();

        if(Properties.Settings.Default.WindowSettings.Count > 0)
            foreach (string S in Properties.Settings.Default.WindowSettings)
                if (S.Split('|').First().ToLower() == UniqueName.ToLower())
                {
                    Properties.Settings.Default.WindowSettings.Remove(S);
                    break;
                }

        Properties.Settings.Default.WindowSettings.Add(string.Format("{0}|{1}|{2}|{3}|{4}|{5}",
            UniqueName, form.Top.ToString(), form.Left.ToString(), form.Height.ToString(), form.Width.ToString(), form.WindowState.ToString()));

        Properties.Settings.Default.Save();
    }

    public static void RestoreLastLocation(this Form form, string UniqueName)
    {
        if (Properties.Settings.Default.WindowSettings != null && Properties.Settings.Default.WindowSettings.Count > 0)
            foreach (string S in Properties.Settings.Default.WindowSettings)
            {
                string[] Parts = S.Split('|');
                if (Parts[0].ToLower() == UniqueName.ToLower())
                {
                    form.Top = int.Parse(Parts[1]);
                    form.Left = int.Parse(Parts[2]);
                    form.Height = int.Parse(Parts[3]);
                    form.Width = int.Parse(Parts[4]);
                    form.WindowState = (FormWindowState)Enum.Parse(typeof(FormWindowState), Parts[5]);
                    break;
                }
            }
    }

据我所见,这两个示例都在窗体关闭时存储窗口位置,而不是应用程序。请注意分配属性的顺序。首先设置位置,然后设置窗口状态。反过来做会出错。@HansPassant你是对的。这只是按正确的顺序设置值的问题。谢谢y m
    public static void SaveLastLocation(this Form form, string UniqueName)
    {
        FormWindowState CurState = form.WindowState;
        if (CurState == FormWindowState.Minimized)
            CurState = FormWindowState.Normal;

        form.WindowState = FormWindowState.Normal;

        if (Properties.Settings.Default.WindowSettings == null)
            Properties.Settings.Default.WindowSettings = new System.Collections.Specialized.StringCollection();

        if(Properties.Settings.Default.WindowSettings.Count > 0)
            foreach (string S in Properties.Settings.Default.WindowSettings)
                if (S.Split('|').First().ToLower() == UniqueName.ToLower())
                {
                    Properties.Settings.Default.WindowSettings.Remove(S);
                    break;
                }

        Properties.Settings.Default.WindowSettings.Add(string.Format("{0}|{1}|{2}|{3}|{4}|{5}",
            UniqueName, form.Top.ToString(), form.Left.ToString(), form.Height.ToString(), form.Width.ToString(), form.WindowState.ToString()));

        Properties.Settings.Default.Save();
    }

    public static void RestoreLastLocation(this Form form, string UniqueName)
    {
        if (Properties.Settings.Default.WindowSettings != null && Properties.Settings.Default.WindowSettings.Count > 0)
            foreach (string S in Properties.Settings.Default.WindowSettings)
            {
                string[] Parts = S.Split('|');
                if (Parts[0].ToLower() == UniqueName.ToLower())
                {
                    form.Top = int.Parse(Parts[1]);
                    form.Left = int.Parse(Parts[2]);
                    form.Height = int.Parse(Parts[3]);
                    form.Width = int.Parse(Parts[4]);
                    form.WindowState = (FormWindowState)Enum.Parse(typeof(FormWindowState), Parts[5]);
                    break;
                }
            }
    }