.NET / Windows窗体:记住窗口大小和位置

问题描述 投票:38回答:10

我有一个带有普通窗口的Windows窗体应用程序。现在,当我关闭应用程序并重新启动它时,我希望主窗口出现在屏幕上的相同位置,其大小与关闭时的大小相同。

在Windows窗体中是否有一种简单的方法可以记住屏幕位置和窗口大小(如果可能的话,窗口状态)或者是否必须手动完成所有操作?

c# .net winforms window
10个回答
32
投票

您需要在应用程序设置中保存窗口位置和大小。这是一个很好的C#article,向您展示如何。

编辑

您可以在应用程序设置中保存您想要的任何内容。在设置网格的“类型”列中,您可以浏览到任何.NET类型。 WindowState位于System.Windows.Forms中,并列为FormWindowState。 FormStartPosition还有一个属性。


0
投票

关闭表单时,您也可以将它保存在(比方说)config.xml中:

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
    XmlDocument docConfigPath = new XmlDocument();
    docConfigPath.Load(XML_Config_Path);

    WriteNode(new string[] { "config", "Size", "Top", Top.ToString() }, docConfigPath);
    WriteNode(new string[] { "config", "Size", "Left", Left.ToString() }, docConfigPath);
    WriteNode(new string[] { "config", "Size", "Height", Height.ToString() }, docConfigPath);
    WriteNode(new string[] { "config", "Size", "Width", Width.ToString() }, docConfigPath);

    docConfigPath.Save(XML_Config_Path);
}

public static XmlNode WriteNode(string[] sNode, XmlDocument docConfigPath)
{
    int cnt = sNode.Length;
    int iNode = 0;
    string sNodeNameLast = "/" + sNode[0];
    string sNodeName = "";
    XmlNode[] xN = new XmlNode[cnt];

    for (iNode = 1; iNode < cnt - 1; iNode++)
    {
        sNodeName = "/" + sNode[iNode];
        xN[iNode] = docConfigPath.SelectSingleNode(sNodeNameLast + sNodeName);
        if (xN[iNode] == null)
        {
            xN[iNode] = docConfigPath.CreateNode("element", sNode[iNode], "");
            xN[iNode].InnerText = "";
            docConfigPath.SelectSingleNode(sNodeNameLast).AppendChild(xN[iNode]);
        }
        sNodeNameLast += sNodeName;
    }

    if (sNode[cnt - 1] != "")
        xN[iNode - 1].InnerText = sNode[cnt - 1];

    return xN[cnt - 2];
}

加载到你的:

private void Form1_Load(object sender, EventArgs e)
{
    XmlDocument docConfigPath = new XmlDocument();
    docConfigPath.Load(XML_Config_Path);
    XmlNodeList nodeList = docConfigPath.SelectNodes("config/Size");

    Height = ReadNodeInnerTextAsNumber("config/Size/Height", docConfigPath);
    Width = ReadNodeInnerTextAsNumber("config/Size/Width", docConfigPath);
    Top = ReadNodeInnerTextAsNumber("config/Size/Top", docConfigPath);
    Left = ReadNodeInnerTextAsNumber("config/Size/Left", docConfigPath);
}

config.xml应包含以下内容:

<?xml version="1.0" encoding="utf-8"?>
<config>
  <Size>
    <Height>800</Height>
    <Width>1400</Width>
    <Top>100</Top>
    <Left>280</Left>
  </Size>
</config>

55
投票

如果将此代码添加到FormClosing事件处理程序:

if (WindowState == FormWindowState.Maximized)
{
    Properties.Settings.Default.Location = RestoreBounds.Location;
    Properties.Settings.Default.Size = RestoreBounds.Size;
    Properties.Settings.Default.Maximised = true;
    Properties.Settings.Default.Minimised = false;
}
else if (WindowState == FormWindowState.Normal)
{
    Properties.Settings.Default.Location = Location;
    Properties.Settings.Default.Size = Size;
    Properties.Settings.Default.Maximised = false;
    Properties.Settings.Default.Minimised = false;
}
else
{
    Properties.Settings.Default.Location = RestoreBounds.Location;
    Properties.Settings.Default.Size = RestoreBounds.Size;
    Properties.Settings.Default.Maximised = false;
    Properties.Settings.Default.Minimised = true;
}
Properties.Settings.Default.Save();

它将保存当前状态。

然后将此代码添加到表单的OnLoad处理程序中:

if (Properties.Settings.Default.Maximised)
{
    WindowState = FormWindowState.Maximized;
    Location = Properties.Settings.Default.Location;
    Size = Properties.Settings.Default.Size;
}
else if (Properties.Settings.Default.Minimised)
{
    WindowState = FormWindowState.Minimized;
    Location = Properties.Settings.Default.Location;
    Size = Properties.Settings.Default.Size;
}
else
{
    Location = Properties.Settings.Default.Location;
    Size = Properties.Settings.Default.Size;
}

它将恢复最后的状态。

它甚至还记得多监视器设置中的哪个监视器最大化了应用程序。


3
投票

以前的解决方案对我不起作用。玩了一会儿之后我最终得到了以下代码:

  • 保持最大化和正常状态
  • 用默认位置替换最小化状态
  • 如果屏幕尺寸发生变化(分离式监视器,远程连接......),在屏幕外打开应用程序时,用户将无法进入令人沮丧的状态。 private void MyForm_Load(object sender, EventArgs e) { if (Properties.Settings.Default.IsMaximized) WindowState = FormWindowState.Maximized; else if (Screen.AllScreens.Any(screen => screen.WorkingArea.IntersectsWith(Properties.Settings.Default.WindowPosition))) { StartPosition = FormStartPosition.Manual; DesktopBounds = Properties.Settings.Default.WindowPosition; WindowState = FormWindowState.Normal; } } private void MyForm_FormClosing(object sender, FormClosingEventArgs e) { Properties.Settings.Default.IsMaximized = WindowState == FormWindowState.Maximized; Properties.Settings.Default.WindowPosition = DesktopBounds; Properties.Settings.Default.Save(); }

用户设置:

    <userSettings>
    <WindowsFormsApplication2.Properties.Settings>
        <setting name="WindowPosition" serializeAs="String">
            <value>0, 0, -1, -1</value>
        </setting>
        <setting name="IsMaximized" serializeAs="String">
            <value>False</value>
        </setting>
    </WindowsFormsApplication2.Properties.Settings>
</userSettings>

注意:WindowsPosition是故意错误的,因此在首次启动时应用程序将使用默认位置。


3
投票

我尝试了几种不同的方法;这就是最终为我工作的东西。 (在这种情况下 - 首次启动时 - 默认值尚未保留,因此表单将使用设计器中设置的值)

  1. 将设置添加到项目中(手动 - 不要依赖visual studio):Properties.Settings
  2. 将以下代码添加到您的表单: private void Form1_Load(object sender, EventArgs e) { this.RestoreWindowPosition(); } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { this.SaveWindowPosition(); } private void RestoreWindowPosition() { if (Settings.Default.HasSetDefaults) { this.WindowState = Settings.Default.WindowState; this.Location = Settings.Default.Location; this.Size = Settings.Default.Size; } } private void SaveWindowPosition() { Settings.Default.WindowState = this.WindowState; if (this.WindowState == FormWindowState.Normal) { Settings.Default.Location = this.Location; Settings.Default.Size = this.Size; } else { Settings.Default.Location = this.RestoreBounds.Location; Settings.Default.Size = this.RestoreBounds.Size; } Settings.Default.HasSetDefaults = true; Settings.Default.Save(); }

2
投票

Matt - 要将WindowState保存为用户设置,请在“设置”对话框的“类型”下拉列表中,滚动到底部并选择“浏览”。

在“选择类型”对话框中,展开System.Windows.Forms,然后可以选择“FormWindowState”作为类型。

(对不起,我没有看到允许我评论评论的按钮......)


2
投票

如果你有超过1个表格,你可以使用这样的东西......

添加此部分所有表单加载无效

var AbbA = Program.LoadFormLocationAndSize(this);
            this.Location = new Point(AbbA[0], AbbA[1]);
            this.Size = new Size(AbbA[2], AbbA[3]);
            this.FormClosing += new FormClosingEventHandler(Program.SaveFormLocationAndSize);

将表单位置和大小保存到app.config xml

public static void SaveFormLocationAndSize(object sender, FormClosingEventArgs e)
{
    Form xForm = sender as Form;
    Configuration config = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);
    if (ConfigurationManager.AppSettings.AllKeys.Contains(xForm.Name))
        config.AppSettings.Settings[xForm.Name].Value = String.Format("{0};{1};{2};{3}", xForm.Location.X, xForm.Location.Y, xForm.Size.Width, xForm.Size.Height);
    else
        config.AppSettings.Settings.Add(xForm.Name, String.Format("{0};{1};{2};{3}", xForm.Location.X, xForm.Location.Y, xForm.Size.Width, xForm.Size.Height));
    config.Save(ConfigurationSaveMode.Full);
}

从app.config xml加载表单位置和大小

public static int[] LoadFormLocationAndSize(Form xForm)
{
    int[] LocationAndSize = new int[] { xForm.Location.X, xForm.Location.Y, xForm.Size.Width, xForm.Size.Height };
    //---//
    try
    {
        Configuration config = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);
        var AbbA = config.AppSettings.Settings[xForm.Name].Value.Split(';');
        //---//
        LocationAndSize[0] = Convert.ToInt32(AbbA.GetValue(0));
        LocationAndSize[1] = Convert.ToInt32(AbbA.GetValue(1));
        LocationAndSize[2] = Convert.ToInt32(AbbA.GetValue(2));
        LocationAndSize[3] = Convert.ToInt32(AbbA.GetValue(3));
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    //---//
    return LocationAndSize;
}

1
投票

您必须在某处手动保存信息。我建议将其作为应用程序设置,将它们存储在用户特定的独立存储中。

加载后,请阅读设置,然后调整/移动表单。


0
投票

如果你使用神话般的开源库 - Jot,你可以忘记繁琐的.settings文件,只需这样做:

public MainWindow()
{
    InitializeComponent();

    _stateTracker.Configure(this)
        .IdentifyAs("MyMainWindow")
        .AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
        .RegisterPersistTrigger(nameof(Closed))
        .Apply();
}

还有一个Nuget包,你几乎可以配置有关数据存储方式/时间/位置的所有内容。

免责声明:我是作者,但图书馆是完全开源的(在麻省理工学院许可下)。


0
投票

我的答案是改编自ChrisF♦'s answer,但我修复了一件我不喜欢的事情 - 如果窗口在关闭时被最小化,它将在下次开始时显示为最小化。

我的代码通过记住窗口在最小化时是最大化还是正常来正确处理该情况,并相应地设置持久状态。

不幸的是,Winforms没有直接暴露这些信息,所以我需要覆盖WndProc并自己存储它。见Check if currently minimized window was in maximized or normal state at the time of minimization

partial class Form1 : Form
{
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_SYSCOMMAND)
        {
            int wparam = m.WParam.ToInt32() & 0xfff0;

            if (wparam == SC_MAXIMIZE)
                LastWindowState = FormWindowState.Maximized;
            else if (wparam == SC_RESTORE)
                LastWindowState = FormWindowState.Normal;
        }

        base.WndProc(ref m);
    }

    private const int WM_SYSCOMMAND = 0x0112;
    private const int SC_MAXIMIZE = 0xf030;
    private const int SC_RESTORE = 0xf120;
    private FormWindowState LastWindowState;

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        if (WindowState == FormWindowState.Normal)
        {
            Properties.Settings.Default.WindowLocation = Location;
            Properties.Settings.Default.WindowSize = Size;
        }
        else
        {
            Properties.Settings.Default.WindowLocation = RestoreBounds.Location;
            Properties.Settings.Default.WindowSize = RestoreBounds.Size;
        }

        if (WindowState == FormWindowState.Minimized)
        {
            Properties.Settings.Default.WindowState = LastWindowState;
        }
        else
        {
            Properties.Settings.Default.WindowState = WindowState;
        }

        Properties.Settings.Default.Save();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        if (Properties.Settings.Default.WindowSize != new Size(0, 0))
        {
            Location = Properties.Settings.Default.WindowLocation;
            Size = Properties.Settings.Default.WindowSize;
            WindowState = Properties.Settings.Default.WindowState;
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.