2008-09-18 8 views
10

En una aplicación WinForms 2.0 C#, ¿cuál es el método típico utilizado para guardar y restaurar la posición y el tamaño del formulario en una aplicación?Guardar y restaurar la posición y el tamaño del formulario

Relacionado, ¿es posible agregar nuevas configuraciones de la aplicación del usuario en AT RUNTIME? Veo totalmente cómo agregar configuraciones en el momento del diseño, eso no es un problema. Pero, ¿y si quiero crear uno en tiempo de ejecución?

Más detalles:

mi solicitud es una conversión de una aplicación existente de Visual FoxPro. He estado tratando de leer todo lo que puedo sobre la configuración de la aplicación, la configuración del usuario, etc. y me he dejado claro sobre la manera de hacer las cosas en .Net, pero todavía hay varias cosas en las que estoy confundido.

En la aplicación Fox, la configuración guardada se almacena en el registro. Mis formularios tienen una subclase y tengo un código de clase base que guarda automáticamente la posición y el tamaño del formulario en el registro con la clave del nombre del formulario. Cada vez que creo un formulario nuevo, no tengo que hacer nada especial para obtener este comportamiento; está integrado en la clase base. Mis formularios .Net también tienen una subclase, esa parte funciona bien.

En .Net, tengo la impresión de que se supone que debo usar la configuración de ámbito del usuario para cosas como las preferencias del usuario. El tamaño y la ubicación de un formulario definitivamente parecen preferencias del usuario. Pero no veo ninguna forma de agregar automáticamente estas configuraciones al proyecto. En otras palabras, cada vez que agrego un formulario nuevo a mi proyecto (y son cientos de formularios), debo recordar agregar una configuración de aplicación de ámbito de usuario y asegurarme de darle el mismo nombre que el formulario, es decir, " FormMySpecialSizePosition "para mantener el tamaño y la posición. Prefiero no tener que recordar hacer eso. ¿Es esto solo una mala suerte? ¿O estoy ladrando completamente al árbol equivocado al tratar de usar la configuración de ámbito del Usuario? ¿Debo crear mi propio archivo XML para mantener la configuración, de modo que pueda hacer lo que quiera (es decir, agregar una nueva configuración en tiempo de ejecución)? ¿O algo mas?

Seguramente esto es muy común y alguien puede decir la forma "correcta" de hacerlo. ¡Gracias por adelantado!

+0

Puede que una pregunta que le hice hace un tiempo fuera útil. Tiene una solución parcialmente completa para una base de formulario que puede heredar para hacer que un formulario persista en sus límites y ubicación. Probablemente solo necesites hacer que almacene su configuración en un archivo xml o algo así. – Svish

Respuesta

0

Puede crear una clase de formulario base con funciones comunes, como recordar la posición y el tamaño, y heredar de esa clase base.

public class myForm : Form { 
protected override void OnLoad(){ 
    //load the settings and apply them 
    base.OnLoad(); 
} 

protected override void OnClose(){ 
    //save the settings 
    base.OnClose(); 
} 
} 
then for the other forms: 

public class frmMainScreen : myForm { 
// you get the settings for free ;) 
}

Bueno, algo por el estilo;)

+0

Código de trabajo real sería mucho más útil. ¡Voto abajo! –

0

estoy en el mismo barco que tú, en que tengo un número de formas (MDI hijos, en mi caso) que quiero preservar la posición y tamaño de para cada usuario. De mi investigación, la creación de configuraciones de aplicaciones en tiempo de ejecución no es compatible. (Consulte this blog entry) Sin embargo, no es necesario que pegue todo en el archivo de configuración principal. Puede agregar un archivo de configuración a su proyecto (explained here in the MSDN) y usarlo a través del objeto Properties.Settings. Esto no aliviará el dolor de tener que recordar crear nuevas configuraciones para cada formulario, pero al menos las mantendrá unidas y no saturará la configuración principal de la aplicación.

En cuanto a usar la clase base para recuperar la configuración ... No sé si puedes hacerlo allí. Lo que haría (y probablemente haré) es nombrar cada atributo, luego usar Me.GetType(). ToString() (estoy trabajando en VB) para componer los nombres de los atributos que deseo recuperar en el evento Load() de cada forma.

8
private void Form1_Load(object sender, EventArgs e) 
{ 
    // restore location and size of the form on the desktop 
    this.DesktopBounds = 
     new Rectangle(Properties.Settings.Default.Location, 
    Properties.Settings.Default.Size); 
    // restore form's window state 
    this.WindowState = (FormWindowState)Enum.Parse(
     typeof(FormWindowState), 
     Properties.Settings.Default.WindowState); 
} 

private void Form1_FormClosing(object sender, FormClosingEventArgs e) 
{ 
    System.Drawing.Rectangle bounds = this.WindowState != FormWindowState.Normal ? this.RestoreBounds : this.DesktopBounds; 
    Properties.Settings.Default.Location = bounds.Location; 
    Properties.Settings.Default.Size = bounds.Size; 
    Properties.Settings.Default.WindowState = 
     Enum.GetName(typeof(FormWindowState), this.WindowState); 
    // persist location ,size and window state of the form on the desktop 
    Properties.Settings.Default.Save(); 
} 
+0

Esta solución tiene un problema si cierra la ventana en un estado minimizado. – robsch

+0

Esta solución tampoco funciona si no está escribiendo una aplicación, p. si estás escribiendo un plugin Tampoco menciona cómo configurar o configurar Propiedades que no es obvio y requiere una búsqueda de documentación. –

0

acabo de transmitirlo a un archivo XML independiente - rápido y sucio y probablemente no lo que usted está después:

 Dim winRect As String() = util.ConfigFile.GetUserConfigInstance().GetValue("appWindow.rect").Split(",") 
     Dim winState As String = util.ConfigFile.GetUserConfigInstance().GetValue("appWindow.state") 
     ' 
     Me.WindowState = FormWindowState.Normal 
     ' 
     Me.Left = CType(winRect(0), Integer) 
     Me.Top = CType(winRect(1), Integer) 
     Me.Width = CType(winRect(2), Integer) 
     Me.Height = CType(winRect(3), Integer) 
     ' 
     If winState = "maximised" Then 
      Me.WindowState = FormWindowState.Maximized 
     End If 

y

 Dim winState As String = "normal" 
     If Me.WindowState = FormWindowState.Maximized Then 
      winState = "maximised" 
     ElseIf Me.WindowState = FormWindowState.Minimized Then 
      winState = "minimised" 
     End If 
     ' 
     If Me.WindowState = FormWindowState.Normal Then 
      ' 
      Dim winRect As String = CType(Me.Left, String) & "," & CType(Me.Top, String) & "," & CType(Me.Width, String) & "," & CType(Me.Height, String) 
      ' only save window rectangle if its not maximised/minimised 
      util.ConfigFile.GetUserConfigInstance().SetValue("appWindow.rect", winRect) 
     End If 
     ' 
     util.ConfigFile.GetUserConfigInstance().SetValue("appWindow.state", winState) 
0
+0

La mayoría de estos enlaces administra un conjunto de configuraciones, la ubicación y el tamaño de un formulario. Si tiene varios formularios, empeora y le gustaría mantenerlo simple en la clase base del formulario. Este artículo maneja múltiples formas: http://www.code-magazine.com/article.aspx?quickid=0607031 –

2

Tengo este código de alguna parte, pero por desgracia en el momento (hace mucho tiempo) no hizo un comentario acerca de dónde obtuvo.

Esto ahorra la información formulario para registro HKCU del usuario:

using System; 
using System.Windows.Forms; 
using Microsoft.Win32; 

/// <summary>Summary description for FormPlacement.</summary> 
public class PersistentForm : System.Windows.Forms.Form 
{ 
    private const string DIALOGKEY = "Dialogs"; 

    /// <summary></summary> 
    protected override void OnCreateControl() 
    { 
     LoadSettings(); 
     base.OnCreateControl(); 
    } 

    /// <summary></summary> 
    protected override void OnClosing(System.ComponentModel.CancelEventArgs e) 
    { 
     SaveSettings(); 
     base.OnClosing(e); 
    } 

    /// <summary>Saves the form's settings.</summary> 
    public void SaveSettings() 
    { 
     RegistryKey dialogKey = Application.UserAppDataRegistry.CreateSubKey(DIALOGKEY); 
     if (dialogKey != null) 
     { 
      RegistryKey formKey = dialogKey.CreateSubKey(this.GetType().ToString()); 
      if (formKey != null) 
      { 
       formKey.SetValue("Left", this.Left); 
       formKey.SetValue("Top", this.Top); 
       formKey.Close(); 
      } 
      dialogKey.Close(); 
     } 
    } 

    /// <summary></summary> 
    public void LoadSettings() 
    { 
     RegistryKey dialogKey = Application.UserAppDataRegistry.OpenSubKey(DIALOGKEY); 
     if (dialogKey != null) 
     { 
      RegistryKey formKey = dialogKey.OpenSubKey(this.GetType().ToString()); 
      if (formKey != null) 
      { 
       this.Left = (int)formKey.GetValue("Left"); 
       this.Top = (int)formKey.GetValue("Top"); 
       formKey.Close(); 
      } 
      dialogKey.Close(); 
     } 
    } 
} 
2

realidad, hay una falta real de una sola, "simplemente funciona" solución a este en cualquier lugar en Internet, así que aquí está mi propia creación:

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Drawing; 
using System.Windows.Forms; 
using Microsoft.Win32; 
using System.ComponentModel; 
using System.Security.Cryptography; 

namespace nedprod 
{ 
    abstract public class WindowSettings 
    { 
     private Form form; 

     public FormWindowState state; 
     public Point location; 
     public Size size; 

     public WindowSettings(Form _form) 
     { 
      this.form = _form; 
     } 
     internal class MD5Sum 
     { 
      static MD5CryptoServiceProvider engine = new MD5CryptoServiceProvider(); 
      private byte[] sum = engine.ComputeHash(BitConverter.GetBytes(0)); 
      public MD5Sum() { } 
      public MD5Sum(string s) 
      { 
       for (var i = 0; i < sum.Length; i++) 
        sum[i] = byte.Parse(s.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber); 
      } 
      public void Add(byte[] data) 
      { 
       byte[] temp = new byte[sum.Length + data.Length]; 
       var i=0; 
       for (; i < sum.Length; i++) 
        temp[i] = sum[i]; 
       for (; i < temp.Length; i++) 
        temp[i] = data[i - sum.Length]; 
       sum=engine.ComputeHash(temp); 
      } 
      public void Add(int data) 
      { 
       Add(BitConverter.GetBytes(data)); 
      } 
      public void Add(string data) 
      { 
       Add(Encoding.UTF8.GetBytes(data)); 
      } 
      public static bool operator ==(MD5Sum a, MD5Sum b) 
      { 
       if (a.sum == b.sum) return true; 
       if (a.sum.Length != b.sum.Length) return false; 
       for (var i = 0; i < a.sum.Length; i++) 
        if (a.sum[i] != b.sum[i]) return false; 
       return true; 
      } 
      public static bool operator !=(MD5Sum a, MD5Sum b) 
      { 
       return !(a == b); 
      } 
      public override bool Equals(object obj) 
      { 
       try 
       { 
        return (bool)(this == (MD5Sum)obj); 
       } 
       catch 
       { 
        return false; 
       } 
      } 
      public override int GetHashCode() 
      { 
       return ToString().GetHashCode(); 
      } 
      public override string ToString() 
      { 
       StringBuilder sb = new StringBuilder(); 
       for (var i = 0; i < sum.Length; i++) 
        sb.Append(sum[i].ToString("x2")); 
       return sb.ToString(); 
      } 
     } 
     private MD5Sum screenconfig() 
     { 
      MD5Sum md5=new MD5Sum(); 
      md5.Add(Screen.AllScreens.Length); // Hash the number of screens 
      for(var i=0; i<Screen.AllScreens.Length; i++) 
      { 
       md5.Add(Screen.AllScreens[i].Bounds.ToString()); // Hash the dimensions of this screen 
      } 
      return md5; 
     } 
     public void load() 
     { 
      using (RegistryKey r = Registry.CurrentUser.OpenSubKey(@"Software\" + CompanyId() + @"\" + AppId() + @"\Window State\" + form.Name)) 
      { 
       if (r != null) 
       { 
        try 
        { 
         string _location = (string)r.GetValue("location"), _size = (string)r.GetValue("size"); 
         state = (FormWindowState)r.GetValue("state"); 
         location = (Point)TypeDescriptor.GetConverter(typeof(Point)).ConvertFromInvariantString(_location); 
         size = (Size)TypeDescriptor.GetConverter(typeof(Size)).ConvertFromInvariantString(_size); 

         // Don't do anything if the screen config has since changed (otherwise windows vanish off the side) 
         if (screenconfig() == new MD5Sum((string) r.GetValue("screenconfig"))) 
         { 
          form.Location = location; 
          form.Size = size; 
          // Don't restore if miminised (it's unhelpful as the user misses the fact it's opened) 
          if (state != FormWindowState.Minimized) 
           form.WindowState = state; 
         } 
        } 
        catch (Exception) 
        { 
        } 
       } 
      } 
     } 
     public void save() 
     { 
      state = form.WindowState; 
      if (form.WindowState == FormWindowState.Normal) 
      { 
       size = form.Size; 
       location = form.Location; 
      } 
      else 
      { 
       size = form.RestoreBounds.Size; 
       location = form.RestoreBounds.Location; 
      } 
      using (RegistryKey r = Registry.CurrentUser.CreateSubKey(@"Software\" + CompanyId()[email protected]"\"+AppId() + @"\Window State\" + form.Name, RegistryKeyPermissionCheck.ReadWriteSubTree)) 
      { 
       r.SetValue("state", (int) state, RegistryValueKind.DWord); 
       r.SetValue("location", location.X.ToString() + "," + location.Y.ToString(), RegistryValueKind.String); 
       r.SetValue("size", size.Width.ToString()+","+size.Height.ToString(), RegistryValueKind.String); 
       r.SetValue("screenconfig", screenconfig().ToString(), RegistryValueKind.String); 
      } 
     } 
     abstract protected string CompanyId(); 
     abstract protected string AppId(); 
    } 
} 

Esta aplicación almacena la posición y el tamaño de un formulario en HKCU/Software/< CompanyID() >/< AppId() >/ventana Estado/< nombre del formulario >. No restaurará la configuración si la configuración del monitor cambia para evitar que las ventanas se restauren fuera de la pantalla.

Obviamente, esto no puede manejar varias instancias del mismo formulario. También deshabilité específicamente la restauración minimizada, pero esa es una solución fácil de la fuente.

Lo anterior está diseñado para ser soltado en su propio archivo .cs y nunca volver a tocar. Usted tiene que crear una instancia de una copia local del espacio de nombres como esto (en Program.cs o su archivo .cs principales plugin o donde sea):

namespace <your app/plugin namespace name> 
{ 
    public class WindowSettings : nedprod.WindowSettings 
    { 
     public WindowSettings(Form form) : base(form) { } 
     protected override string CompanyId() { return "<your company name>"; } 
     protected override string AppId() { return "<your app name>"; } 
    } 
    .... 

Ahora usted tiene una ejemplificación no abstracta en el espacio de nombres principal. Por lo tanto, para utilizar, añadir esto a las formas que desea guardar y restaurar:

private void IssuesForm_FormClosing(object sender, FormClosingEventArgs e) 
    { 
     new WindowSettings(this).save(); 
    } 

    private void IssuesForm_Load(object sender, EventArgs e) 
    { 
     new WindowSettings(this).load(); 
    } 

Obviamente se siente libre de personalizar a sus propios fines. No hay garantía expresa o implícita. Utilice bajo su propio riesgo: rechazo cualquier derecho de autor.

Niall

0

Aquí está el código que utilicé.

private void SaveWindowPosition() 
{ 
    Rectangle rect = (WindowState == FormWindowState.Normal) ? 
     new Rectangle(DesktopBounds.Left, DesktopBounds.Top, DesktopBounds.Width, DesktopBounds.Height) : 
     new Rectangle(RestoreBounds.Left, RestoreBounds.Top, RestoreBounds.Width, RestoreBounds.Height); 
    RegistrySettings.SetSetting("WindowPosition", String.Format("{0},{1},{2},{3},{4}", 
     (int)this.WindowState, 
     rect.Left, rect.Top, rect.Width, rect.Height)); 
} 

private void RestoreWindowPosition() 
{ 
    try 
    { 
     string s = RegistrySettings.GetSetting("WindowPosition", String.Empty) as string; 
     if (s != null) 
     { 
      List<int> settings = s.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries) 
            .Select(v => int.Parse(v)).ToList(); 
      if (settings.Count == 5) 
      { 
       this.SetBounds(
        settings[1], 
        settings[2], 
        settings[3], 
        settings[4]); 
       this.WindowState = (FormWindowState)settings[0]; 
      } 
     } 
    } 
    catch { /* Just leave current position if error */ } 
} 

También presenté este código en mi artículo Saving and Restoring a Form's Window Position.

Cuestiones relacionadas