archivo - settings variables c#
Cómo registrar la posición de la ventana en la configuración de la aplicación Windows Forms (8)
Parece un requisito estándar: la próxima vez que el usuario inicie la aplicación, abra la ventana en la misma posición y el estado que tenía antes. Aquí está mi lista de deseos:
- Posición de ventana igual a como estaba
- A menos que la pantalla haya cambiado de tamaño y la posición anterior esté ahora fuera de la pantalla.
- Los divisores deben conservar su posición
- Los contenedores de pestañas deben conservar su selección
- Algunos menús desplegables deben conservar su selección
- El estado de la ventana (maximizar, minimizar, normal) es el mismo que era.
- Tal vez nunca deberías comenzar a minimizar, no lo he decidido.
Agregaré mis soluciones actuales como una respuesta junto con las limitaciones.
Aquí hay un ejemplo de algunos que uso yo mismo. Solo toma en consideración el monitor principal, por lo que podría ser mejor manejarlo de forma diferente si se usa en múltiples 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();
La solución más simple que he encontrado es usar el enlace de datos con la configuración de la aplicación. Ato las propiedades location y clientSize en la ventana junto con el splitterDistance en el splitter.
Inconvenientes:
- Si cierra la ventana mientras está minimizado, se abre oculto la próxima vez. Es realmente difícil recuperar la ventana.
- Si cierra la ventana mientras está maximizado, se abre llenando toda la pantalla, pero no maximizando (problema menor).
- Cambiar el tamaño de la ventana usando la esquina superior derecha o la esquina inferior izquierda es feo. Supongo que las dos propiedades de datos se están peleando.
Si desea experimentar con el comportamiento extraño, publiqué una solución de muestra con esta técnica.
Puede usar la configuración de la aplicación para establecer qué propiedades de control se conservarán, en el evento Form_closed debe usar el método save en la configuración de la aplicación para escribirlas en el disco:
Properties.Settings.Default.Save();
El ejemplo a continuación muestra cómo lo hago
Se llama a SavePreferences al cerrar el formulario y guarda el tamaño del formulario, y un indicador que indica si está maximizado (en esta versión no guardo si está minimizado: volverá a restaurarse o se maximizará la próxima vez).
LoadPreferences se llama desde OnLoad.
Primero guarde el WindowState en tiempo de diseño y configúrelo en Normal. Solo puede establecer correctamente el tamaño del formulario si WindowState es Normal.
A continuación, restaure el Tamaño desde su configuración persistente.
Ahora asegúrese de que el formulario se ajuste a su pantalla (llame a FitToScreen). La resolución de la pantalla puede haber cambiado desde la última vez que ejecutó la aplicación.
Finalmente vuelva a configurar WindowState en Maximized (si persiste como tal) o en el valor de tiempo de diseño guardado anteriormente.
Esto obviamente podría adaptarse para persistir en la posición inicial y si la forma se minimizó cuando se cerró, no tuve que hacer eso. Otras configuraciones para controles en su formulario como la posición del divisor y el contenedor de pestañas son sencillas.
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
Realizo una configuración para cada valor que quiero guardar, y uso un 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;
}
Tenga en cuenta que la recompilación borra el archivo de configuración donde se almacenan las configuraciones, así que pruébela sin hacer cambios de código entre un guardado y una restauración.
En función de la respuesta aceptada por Don Kirkby y la clase WindowSettings que escribió, puede derivar un CustomForm del estándar para reducir la cantidad de código idéntico escrito para todos y cada uno de los formularios, tal como este:
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 esto, pase la clase de configuración de la aplicación y el nombre de configuración en el constructor:
CustomForm.MyCustomForm f = new CustomForm.MyCustomForm(Properties.Settings.Default, "formSettings");
Esto usa Reflection para obtener / establecer la configuración anterior de / a la clase de configuración. Puede que no sea óptimo colocar la llamada Guardar en la rutina Form_Closing, se podría eliminar y guardar el archivo de configuración cada vez que se cierre la aplicación principal.
Para usarlo como una forma regular, simplemente use el constructor sin parámetros.
Un truco puede usar Configuraciones para almacenar esa información. Todo lo que tiene que hacer es vincular la propiedad deseada (por ejemplo, formulario.Tamaño y forma.Ubicación) a una configuración específica y se guardará y actualizará automáticamente.
Mi otra opción es escribir más código personalizado en la configuración de la aplicación y ejecutarlo en formLoad y formClosed. Esto no usa el enlace de datos.
Inconvenientes:
- Más código para escribir.
- Muy tímido. El orden en que configuras las propiedades en formLoad es confuso. Por ejemplo, debe asegurarse de haber configurado el tamaño de la ventana antes de establecer la distancia del divisor.
En este momento, esta es mi solución preferida, pero parece que es demasiado trabajo. Para reducir el trabajo, creé una clase WindowSettings que serializa la ubicación de la ventana, el tamaño, el estado y cualquier posición del divisor en una sola configuración de aplicación. Luego puedo crear una configuración de ese tipo para cada formulario en mi aplicación, guardar al cerrar y restaurar al cargar.
Publiqué el código fuente , incluida la clase WindowSettings y algunos formularios que la usan. Las instrucciones para agregarlo a un proyecto se incluyen en el archivo WindowSettings.cs. La parte más complicada fue descubrir cómo agregar una configuración de aplicación con un tipo personalizado. Elige Browse ... en el menú desplegable de tipo, y luego ingresa manualmente el espacio de nombre y el nombre de clase. Los tipos de su proyecto no aparecen en la lista.
Actualización: agregué algunos métodos estáticos para simplificar el código repetitivo que agregas a cada formulario. Una vez que haya seguido las instrucciones para agregar la clase WindowSettings a su proyecto y crear una configuración de aplicación, aquí hay un ejemplo del código que debe agregarse a cada formulario cuya posición desea registrar y 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);
}