Сохраните и Восстановите Положение и Размер Формы - PullRequest
10 голосов
/ 18 сентября 2008

В приложении WinForms 2.0 C #, какой типичный метод используется для сохранения и восстановления положения и размера формы в приложении?

Связано, возможно ли добавить новые настройки приложения в области пользователя при запуске? Я полностью вижу, как добавить настройки во время разработки, это не проблема. Но что, если я хочу создать его во время выполнения?

Подробнее:

Мое приложение - это преобразование существующего приложения Visual FoxPro. Я пытался прочитать как можно больше о настройках приложения, пользовательских настройках и т. Д., Чтобы понять, как это делать .Net, но есть еще несколько вещей, с которыми я запутался.

В приложении Fox сохраненные настройки хранятся в реестре. Мои формы разделены на подклассы, и у меня есть код базового класса, который автоматически сохраняет положение и размер формы в реестре, привязанном к имени формы. Всякий раз, когда я создаю новую форму, мне не нужно делать ничего особенного, чтобы получить такое поведение; это встроено в базовый класс. Мои формы .Net также подклассы, эта часть работает хорошо.

В .Net у меня сложилось впечатление, что я должен использовать параметры пользовательской области для таких вещей, как пользовательские настройки. Размер и расположение формы определенно кажутся предпочтением пользователя. Но я не вижу способа автоматически добавить эти настройки в проект. Другими словами, каждый раз, когда я добавляю новую форму в свой проект (а их сотни), я должен помнить ДОБАВИТЬ настройку приложения в пользовательской области и обязательно дать ей то же имя, что и форме, т.е. FormMySpecialSizePosition "для хранения размера и позиции. Я бы предпочел не вспоминать, чтобы сделать это. Это просто неудача? Или я полностью лаю не на том дереве, пытаясь использовать пользовательские настройки? Нужно ли мне создавать свой собственный XML-файл для хранения настроек, чтобы я мог делать все, что захочу (то есть добавить новый параметр во время выполнения)? Или что-то еще?

Конечно, это очень распространенное явление, и кто-то может сказать "правильный" способ сделать это. Заранее спасибо!

Ответы [ 8 ]

8 голосов
/ 25 октября 2008
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();
}
2 голосов
/ 24 февраля 2012

На самом деле в Интернете практически отсутствует единственное, «просто работающее» решение, так что вот мое собственное творение:

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()+@"\"+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();
    }
}

Эта реализация сохраняет положение и размер формы в HKCU / Software / / / Состояние окна / <имя формы>. Он не восстановит настройки, если конфигурация монитора изменится, чтобы предотвратить восстановление окон за пределами экрана.

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

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

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

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

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

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

Очевидно, не стесняйтесь настраивать под свои собственные цели. Никаких гарантий не выражено или не подразумевается. Используйте на свой страх и риск - я отказываюсь от любых авторских прав.

Найл

2 голосов
/ 19 февраля 2012

Я получил этот код откуда-то, но, к сожалению, в то время (давным-давно) не комментировал, откуда я его взял.

Сохраняет информацию о форме в реестре 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();
        }
    }
}
0 голосов
/ 22 сентября 2014

Вот код, который я использовал.

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

Я также представил этот код в своей статье Сохранение и восстановление позиции окна формы .

0 голосов
/ 27 ноября 2009

Я просто передаю его в отдельный XML файл - быстро и грязно и, вероятно, не то, что вы после:

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

и

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 голосов
/ 19 сентября 2008

Я в той же лодке, что и вы, потому что у меня есть несколько форм (в моем случае это дети MDI), которые я хочу сохранить для каждого пользователя. Из моего исследования, создание параметров приложения во время выполнения не поддерживается. (см. эту запись в блоге ) Тем не менее, вам не нужно вставлять все в основной файл настроек. Вы можете добавить файл настроек в ваш проект ( описан здесь в MSDN ) и использовать его через объект Properties.Settings. Это не избавит от боли, связанной с необходимостью не забывать создавать новые настройки для каждой формы, но, по крайней мере, будет держать их вместе и не загромождать основные настройки приложения.

Что касается использования базового класса для получения настроек ... Я не знаю, можете ли вы сделать это там. То, что я хотел бы (и, вероятно, буду) делать, это именовать каждый атрибут, а затем использовать Me.GetType (). ToString () (я работаю в VB) для объединения имен атрибутов, которые я хочу получить в событии Load () каждой формы.

0 голосов
/ 18 сентября 2008

Вы можете создать базовый класс формы с общими функциями, такими как запоминание позиции и размера и наследование от этого базового класса.

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

Ну как-то так;)

...