24

これは標準的な要件のように思えます。次にユーザーがアプリケーションを起動するときは、以前と同じ位置と状態でウィンドウを開きます。ここに私のウィッシュリストがあります:

  • 窓の位置はそのまま
    • 画面のサイズが変更され、古い位置が画面から外れていない限り。
  • スプリッターはその位置を保持する必要があります
  • タブ コンテナーは選択を保持する必要があります
  • 一部のドロップダウンは選択を保持する必要があります
  • ウィンドウの状態 (最大化、最小化、通常) は以前と同じです。
    • たぶん、最小化を開始すべきではないかもしれませんが、私はまだ決めていません。

制限とともに、現在のソリューションを回答として追加します。

4

8 に答える 8

18

もう 1 つのオプションは、アプリケーション設定に関するカスタム コードをさらに記述し、それを formLoad と formClosed で実行することです。これはデータバインディングを使用しません。

欠点:

  • より多くのコードを記述します。
  • 非常に厄介です。formLoad でプロパティを設定する順序はわかりにくいです。たとえば、スプリッターの距離を設定する前に、ウィンドウ サイズを設定したことを確認する必要があります。

現時点では、これが私の好みの解決策ですが、手間がかかりすぎるようです。作業を軽減するために、ウィンドウの位置、サイズ、状態、およびスプリッターの位置を 1 つのアプリケーション設定にシリアル化する WindowSettings クラスを作成しました。次に、アプリケーションのフォームごとにそのタイプの設定を作成し、閉じるときに保存し、読み込み時に復元するだけです。

WindowSettings クラスとそれを使用するいくつかのフォームを含むソース コードを投稿しました。プロジェクトに追加する手順は、WindowSettings.cs ファイルに含まれています。最も難しい部分は、カスタム タイプのアプリケーション設定を追加する方法を理解することでした。タイプ ドロップダウンから [参照...] を選択し、名前空間とクラス名を手動で入力します。プロジェクトのタイプはリストに表示されません。

更新:各フォームに追加するボイラープレート コードを簡素化するために、いくつかの静的メソッドを追加しました。WindowSettings クラスをプロジェクトに追加し、アプリケーション設定を作成するための指示に従ったら、位置を記録して復元する各フォームに追加する必要があるコードの例を次に示します。

    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);
    }
于 2008-09-19T22:01:33.867 に答える
6

以下のサンプルは、私がそれを行う方法を示しています

  • SavePreferencesは、フォームを閉じるときに呼び出され、フォームのサイズと、最大化されているかどうかを示すフラグを保存します(このバージョンでは、最小化されている場合は保存しません。次回、復元または最大化されて復元されます)。

  • LoadPreferencesはOnLoadから呼び出されます。

  • まず、デザイン時のWindowStateを保存し、それをNormalに設定します。WindowStateがNormalの場合にのみ、フォームサイズを正常に設定できます。

  • 次に、永続化された設定からサイズを復元します。

  • 次に、フォームが画面に収まっていることを確認します(FitToScreenを呼び出します)。アプリケーションを最後に実行してから、画面の解像度が変更されている可能性があります。

  • 最後に、WindowStateをMaximized(そのまま保持されている場合)、または以前に保存されたデザイン時の値に戻します。

これは明らかに、開始位置を維持し、閉じたときにフォームが最小化されたかどうかを維持するように適合させることができます-私はそれを行う必要はありませんでした。スプリッターの位置やタブコンテナーなど、フォーム上のコントロールのその他の設定は簡単です。

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
}

バツ

于 2008-09-20T13:58:36.483 に答える
5

私が見つけた最も簡単な解決策は、アプリケーション設定でデータバインディングを使用することです。ウィンドウのlocationプロパティとclientSizeプロパティを、スプリッターのsplitterDistanceとともにバインドします。

欠点:

  • 最小化した状態でウィンドウを閉じると、次回は非表示になります。ウィンドウを元に戻すのは本当に難しいです。
  • 最大化した状態でウィンドウを閉じると、画面全体に表示されますが、最大化されません(マイナーな問題)。
  • 右上隅または左下隅を使用してウィンドウのサイズを変更するのは見苦しいです。2つのデータバインドされたプロパティが互いに戦っていると思います。

奇妙な振る舞いを実験したい場合は、この手法を使用したサンプルソリューションを投稿しました。

于 2008-09-19T21:54:27.067 に答える
5

保存する値ごとに設定を作成し、次のようなコードを使用します。

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

再コンパイルすると、設定が保存されている構成ファイルが消去されることに注意してください。そのため、保存と復元の間にコードを変更せずにテストしてください。

于 2008-09-20T00:44:18.467 に答える
3

Don Kirkby によって受け入れられた回答と彼が作成した WindowSettings クラスに基づいて、標準フォームから CustomForm を派生させて、すべてのフォームに記述される同一のコードの量を減らすことができます。たとえば、次のようになります。

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

これを使用するには、コンストラクターでアプリケーション設定クラスと設定名を渡します。

CustomForm.MyCustomForm f = new CustomForm.MyCustomForm(Properties.Settings.Default, "formSettings");

これは、リフレクションを使用して、設定クラスとの間で以前の設定を取得/設定します。Save 呼び出しを Form_Closing ルーチンに入れるのは最適ではない場合があります。これを削除して、メイン アプリが終了するたびに設定ファイルを保存することができます。

通常の形式として使用するには、パラメーターなしのコンストラクターを使用するだけです。

于 2011-04-07T07:37:08.340 に答える
2

設定を使用してその情報を保存できるハック。必要なプロパティ(form.Sizeやform.Locationなど)を特定の設定にバインドするだけで、自動的に保存および更新されます。

于 2008-09-19T21:57:23.563 に答える
2

アプリケーション設定を使用して、永続化するコントロール プロパティを設定できます。Form_closed イベントでは、アプリケーション設定の save メソッドを使用してこれらをディスクに書き込む必要があります。

Properties.Settings.Default.Save();
于 2008-09-19T22:02:40.900 に答える
2

これは、私が自分で使用するいくつかの例です。プライマリ モニターのみを考慮しているため、複数のモニターで使用する場合は別の方法で処理した方がよい場合があります。

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();
于 2008-09-19T22:04:05.280 に答える