12

WinForms 2.0 C# アプリケーションで、アプリケーション内のフォームの位置とサイズを保存および復元するために使用される一般的な方法は何ですか?

関連して、実行時に新しいユーザー スコープのアプリケーション設定を追加することは可能ですか? 設計時に設定を追加する方法は完全に理解していますが、それは問題ではありません。しかし、実行時に作成したい場合はどうすればよいでしょうか?

詳細:

私のアプリケーションは、既存の Visual FoxPro アプリケーションの変換です。私は、アプリケーションの設定、ユーザーの設定などについてできる限り多くのことを読み、.Net のやり方を明確にしようと努めてきましたが、まだ混乱していることがいくつかあります。

Fox アプリでは、保存された設定はレジストリに保存されます。私のフォームはサブクラス化されており、フォームの位置とサイズをフォーム名をキーとするレジストリに自動的に保存する基本クラス コードがあります。新しいフォームを作成するときはいつでも、この動作を実現するために特別なことをする必要はありません。基本クラスに組み込まれています。私の .Net フォームもサブクラス化されており、その部分はうまく機能しています。

.Net では、ユーザー設定などにユーザー スコープ設定を使用することになっているという印象を受けます。フォームのサイズと位置は、間違いなくユーザーの好みのようです。しかし、これらの設定をプロジェクトに自動的に追加する方法がわかりません。つまり、プロジェクトに新しいフォームを追加するたびに (そしてそれらは何百ものフォームです)、ユーザー スコープのアプリケーション設定を追加することを忘れずに、フォームと同じ名前を付ける必要があります。 FormMySpecialSizePosition" を使用して、サイズと位置を保持します。私はむしろそれを覚えておく必要はありません。これはただの運の悪さですか?または、ユーザー スコープ設定を使用しようとして、間違ったツリーを完全に吠えていますか? 設定を保持するために独自の XML ファイルを作成する必要がありますか? または、他の何か?

確かにこれは非常に一般的であり、誰かがそれを行う「正しい」方法を教えてくれます。前もって感謝します!

4

8 に答える 8

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();
}
于 2008-10-25T11:43:39.207 に答える
3

実際には、これに対する単一の「うまく機能する」ソリューションがインターネット上のどこにも存在しないため、ここに私自身の作成があります。

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/<CompanyId()>/<AppId()>/Window State/<form name> に格納します。ウィンドウが画面外に復元されるのを防ぐために、モニターの構成が変更された場合、設定は復元されません。

明らかに、これは同じフォームの複数のインスタンスを処理できません。また、最小化された復元を具体的に無効にしましたが、それはソースの簡単な修正です。

上記は、独自の .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();
    }

もちろん、自分の目的に合わせて自由にカスタマイズしてください。保証は明示または暗示されません。ご自身の責任で使用してください - 私は著作権を放棄します。

ニール

于 2012-02-24T19:06:58.343 に答える
2

このコードはどこかから入手しましたが、残念ながら当時(ずっと前)はどこから入手したかについてコメントしていませんでした。

これにより、フォーム情報がユーザーの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();
        }
    }
}
于 2012-02-19T18:26:34.670 に答える
0

私はそれを別のファイルにストリーミングするだけ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)
于 2009-11-27T11:48:34.953 に答える
0

チェックアウトするための関連リンクを次に示します。

アプリケーション設定機能を使用してフォームのサイズと場所を保存する

アプリケーション設定の使用方法の良い例

永続的なアプリケーション設定の秘密を探る

于 2010-12-17T21:36:51.837 に答える
0

私は、各ユーザーの位置とサイズを保持したい多数のフォーム (私の場合は MDI の子) を持っているという点で、あなたと同じボートに乗っています。私の調査によると、実行時にアプリケーション設定を作成することはサポートされていません。(このブログエントリを参照してください) ただし、すべてをメイン設定ファイルに貼り付ける必要はありません。プロジェクトに設定ファイルを追加し ( MSDN で説明されています)、Properties.Settings オブジェクトを介して使用できます。これは、フォームごとに新しい設定を作成することを覚えておく必要があるという苦痛を和らげるわけではありませんが、少なくともそれらをまとめて保持し、メインのアプリケーション設定を混乱させることはありません.

基本クラスを使用して設定を取得する限り...そこでできるかどうかはわかりません。私がすること (そしておそらくすること) は、各属性に名前を付けてから、Me.GetType().ToString() (私は VB で作業しています) を使用して、Load() イベントで取得する属性の名前を合成します。各フォームの。

于 2008-09-19T14:53:33.100 に答える
0

これが私が使用したコードです。

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

このコードは、私の記事「フォームのウィンドウ位置の保存と復元」でも紹介しました。

于 2014-09-21T20:57:15.507 に答える
0

位置とサイズを記憶し、その基本クラスから継承するなど、共通の機能を持つ基本フォーム クラスを作成できます。

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

まあ、そのようなもの;)

于 2008-09-18T14:45:43.963 に答える