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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1873658/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 21:32:03  来源:igfitidea点击:

.NET / Windows Forms: remember windows size and location

c#.netwinformswindow

提问by clamp

I have a Windows Forms application with a normal window. Now when I close the application and restart it, I want that the main window appears at the same location on my screen with the same size of the moment when it was closed.

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

Is there an easy way in Windows Forms to remember the screen location and window size (and if possible the window state) or does everything have to be done by hand?

在 Windows 窗体中是否有一种简单的方法来记住屏幕位置和窗口大小(如果可能的话,还有窗口状态)还是所有的事情都必须手工完成?

采纳答案by Walter

You'll need to save the window location and size in your application settings. Here's a good C# articleto show you how.

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

EDIT

编辑

You can save pretty much anything you want in the application settings. In the Type column of the settings grid you can browse to any .NET type. WindowState is in System.Windows.Forms and is listed as FormWindowState. There's also a property for FormStartPosition.

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

回答by Ian

You'll have to manually save the information somewhere. I'd suggest doing so as application settings, storing them in user specific isolated storage.

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

Once you load up, read the settings then resize/move your form.

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

回答by JohnForDummies

Matt - to save the WindowState as a user setting, in the Settings Dialog, in the "Type" dropdown, scroll to the bottom and select "Browse".

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

In the "Select a Type" dialog, expand System.Windows.Forms and you can choose "FormWindowState" as the type.

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

(sorry, I don't see a button that allows me to comment on the comment...)

(抱歉,我没有看到允许我对评论发表评论的按钮...)

回答by ChrisF

If you add this code to your FormClosingevent handler:

如果将此代码添加到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();

It will save the current state.

它将保存当前状态。

Then add this code to your form's OnLoadhandler:

然后将此代码添加到表单的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;
}

It will restore the last state.

它将恢复最后的状态。

It even remembers which monitor in a multi monitor set up the application was maximised to.

它甚至可以记住应用程序最大化到多显示器设置中的哪个显示器。

回答by ChrisF

If you have more than 1 form you can use something like this...

如果您有 1 个以上的表格,您可以使用这样的东西...

Add this part all form load void

添加这部分所有形式负载无效

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);

Save form location and size to app.config xml

将表单位置和大小保存到 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);
}

Load form location and size from app.config xml

从 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;
}

回答by jing

Previous solutions didn't work for me. After playing a while I ended up with following code which:

以前的解决方案对我不起作用。玩了一段时间后,我最终得到了以下代码:

  • preserves maximised and normal state
  • replaces minimised state with default position
  • in case of screen size changes (detached monitor, remote connection,...) it will not get user into frustrating state with application open outside of screen.

    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();
    }
    
  • 保留最大化和正常状态
  • 用默认位置替换最小化状态
  • 如果屏幕尺寸发生变化(分离的显示器、远程连接等),它不会让用户在屏幕外打开应用程序时陷入令人沮丧的状态。

    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();
    }
    

user settings:

用户设置:

    <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>

Note: the WindowsPosition is intentionally wrong, so during first launch application will use default location.

注意:WindowsPosition 是故意错误的,所以在第一次启动应用程序时将使用默认位置。

回答by anakic

If you use the fabulous open source library - Jot, you can forget about the tedious .settings files and just do this:

如果您使用出色的开源库 - 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();
}

There's a Nuget package as well, and you can configure pretty much everything about how/when/where data is stored.

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

Disclaimer: I'm the author, but the library is completely open source (under MIT license).

免责声明:我是作者,但该库是完全开源的(在 MIT 许可下)。

回答by sashoalm

My answer is adapted from ChrisF?'s answer, but I've fixed one thing I didn't like - if the window is minimized at the time of closing, it would appear minimized on next start.

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

My code handles that case correctly by remembering whether the window was maximized or normal at the time of its minimization, and setting the persistent state accordingly.

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

Unfortunately, Winforms doesn't expose that information directly, so I needed to override WndProc and store it myself. See Check if currently minimized window was in maximized or normal state at the time of minimization

不幸的是,Winforms 不直接公开该信息,因此我需要覆盖 WndProc 并自己存储它。请参阅检查当前最小化的窗口在最小化时是否处于最大化或正常状态

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;
        }
    }

回答by darksider474

I tried a few different methods; this is what ended up working for me. (In this case - on first launch - the defaults haven't been persisted yet, so the form will use the values set in the designer)

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

  1. Add the settings to the project (manually - don't rely on visual studio): Properties.Settings

  2. Add the following code to your form:

    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();
    }
    
  1. 将设置添加到项目中(手动 - 不要依赖 Visual Studio): 属性.设置

  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();
    }
    

回答by Deniz

You could also save it in your (let's say) config.xml when you close the form:

您还可以在关闭表单时将其保存在(假设)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];
}

And the loading is on your:

并且加载在您的:

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);
}

The config.xml should contain the following:

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>