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

Как записать положение окна в настройках приложения Windows Forms

Похоже на стандартное требование: в следующий раз, когда пользователь запустит приложение, откройте окно в том же положении и состоянии, что и раньше. Вот мой список пожеланий:

  • Положение окна так же, как и
    • Если размер экрана не изменился, а старое положение теперь выключено.
  • Сплиттеры должны сохранять свою позицию.
  • Контейнеры для вкладок должны сохранять свой выбор
  • Некоторые выпадающие списки должны сохранять свой выбор
  • Состояние окна (максимизация, минимизация, нормальное) - это то же самое, что и было.
    • Возможно, вы никогда не должны начинать свертываться, я не решил.

Я добавлю свои текущие решения в качестве ответа вместе с ограничениями.

4b9b3361

Ответ 1

Другой вариант - написать более настраиваемый код вокруг параметров приложения и выполнить его на formLoad и formClosed. Это не использует привязку данных.

Недостатки:

  • Больше кода для записи.
  • Очень неудобно. Заказ, который вы задали для свойств на formLoad, запутан. Например, вы должны убедиться, что вы установили размер окна, прежде чем устанавливать расстояние сплиттера.

Прямо сейчас, это мое предпочтительное решение, но это похоже на слишком много работы. Чтобы уменьшить работу, я создал класс WindowSettings, который сериализует расположение окна, размер, состояние и любые позиции разделителя для одного параметра приложения. Затем я могу просто создать настройку этого типа для каждой формы в своем приложении, сэкономить на закрытии и восстановить при загрузке.

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

Обновление: Я добавил несколько статических методов, чтобы упростить шаблонный код, который вы добавляете к каждой форме. После того, как вы выполнили инструкции по добавлению класса WindowSettings к вашему проекту и созданию параметра приложения, здесь приведен пример кода, который должен быть добавлен к каждой форме, положение которой вы хотите записать и восстановить.

    private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        Settings.Default.CustomWindowSettings = WindowSettings.Record(
            Settings.Default.CustomWindowSettings,
            this, 
            splitContainer1);
    }

    private void MyForm_Load(object sender, EventArgs e)
    {
        WindowSettings.Restore(
            Settings.Default.CustomWindowSettings, 
            this, 
            splitContainer1);
    }

Ответ 2

Пример ниже показывает, как я это делаю

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

  • LoadPreferences вызывается из OnLoad.

  • Сначала сохраните WindowSte Design-time и установите его в Normal. Вы можете только успешно установить размер формы, если WindowState имеет значение Normal.

  • Затем восстановите размер из ваших сохраненных настроек.

  • Теперь убедитесь, что форма соответствует вашему экрану (вызов FitToScreen). Разрешение экрана может измениться с момента последнего запуска приложения.

  • Наконец, установите WindowState на Maximized (если оно сохраняется как таковое) или на значение времени разработки, сохраненное ранее.

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

private void FitToScreen()
{
    if (this.Width > Screen.PrimaryScreen.WorkingArea.Width)
    {
        this.Width = Screen.PrimaryScreen.WorkingArea.Width;
    }
    if (this.Height > Screen.PrimaryScreen.WorkingArea.Height)
    {
        this.Height = Screen.PrimaryScreen.WorkingArea.Height;
    }
}   
private void LoadPreferences()
{
    // Called from Form.OnLoad

    // Remember the initial window state and set it to Normal before sizing the form
    FormWindowState initialWindowState = this.WindowState;
    this.WindowState = FormWindowState.Normal;
    this.Size = UserPreferencesManager.LoadSetting("_Size", this.Size);
    _currentFormSize = Size;
    // Fit to the current screen size in case the screen resolution
    // has changed since the size was last persisted.
    FitToScreen();
    bool isMaximized = UserPreferencesManager.LoadSetting("_Max", initialWindowState == FormWindowState.Maximized);
    WindowState = isMaximized ? FormWindowState.Maximized : FormWindowState.Normal;
}
private void SavePreferences()
{
    // Called from Form.OnClosed
    UserPreferencesManager.SaveSetting("_Size", _currentFormSize);
    UserPreferencesManager.SaveSetting("_Max", this.WindowState == FormWindowState.Maximized);
    ... save other settings
}

х

Ответ 3

Самое простое решение, которое я нашел, это использовать привязку данных к настройкам приложения. Я привязываю свойства location и clientSize к окну вместе с splitterDistance на разделителе.

Недостатки:

  • Если вы закроете окно при его минимизации, он откроется в следующий раз. Очень тяжело вернуть окно.
  • Если вы закрываете окно в то время как оно максимизировано, оно открывается, заполняя весь экран, но не максимизировавшись (незначительная проблема).
  • Изменение размера окна с помощью верхнего правого угла или нижнего левого угла просто уродливо. Я думаю, что два свойства привязки связаны друг с другом.

Если вы хотите поэкспериментировать со странным поведением, я разместил образец решения, используя эту технику.

Ответ 4

Я делаю настройку для каждого значения, которое хочу сохранить, и использую такой код:

private void MainForm_Load(object sender, EventArgs e) {
  RestoreState();
}

private void MainForm_FormClosing(object sender, FormClosingEventArgs e) {
  SaveState();
}

private void SaveState() {
  if (WindowState == FormWindowState.Normal) {
    Properties.Settings.Default.MainFormLocation = Location;
    Properties.Settings.Default.MainFormSize = Size;
  } else {
    Properties.Settings.Default.MainFormLocation = RestoreBounds.Location;
    Properties.Settings.Default.MainFormSize = RestoreBounds.Size;
  }
  Properties.Settings.Default.MainFormState = WindowState;
  Properties.Settings.Default.SplitterDistance = splitContainer1.SplitterDistance;
  Properties.Settings.Default.Save();
}

private void RestoreState() {
  if (Properties.Settings.Default.MainFormSize == new Size(0, 0)) {
    return; // state has never been saved
  }
  StartPosition = FormStartPosition.Manual;
  Location = Properties.Settings.Default.MainFormLocation;
  Size = Properties.Settings.Default.MainFormSize;
  // I don't like an app to be restored minimized, even if I closed it that way
  WindowState = Properties.Settings.Default.MainFormState == 
    FormWindowState.Minimized ? FormWindowState.Normal : Properties.Settings.Default.MainFormState;
  splitContainer1.SplitterDistance = Properties.Settings.Default.SplitterDistance;
}

Имейте в виду, что перекомпиляция стирает файл конфигурации, где хранятся настройки, поэтому проверьте его, не внося изменения кода между сохранением и восстановлением.

Ответ 5

Основываясь на принятом ответе Дона Киркби и класса WindowSettings, который он написал, вы можете получить CustomForm из стандартного, чтобы уменьшить количество идентичного кода, написанного для каждой формы, возможно, так:

using System;
using System.Configuration;
using System.Reflection;
using System.Windows.Forms;

namespace CustomForm
{
  public class MyCustomForm : Form
  {
    private ApplicationSettingsBase _appSettings = null;
    private string _settingName = "";

    public Form() : base() { }

    public Form(ApplicationSettingsBase settings, string settingName)
      : base()
    {
      _appSettings = settings;
      _settingName = settingName;

      this.Load += new EventHandler(Form_Load);
      this.FormClosing += new FormClosingEventHandler(Form_FormClosing);
    }

    private void Form_Load(object sender, EventArgs e)
    {
      if (_appSettings == null) return;

      PropertyInfo settingProperty = _appSettings.GetType().GetProperty(_settingName);
      if (settingProperty == null) return;

      WindowSettings previousSettings = settingProperty.GetValue(_appSettings, null) as WindowSettings;
      if (previousSettings == null) return;

      previousSettings.Restore(this);
    }

    private void Form_FormClosing(object sender, FormClosingEventArgs e)
    {
      if (_appSettings == null) return;

      PropertyInfo settingProperty = _appSettings.GetType().GetProperty(_settingName);
      if (settingProperty == null) return;

      WindowSettings previousSettings = settingProperty.GetValue(_appSettings, null) as WindowSettings;
      if (previousSettings == null)
        previousSettings = new WindowSettings();

      previousSettings.Record(this);

      settingProperty.SetValue(_appSettings, previousSettings, null);

      _appSettings.Save();
    }
  }
}

Чтобы использовать это, передайте свой класс параметров приложения и имя параметра в конструкторе:

CustomForm.MyCustomForm f = new CustomForm.MyCustomForm(Properties.Settings.Default, "formSettings");

Это использует Reflection для получения/установки предыдущих настроек из/в класс настроек. Не может быть оптимальным поставить вызов Save в процедуру Form_Closing, его можно удалить и сохранить файл настроек всякий раз, когда основное приложение завершает работу.

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

Ответ 6

Для взлома вы можете использовать Настройки для хранения этой информации. Все, что вам нужно сделать, это привязать желаемое свойство (например, form.Size и form.Location) к определенному параметру, и оно автоматически сохраняется и обновляется.

Ответ 7

Вы можете использовать параметры приложения, чтобы установить, какие свойства управления будут сохраняться, в событии Form_closed вам необходимо использовать метод сохранения в настройках приложения, чтобы записать их на диск:

Properties.Settings.Default.Save();

Ответ 8

Вот пример нескольких, которые я использую сам. Он учитывает только первичный монитор, поэтому лучше использовать его по-разному, если использовать его на нескольких мониторах.

Size size;
int x;
int y;
if (WindowState.Equals(FormWindowState.Normal))
{
    size = Size;
    if (Location.X + size.Width > Screen.PrimaryScreen.Bounds.Width)
        x = Screen.PrimaryScreen.Bounds.Width - size.Width;
    else
        x = Location.X;
    if (Location.Y + Size.Height > Screen.PrimaryScreen.Bounds.Height)
        y = Screen.PrimaryScreen.Bounds.Height - size.Height;
    else
        y = Location.Y;
}
else
{
size = RestoreBounds.Size;
x = (Screen.PrimaryScreen.Bounds.Width - size.Width)/2;
y = (Screen.PrimaryScreen.Bounds.Height - size.Height)/2;
}
Properties.Settings.Position.AsPoint = new Point(x, y); // Property setting is type of Point
Properties.Settings.Size.AsSize = size;                 // Property setting is type of Size
Properties.Settings.SplitterDistance.Value = splitContainer1.SplitterDistance; // Property setting is type of int
Properties.Settings.IsMaximized = WindowState == FormWindowState.Maximized;    // Property setting is type of bool
Properties.Settings.DropDownSelection = DropDown1.SelectedValue;
Properties.Settings.Save();