Pergunta

Parece uma exigência padrão: próxima vez que os lançamentos de usuários do aplicativo, abrir a janela na mesma posição e estado em que estava antes. Aqui está minha lista de desejos:

  • Posição Janela mesma que era
    • A menos que a tela foi redimensionado e a posição de idade é agora fora da tela.
  • Divisores deve manter a sua posição
  • recipientes Tab deve manter a sua seleção
  • Alguns menus suspensos devem manter a sua seleção
  • estado Window (maximizar, minimizar, normal) é o mesmo que era.
    • Talvez você nunca deve iniciar minimizado, eu não decidi.

Vou acrescentar meus soluções atuais como uma resposta juntamente com as limitações.

Foi útil?

Solução

A minha outra opção é escrever mais código personalizado em torno das configurações do aplicativo e executá-lo em FormLoad e FormClosed. Isso não usar ligação de dados.

Desvantagens:

  • Mais código para escrever.
  • Muito complicadas. A fim de definir as propriedades em FormLoad é confuso. Por exemplo, você tem que ter certeza que você definir o tamanho da janela antes de definir a distância divisor.

Agora, esta é a minha solução preferida, mas parece muito trabalho. Para reduzir o trabalho, eu criei uma classe WindowSettings que serializa a localização da janela, tamanho, estado e quaisquer posições divisor para uma única configuração do aplicativo. Então eu posso apenas criar um ambiente desse tipo para cada formulário no meu aplicativo, senão numa estreita, e restaurar na carga.

o código fonte , incluindo os WindowSettings classe e algumas formas que o utilizam. Instruções sobre como adicionar a um projeto estão incluídos no arquivo WindowSettings.cs. A parte mais complicada foi descobrir como adicionar uma configuração de aplicativo com um tipo personalizado. Você escolhe Browse ... do tipo suspensa e digite manualmente o nome do namespace e classe. Tipos de seu projeto não aparecem na lista.

Update: Eu adicionei alguns métodos estáticos para simplificar o código clichê que você adicionar a cada formulário. Uma vez que você seguiu as instruções para adicionar a classe WindowSettings ao seu projeto e criar uma configuração de aplicativo, aqui está um exemplo do código que tem de ser adicionado a cada formulário cuja posição que deseja gravar e restaurar.

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

Outras dicas

O exemplo abaixo mostra como eu fazê-lo

  • SavePreferences é chamado quando fechar o formulário e salva o tamanho do formulário, e um sinalizador que indica se ele está maximizado (nesta versão eu não salvar se ele é minimizado - ele vai voltar-se restaurado ou maximizada próxima vez) .

  • loadPreferences é chamado de OnLoad.

  • Primeiro salvar o design-time WindowState e configurá-lo para Normal. Você só pode definir com sucesso o tamanho do formulário se é WindowState é Normal.

  • Em seguida restaurar o tamanho de suas configurações persistiram.

  • Agora certifique-se os ajustes de formulário na tela (chamada para FitToScreen). A resolução da tela pode ter mudado desde a última vez que executou o aplicativo.

  • Finalmente definir a volta WindowState para maximizado (se persistiu como tal), ou para o design-time valor salvo anteriormente.

Esta poderia, obviamente, ser adaptado a persistir a posição de início e se o formulário foi minimizada quando fechado - eu não precisava fazer isso. Outras configurações para controles em seu formulário tais como a posição divisor e recipiente guia são simples.

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
}

x

A solução mais simples eu encontrei é usar a vinculação de dados com as configurações do aplicativo. propriedades I se ligam a localização e ClientSize na janela, juntamente com a splitterDistance no divisor.

Desvantagens:

  • Se você fechar a janela enquanto minimizado, ele abre escondida na próxima vez. É realmente difícil para obter a janela traseira.
  • Se você fechar a janela enquanto maximizada, abre-se preenchendo toda a tela, mas não maximizada (questão menor).
  • O redimensionamento da janela usando o canto superior direito ou no canto inferior esquerdo é apenas feio. Eu acho que as duas propriedades de ligação de dados estão lutando entre si.

Se você gostaria de experimentar com o comportamento estranho, eu postei uma href="http://dl.getdropbox.com/u/194081/WindowSettings.zip" solução de amostra usando esta técnica.

Eu faço uma configuração para cada valor que pretende guardar, e utilize o código como este:

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

Tenha em mente que recompilação limpa o arquivo de configuração onde as configurações são armazenadas para testá-lo sem fazer alterações de código entre uma gravação e uma restauração.

Com base na resposta aceita por Don Kirkby ea classe WindowSettings ele escreveu, você poderia derivar uma CustomForm do modelo standard para reduzir a quantidade de código idêntico escrito para toda e qualquer forma, talvez assim:

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

Para usar isso, passe sua classe de configurações do aplicativo e definir nome no construtor:

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

Este usa reflexão para obter / definir as configurações anteriores de / para a classe definições. Pode não ser o ideal para colocar o Salvar chamada para a rotina form_closing, pode-se remover essa e salve o arquivo configurações sempre que as saídas de aplicativos principal.

Para usá-lo como uma forma regular, basta usar o construtor sem parâmetros.

Você pode usar as configurações do aplicativo para definir quais propriedades de controle serão persistiram, em caso Form_closed você tem que usar o método Save nas configurações do aplicativo para escrever estes para o disco:

Properties.Settings.Default.Save();

Aqui está um exemplo de alguns que eu me uso. Ele só leva em consideração o monitor principal, por isso pode ser melhor para lidar com isso de forma diferente, se usado em vários monitores.

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

Um hack você pode usar as configurações para armazenar essas informações. Tudo que você tem a fazer é ligar a propriedade desejada (ex. Form.Size e form.Location) para uma configuração específica e são salvos e atualizados automaticamente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top