Windows フォームのサイズを ApplicationSettings にバインドできないのはなぜですか?

StackOverflow https://stackoverflow.com/questions/18585

質問

アップデート:コード付きで解決しました

動作しました。コードについては以下の回答を参照してください...

元の投稿

タンディが指摘したように、 彼の答え わたしの 最後の質問, を使用すると、Windows フォーム コントロールに関するほとんどすべてを ApplicationSettings に簡単にバインドできます。では、フォーム サイズでこれを行う方法は本当にないのでしょうか? このチュートリアル ウィンドウが最大化または最小化されている場合に、サイズの代わりに RestoreBounds を保存できるように、Size を明示的に処理する必要があると述べています。ただし、次のようなプロパティを使用できればよかったと思います。

public Size RestoreSize
{
    get
    {
        if (this.WindowState == FormWindowState.Normal)
        {
            return this.Size;
        }
        else
        {
            return this.RestoreBounds.Size;
        }
    }
    set
    {
        ...
    }
}

しかし、デザイナーでこれをバインドする方法がわかりません(特に、PropertyBinding リストに Size がありません)。

役に立ちましたか?

解決

私はついに、これを完全に解決する Form サブクラスを思いつきました。使用するには:

  1. Form ではなく RestorableForm から継承します。
  2. (ApplicationSettings) -> (PropertyBinding) で WindowRestoreState にバインディングを追加します。
  3. ウィンドウが閉じようとしているときに、Properties.Settings.Default.Save() を呼び出します。

セッション間でウィンドウの位置と状態が記憶されるようになりました。以下の他の投稿者からの提案に従って、ウィンドウ自体を復元するときにウィンドウが利用可能なディスプレイに適切にフィットするようにする関数 ConstrainToScreen を組み込みました。

コード

// Consider this code public domain. If you want, you can even tell
// your boss, attractive women, or the other guy in your cube that
// you wrote it. Enjoy!

using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;

namespace Utilities
{
    public class RestorableForm : Form, INotifyPropertyChanged
    {
        // We invoke this event when the binding needs to be updated.
        public event PropertyChangedEventHandler PropertyChanged;

        // This stores the last window position and state
        private WindowRestoreStateInfo windowRestoreState;

        // Now we define the property that we will bind to our settings.
        [Browsable(false)]        // Don't show it in the Properties list
        [SettingsBindable(true)]  // But do enable binding to settings
        public WindowRestoreStateInfo WindowRestoreState
        {
            get { return windowRestoreState; }
            set
            {
                windowRestoreState = value;
                if (PropertyChanged != null)
                {
                    // If anybody's listening, let them know the
                    // binding needs to be updated:
                    PropertyChanged(this,
                        new PropertyChangedEventArgs("WindowRestoreState"));
                }
            }
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            WindowRestoreState = new WindowRestoreStateInfo();
            WindowRestoreState.Bounds
                = WindowState == FormWindowState.Normal ?
                  Bounds : RestoreBounds;
            WindowRestoreState.WindowState = WindowState;

            base.OnClosing(e);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            if (WindowRestoreState != null)
            {
                Bounds = ConstrainToScreen(WindowRestoreState.Bounds);
                WindowState = WindowRestoreState.WindowState;
            }
        }

        // This helper class stores both position and state.
        // That way, we only have to set one binding.
        public class WindowRestoreStateInfo
        {
            Rectangle bounds;
            public Rectangle Bounds
            {
                get { return bounds; }
                set { bounds = value; }
            }

            FormWindowState windowState;
            public FormWindowState WindowState
            {
                get { return windowState; }
                set { windowState = value; }
            }
        }

        private Rectangle ConstrainToScreen(Rectangle bounds)
        {
            Screen screen = Screen.FromRectangle(WindowRestoreState.Bounds);
            Rectangle workingArea = screen.WorkingArea;

            int width = Math.Min(bounds.Width, workingArea.Width);
            int height = Math.Min(bounds.Height, workingArea.Height);

            // mmm....minimax
            int left = Math.Min(workingArea.Right - width,
                                Math.Max(bounds.Left, workingArea.Left));
            int top = Math.Min(workingArea.Bottom - height,
                                Math.Max(bounds.Top, workingArea.Top));

            return new Rectangle(left, top, width, height);
        }
    }
}

設定 バインディング リファレンス

他のヒント

Form.Size プロパティが設定バインディング UI で使用できない理由は、このプロパティがマークされているためです。 DesignerSerializationVisibility.Hidden. 。これは、設計者がデータ バインディングを生成することはおろか、シリアル化する方法も知らないことを意味します。代わりに、 フォーム.クライアントサイズ プロパティはシリアル化されるものです。

束縛して賢くなろうとすると 位置 そして クライアントサイズ, 、別の問題が発生します。フォームの左端または上端からサイズを変更しようとすると、奇妙な動作が発生します。これは、相互に影響を与えるプロパティ セットのコンテキストで双方向のデータ バインディングが機能する方法に関係しているようです。両方 位置 そして クライアントサイズ 最終的には共通メソッドを呼び出します。 SetBoundsCore().

また、次のようなプロパティへのデータバインディング 位置 そして サイズ ただ効率的ではありません。ユーザーがフォームを移動またはサイズ変更するたびに、Windows は何百ものメッセージをフォームに送信し、フォームを閉じる前の最後の位置とサイズを保存したいだけなのに、データ バインディング ロジックに多くの処理を実行させます。

これは私がやっていることを非常に簡略化したものです。

private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
    Properties.Settings.Default.MyState = this.WindowState;
    if (this.WindowState == FormWindowState.Normal)
    {
       Properties.Settings.Default.MySize = this.Size;
       Properties.Settings.Default.MyLoc = this.Location;
    }
    else
    {
       Properties.Settings.Default.MySize = this.RestoreBounds.Size;
       Properties.Settings.Default.MyLoc = this.RestoreBounds.Location;
    }
    Properties.Settings.Default.Save();
}

private void MyForm_Load(object sender, EventArgs e)
{
    this.Size = Properties.Settings.Default.MySize;
    this.Location = Properties.Settings.Default.MyLoc;
    this.WindowState = Properties.Settings.Default.MyState;
} 

なぜこれが非常に簡略化されたバージョンなのでしょうか?なぜなら、これを適切に行うことは、 はるかにトリッキーな 見た目よりも:-)

さて、私はこれを簡単に試してみましたが、あなたは正しいですが、直接行う方法はありません 練る フォームのサイズを AppSettings に追加すると、独自の値を追加して、読み込み時にサイズを変更できます。

これが一般的な機能である場合は、Form をサブクラス化し、App.Config でフォームのサイズ設定を自動的に調べるようにすることをお勧めします。

(または、独自のファイルをロールすることもできます。XML ファイル「formname.settings.xml」などをクエリするために取得しますか?- 考えが口に出ていた!)..

これが私が持っていたものです(非常に大まかで、エラーチェックなどはありません)。

アプリ構成

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>
        <add key ="FormHeight" value="500" />
        <add key ="FormWidth" value="200"/>
    </appSettings>
</configuration>

フォームコード

    private void Form1_Load(object sender, EventArgs e)
    {
        string height = ConfigurationManager.AppSettings["FormHeight"];
        int h = int.Parse(height);
        string width = ConfigurationManager.AppSettings["FormWidth"];
        int w = int.Parse(width);
        this.Size = new Size(h, w);
    }

サイズ バインドが許可されていないのではないかと想像する理由の 1 つは、セッション間で画面が変わる可能性があるためです。

解像度が下がったときにサイズをロードし直すと、タイトル バーが画面の制限を超える可能性があります。

また、複数のモニターの設定にも注意する必要があります。アプリが次回実行されるときにモニターが使用できなくなる可能性があります。

私はロブ・クーパーの答えに同意します。しかし、マーティンは非常に良い指摘をしていると思います。ユーザーがアプリケーションを開いて、アプリが画面外に表示されることほど素晴らしいことはありません。

したがって、実際には、フォームのサイズを設定する前に、両方の答えを組み合わせて、現在の画面のサイズを念頭に置く必要があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top