DOBON.NET DOBON.NETプログラミング掲示板過去ログ

Properties.Settingsでのフォーム状態保存で、挙動不審

環境/言語:[XP]
分類:[.NET]

Windowsアプリケーションの位置やサイズを保存するには?[2.0のみ、C#、VB]
http://www.atmarkit.co.jp/fdotnet/dotnettips/438winsettings/winsettings.html


を参考に
PropertyBindingのLocationとClientSizeを保存設定にし、
Form_Closingに
Properties.Settings.Default.Save();
を追加しました。

一見すると正しく動いているようにみえます。Formの位置も大きさも復元します。

しかし、このフォーム、WindowStateを変化させると、挙動がおかしくなります。

たとえば、起動後にフォームを最小化しすぐもとに戻すと、フォームのサイズが超縮小状態になります。
フォームを最大化してすぐもとに戻すと、今度はフォームのサイズが勝手に巨大化します。

自分のどのプログラムでも、同じ現象になるのですが、原因がわかりません。

たぶんどっかのやり方が間違っているのかもしれませんが、どのHPを検索しても同じやり方がかいてあります。
もしかして、VisualStudioのバグ??


環境はMicrosoft Visual C# 2005 Express Editionを使用して、WindowsXP、.NET2.0を使用しております。
■No17479に返信(takoさんの記事)

こんにちは takoさん

私のところでも同じ動作になります。
Scope を User にすると御指摘の様になります。

これでは困りますね。
エツさん、こんにちは。

情報ありがとうございます。同じ現象がおきるのですね。

設定ファイルかレジストリあたりに保存するように自力でどうにかしたいと思います。せっかく便利そうな機能なのに残念です。
■No17483に返信(takoさんの記事)

> 設定ファイルかレジストリあたりに保存するように自力でどうにかしたいと思います。せっかく便利そうな機能なのに残念です。

Settings が使用できないのは残念ですから次のようなコードを書きました。
最大化、最小化から元の大きさに戻す時、一旦戻った後で再度フォームのLocation, Sizeを指定する。これで一応上手く動いています。
しかし、実験ですので、実際にフォームに色々なコントロールが配置された場合のレスポンスなどを検証することが必要です。

        private Rectangle fmrect;   //Normal時のFormの位置とサイズ
        private bool fone = false;  //最大化、最小化でtrue にセット
  

        private void Form1_Load(object sender, EventArgs e)
        {
            fmrect = new Rectangle(this.Location, this.Size);
        }

        private void Form1_ResizeEnd(object sender, EventArgs e)
        {
            fmrect = new Rectangle(this.Location, this.Size);
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Normal)
            {
                if (fone)   //最大化、最小化の次の元の大きさのとき1回だけ通過する
                {
                    Application.Idle += new EventHandler(FormSizeNormal);
                    fone = false;
                }
            }
            else
                fone = true;
        }

        //システムがアイドルになれば元の位置、サイズにフォームを変更する
        protected void FormSizeNormal(object sender, EventArgs e)
        {
            Application.Idle -= this.FormSizeNormal;
            this.Bounds = new Rectangle(fmrect.Location, fmrect.Size);
            fone = false;
        }


        //次回起動時のために今回終了時のフォームの位置、サイズをディスクに保存
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Properties.Settings.Default.Save();
        }
■No17498に返信(エツさんの記事)

失礼しました。
■No17498 はバグがあります。

もう少し検証してアップします。
■No17500に返信(エツさんの記事)
> ■No17498に返信(エツさんの記事)

多分これで大丈夫と思います。


        private Rectangle fmrect;   //Normal時のFormの位置とサイズ
        private bool fone = false;  //最大化、最小化でtrue にセット



        private void Form1_Resize(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Normal)
            {
                if (fone)   //最大化、最小化の次の元の大きさのとき1回だけ通過する
                {
                    Application.Idle += new EventHandler(FormSizeNormal);
                    fone = false;
                }
            }
            else
            {
                if (!fone)
                    fmrect = new Rectangle(this.RestoreBounds.Location, this.RestoreBounds.Size);
                fone = true;
            }
        }

        //システムがアイドルになれば元の位置、サイズにフォームを変更する
        protected void FormSizeNormal(object sender, EventArgs e)
        {
            fone = false;
            Application.Idle -= this.FormSizeNormal;
            this.Bounds = new Rectangle(fmrect.Location, fmrect.Size);
        }


        //次回起動時のために今回終了時のフォームの位置、サイズをディスクに保存
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Properties.Settings.Default.Save();
        }
エツさんありごとうございました。おかげさまでうまく動きました。

同じようなことをしようといろいろやっていたのですが、WindowStateChangedというイベントがありそうでなかったので、萎えておりました。

また機会がありましたらよろしくご指導お願いいたします。
解決済み!
と思ったら、ウインドウサイズが復元されないようです。
■No17503に返信(takoさんの記事)
> と思ったら、ウインドウサイズが復元されないようです。
>

上手くいったと思ったのですが。
ウインドウサイズが復元されないとは、どのような動作でしょうか?
■No17504に返信(エツさんの記事)
> ■No17503に返信(takoさんの記事)
> ウインドウサイズが復元されないとは、どのような動作でしょうか?

デバッグ動作でなくて出力されたexeファイル を直接クリックして、動作させた時に最大化、最小化の画面しか、出ない事ですか?

例えば私の環境ですと作成したプロジェクトホルダー内にbinホルダーがあり、
binホルダー内にDebugホルダーとReleaseホルダーがあります。
exe ファイルは両方にありますが、Releaseホルダーのexeファイルが正常に動作するファイルです。これはプロジェクトのプロパティのビルド項目で出力パスをReleaseホルダーに設定してあるからです。

次の手順で再度確認してください。
ソリューションのビルドをする。
プロジェクトのプロパティのビルド項目で出力設定してあるホルダーのexeファイルで動作させる。(私の場合はReleaseホルダーのexeファイル)

#明日から暫くやり取りできない環境になりますが、悪しからず。
いろいろいじったせいでした。すみません。

いじったというのは、べつの不都合のためで、ちょっと無理矢理ですけど、最小化したまま右ボタンから終了すると、次回起動から最小化を解除できずにハマルという現象です。

それで、起動時や終了時に、this.WindowState == FormWindowState.Normalをいれてみたのですが、うまくいかず、ウインドウの再現もできなくなったのでした。

やっと期待できるような動作結果を得る方法にたどりつきました。

ベースは教えていただいたコードで、さらに以下のように改良すると、最大化や最小化のまま終了しても、大丈夫になりました。


private void Form1_FormClosing( object sender, FormClosingEventArgs e )
{
if( this.WindowState != FormWindowState.Normal )
{
this.WindowState = FormWindowState.Normal;
this.Bounds = new Rectangle( fmrect.Location, fmrect.Size );
}
Properties.Settings.Default.Save();
}


実は、エツさんに書いていただいたプログラムも、まだ意味がよくわかっていないのですが、試行錯誤の力業で、むりやり発見しました。丸一日かかりました。とほほ・・・・

DOBON.NET | プログラミング道 | プログラミング掲示板