2008-09-18 17 views
10

W aplikacji WinForms 2.0 C# jaka jest typowa metoda używana do zapisywania i przywracania pozycji formularza i rozmiaru w aplikacji?Zapisywanie i przywracanie pozycji formularza i rozmiaru

Powiązany, czy można dodać nowe ustawienia aplikacji o ROCZTACH? Całkowicie widzę, jak dodawać ustawienia w czasie projektowania, to nie jest problem. Ale co jeśli chcę je utworzyć w czasie wykonywania?

Więcej szczegółów:

Moja aplikacja jest przekształcenie istniejącej aplikacji Visual FoxPro. Starałem się czytać tyle, ile mogę na temat ustawień aplikacji, ustawień użytkownika itp. I jasno zrozumieć sposób działania w sieci .Net, ale wciąż jest kilka rzeczy, które są mi pomieszane.

W aplikacji Fox zapisane ustawienia są przechowywane w rejestrze. Moje formularze są z podklasą i mam kod klasy bazowej, który automatycznie zapisuje pozycję i rozmiar formularza w rejestrze pod kluczem nazwy formularza. Ilekroć tworzę nowy formularz, nie muszę robić nic specjalnego, aby uzyskać takie zachowanie; jest wbudowany w klasę podstawową. Moje formularze .Net również są podklasowane, ta część działa dobrze.

W .Net, mam wrażenie, że powinienem używać ustawień z zakresem użytkownika dla takich rzeczy jak preferencje użytkownika. Rozmiar i położenie formularza zdecydowanie wydają się być preferencją użytkownika. Ale nie widzę żadnego sposobu automatycznego dodania tych ustawień do projektu. Innymi słowy, za każdym razem, gdy dodaję nowy formularz do mojego projektu (i ich są 100-y formularzy), muszę pamiętać o DODANIU ustawienia aplikacji z zakresu użytkownika i nadać mu taką samą nazwę jak formularz, np. " FormMySpecialSizePosition ", aby utrzymać rozmiar i pozycję. Wolałbym nie pamiętać o tym. Czy to tylko ciężkie szczęście? Czy jestem całkowicie szczekając złe drzewo, próbując użyć ustawień z zasięgiem użytkownika? Czy muszę utworzyć własny plik XML do przechowywania ustawień, aby móc zrobić, co chcę (np. Dodać nowe ustawienie w czasie wykonywania)? Albo coś innego?

Z pewnością jest to bardzo powszechne i ktoś może powiedzieć "właściwy" sposób, aby to zrobić. Z góry dziękuję!

+0

Może się zdarzyć, że pytanie, które podałem przed chwilą, może być przydatne. Ma częściowo kompletne rozwiązanie dla bazy formularzy, którą można dziedziczyć, aby formularz utrzymywał granice i lokalizację. Najprawdopodobniej po prostu trzeba będzie zapisać ustawienia w pliku xml lub coś podobnego. – Svish

Odpowiedz

0

Można utworzyć klasę podstawową o wspólnej funkcjonalności, takiej jak zapamiętanie pozycji i rozmiaru oraz dziedziczenie z tej klasy bazowej.

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

No, coś w tym stylu;)

+0

Rzeczywisty kod roboczy byłby znacznie bardziej użyteczny. Wycofane! –

0

jestem w tej samej łodzi, jak ty, że mam wiele form (dzieci MDI, w moim przypadku), że chcę zachować pozycja i rozmiar dla każdego użytkownika. Z moich badań tworzenie ustawień aplikacji w środowisku wykonawczym nie jest obsługiwane. (patrz this blog entry) Jednak nie musisz wbijać wszystkiego do głównego pliku ustawień. Możesz dodać plik ustawień do swojego projektu (explained here in the MSDN) i użyć go poprzez obiekt Properties.Settings. Nie zmniejszy to bólu związanego z koniecznością zapamiętywania nowych ustaleń dla każdej formy, ale przynajmniej będzie je utrzymywał razem i nie zagracał głównych ustawień aplikacji.

Jeśli chodzi o używanie klasy bazowej do pobierania ustawień ... Nie wiem, czy możesz tam to zrobić. To, co chciałbym (i prawdopodobnie zrobię), to nazwać każdy atrybut, a następnie użyć Me.GetType(). ToString() (pracuję w VB), aby złożyć nazwy atrybutów, które chcę pobrać w zdarzeniu Load() każdej formy.

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

To rozwiązanie ma problem, jeśli zamkniesz okno w stanie minionym. – robsch

+0

To rozwiązanie również nie działa, jeśli nie piszesz aplikacji, np. jeśli piszesz wtyczkę. Nie wspomina również o tym, jak skonfigurować lub skonfigurować właściwości, które nie są oczywiste i wymagają przeszukania dokumentacji. –

0

Właśnie strumień go do osobnego pliku xml - szybkie i brudne, a prawdopodobnie nie co jesteś po:

 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 

i

 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

Większość tych łączy zarządza jednym zestawem ustawień, lokalizacją i rozmiarem jednego formularza. Jeśli masz wiele formularzy, jest gorzej i chciałbyś, aby było proste w klasie bazowej dla formularza. W tym artykule opisano wiele form: http://www.code-magazine.com/article.aspx?quickid=0607031 –

2

Mam ten kod gdzieś, ale niestety w tym czasie (dawno temu) nie popełniła komentarz o tym, gdzie mam go od.

Oszczędza info formularz do użytkownika rejestru HKCU:

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

Tu jest rzeczywiście prawdziwy brak jednego, „po prostu działa” rozwiązanie tego dowolnego miejsca w Internecie, więc oto moja własna kreacja:

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

Ta implementacja zapamiętuje pozycję i rozmiar formularza w HKCU/Software/< CompanyId() >/< AppID() >/Okno Stan/< nazwa formularza >. Nie przywróci ustawień, jeśli konfiguracja monitora zmieni się w taki sposób, aby zapobiec przywróceniu systemu Windows poza ekranem.

Oczywiście nie można obsłużyć wielu wystąpień tego samego formularza. Specjalnie zabroniłem także przywracania do minimum, ale to łatwa naprawa źródła.

Powyższe zostało zaprojektowane tak, aby upuścić go do własnego pliku .cs i nigdy więcej nie dotykać. Musisz instancję lokalną kopię namespace tak (w Program.cs lub swoje wtyczki plik główne .cs lub gdziekolwiek):

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

Teraz masz non-abstrakcyjne konkretyzacji w głównej przestrzeni nazw. Tak więc, w użyciu, dodać to do form, które mają być zapisane i przywrócone:

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

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

Oczywiście czuć się swobodnie dostosować do własnych celów. Gwarancja nie jest wyrażona ani dorozumiana. Używaj na własne ryzyko - Zrzekam się wszelkich praw autorskich.

Niall

0

Oto kod, którego użyłem.

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 */ } 
} 

Również przedstawiłem ten kod w moim artykule Saving and Restoring a Form's Window Position.

Powiązane problemy