Подтвердить что ты не робот

.NET/Windows Forms: запомнить размер и местоположение Windows

У меня есть приложение Windows Forms с обычным окном. Теперь, когда я закрываю приложение и перезапускаю его, я хочу, чтобы главное окно отображалось в том же месте на моем экране с тем же размером момента, когда он был закрыт.

Есть ли простой способ в Windows Forms запомнить местоположение экрана и размер окна (и, если возможно, состояние окна) или все это нужно сделать вручную?

4b9b3361

Ответ 1

Вам нужно сохранить расположение и размер окна в настройках вашего приложения. Здесь хорошая статья С# чтобы показать вам, как это сделать.

ИЗМЕНИТЬ

В настройках приложения вы можете сохранить практически все, что угодно. В столбце "Тип" сетки настроек вы можете перейти к любому типу .NET. WindowState находится в System.Windows.Forms и указан как FormWindowState. Также существует свойство FormStartPosition.

Ответ 2

Если вы добавите этот код в свой обработчик событий 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 намеренно ошибочно, поэтому во время первого запуска приложение будет использовать местоположение по умолчанию.

Ответ 4

Я попробовал несколько разных методов; это то, что в конечном итоге работает для меня. (В этом случае - при первом запуске - значения по умолчанию еще не сохранены, поэтому форма будет использовать значения, установленные в конструкторе)

  • Добавьте настройки в проект (вручную - не полагайтесь на визуальную студию): Properties.Settings

  • Добавьте следующий код в форму:

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

Ответ 5

Matt - чтобы сохранить WindowState в качестве пользовательского параметра в диалоговом окне "Настройки" в раскрывающемся списке "Тип", прокрутите страницу вниз и выберите "Обзор".

В диалоговом окне "Выбрать тип" разверните System.Windows.Forms и вы можете выбрать "FormWindowState" в качестве типа.

(извините, я не вижу кнопку, которая позволяет мне прокомментировать комментарий...)

Ответ 6

Если у вас более одной формы, вы можете использовать что-то вроде этого...

Добавить эту часть в любую форму 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);

Сохранить расположение и размер формы в 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;
}

Ответ 7

Вам нужно вручную сохранить информацию где-нибудь. Я бы предложил сделать это как настройки приложения, сохранив их в изолированном хранилище конкретных пользователей.

Как только вы загрузите, прочитайте настройки, затем измените размер/переместите свою форму.

Ответ 8

Если вы используете сказочную библиотеку с открытым исходным кодом - Jot, вы можете забыть о утомительной установке. файлов и просто выполните следующее:

public MainWindow()
{
    InitializeComponent();

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

Там также есть пакет Nuget, и вы можете сконфигурировать почти все о том, как/когда/где хранятся данные.

Отказ от ответственности: я автор, но библиотека полностью открытая (под лицензией MIT).

Ответ 9

Мой ответ адаптирован из ChrisF ♦ answer, но я исправил одно, что мне не понравилось, - если окно сворачивается во время закрытия, он будет сведен к минимуму при следующем запуске.

Мой код правильно обрабатывает этот случай, помня, было ли максимальное или минимальное окно во время его минимизации и соответствующим образом задано постоянное состояние.

К сожалению, 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;
        }
    }

Ответ 10

Вы также можете сохранить его в своем (скажем, скажем) файле 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>

Ответ 11

Я использовал этот метод до сих пор, и он работал отлично. Вам не нужно возиться с настройками приложения. Вместо этого он использует сериализацию для записи файла настроек в ваш рабочий каталог. Я использую JSON, но вы можете использовать собственную .NET сериализацию XML или любую другую сериализацию по этому вопросу.

Поместите эти статические методы в общий класс расширений. Бонусные баллы, если у вас есть общий проект расширений, на который вы ссылаетесь в нескольких проектах:

const string WINDOW_STATE_FILE = "windowstate.json";

public static void SaveWindowState(Form form)
{
    var state = new WindowStateInfo
    {
        WindowLocation = form.Location,
        WindowState = form.WindowState
    };

    File.WriteAllText(WINDOW_STATE_FILE, JsonConvert.SerializeObject(state));
}

public static void LoadWindowState(Form form)
{
    if (!File.Exists(WINDOW_STATE_FILE)) return;

    var state = JsonConvert.DeserializeObject<WindowStateInfo>(File.ReadAllText(WINDOW_STATE_FILE));

    if (state.WindowState.HasValue) form.WindowState = state.WindowState.Value;
    if (state.WindowLocation.HasValue) form.Location = state.WindowLocation.Value;
}

public class WindowStateInfo
{
    public FormWindowState? WindowState { get; set; }

    public Point? WindowLocation { get; set; }
}

Вам нужно написать этот код только один раз и никогда больше не связываться с ним. Теперь самое интересное: поместите приведенный ниже код в события Load и FormClosing, например, так:

private void Form1_Load(object sender, EventArgs e)
{
    WinFormsGeneralExtensions.LoadWindowState(this);
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    WinFormsGeneralExtensions.SaveWindowState(this);
}

Это все, что тебе нужно сделать. Единственная настройка - получить эти расширения в общий класс. После этого просто добавьте две строки кода в код формы, и все готово.

Этот код будет действительно работать, только если ваше приложение WinForm имеет одну форму. Если в нем есть несколько форм, которые вы хотите запомнить, вам нужно проявить творческий подход и сделать что-то вроде этого:

public static void SaveWindowState(Form form)
{
    var state = new WindowStateInfo
    {
        WindowLocation = form.Location,
        WindowState = form.WindowState
    };

    File.WriteAllText($"{form.Name} {WINDOW_STATE_FILE}", JsonConvert.SerializeObject(state));
}

Я только сохраняю местоположение и состояние, но вы можете изменить это, чтобы запомнить высоту и ширину формы или что-то еще. Просто внесите изменение один раз, и оно будет работать для любого приложения, которое его вызывает.