none
設定(My.Settings)の動作 RRS feed

  • 質問

  • 少し前にVisual Basicフォーラムに間違えて書き込んでしまいましたので削除してこちらにアップしなおしましたm(__)m 

    Visual Basic.NET 2005 Express Editionを利用してます。

    IE等のWindowsアプリケーションで前回終了時のウィンドウのサイズや位置を記憶して次回起動時にそれらを元に起動するのにタイトルの機能を利用出来ると思い込んでました。 実際、何度か試したサイズ変更等は思った様に動作してくれました。

    ところが、たまたま作成しているアプリを最小化して元のサイズに戻した所、動作がおかしいです。タイトルバーと右側に並ぶボタン類だけの状態で表示されます。説明がうまく出来ませんが、終了時だけ保存されて最小化等の動作時には保存されなければこんな事にはならないと思うのですが、これは自分でコーディング等の手を加えるべきものなのかが分かりませんでした。

    単に「前回終了時の状態の復元」的な用途としてこの「設定(My.Settings)」という機能は適しているのでしょうか?まだまだこの機能自体を把握出来ておりませんがアドバイス頂ければ幸いです。

    2006年11月6日 9:35

すべての返信

  • えーと、ちょっと今手元に確認できる環境がないので記憶だけで書きます。
    ごめんなさい。

    説明から推測すると、現状サメの餌さんの作成されているプログラムでは、Resize関連のイベント内でMy.Settingsの更新を行われているのではないでしょうか。

    確かWindows Formは、最小化や最大化の操作でもResize関連のイベントが走るはずですので、このタイミングで無条件にMy.Settingsの更新を行ってしまうと、最小化した時にも最小化されたFormのサイズが記録されてしまいます。

    また、終了時に発生するイベントの中で無条件にMy.Settings更新を行うと、最小化状態でタスクバーから終了操作を行った場合にも最小化されたFormのサイズが記録されてしまいます。

    これを回避し、最小・最大でない場合にのみFormの位置・サイズを記録したいのであれば、WindowsStateをチェックして振り分けるのがセオリーだったと思います。

    2006年11月6日 11:41
  • さるべーじさん、ご回答ありがとうございます。

    ちょっとというか大分説明不足でした。僕の希望する事はご理解頂いたかと思いますが、その為に僕が行ったのはフォームのプロパティの一番上にある"ApplicationSettings"の中にある"PropertyBinding"から「アプリケーション設定にバインドする」項目として"ClientSize"項目と"Location"項目の2つを任意の名前をつけて指定しただけなのです。

    自分で該当するプロパティの値をセーブして、次回起動時に利用するのでしたらそのセーブするタイミングでご指摘の事を気をつけておけば問題解決出来るかと思いますが、今回のは自分ではどのタイミングでセーブしてどのタイミングで利用されているのかが分からない(自分が理解出来ていないだけ?)為に対処方法に悩んでます。

    この機能自体の呼び方もあまり分からないままタイトルの様に書いてみたのですが、この機能自体がそもそも僕の考えている用途には不向きなのかも分かっていなかったりします^^; そこで既に試された方、もしくは試して断念したとか修正をすれば使えるとかのアドバイスを頂けたらと思い書き込ませて頂きました。

    MDIのアプリを考えていまして個々の子フォームでそれぞれのプロパティを管理しても良いのですが、出来ればその辺りに手間を掛けずに実現出来ればとこの機能に目をつけた次第です。

    2006年11月7日 3:37
  • ソリュ-ションエクスプローラで全てのファイルを表示ボタンを押すと、
    MyProjectの下にSettings.settingsが出てその下にSettings.Desiner.vbが表示されます。
    そこの該当サイズ設定のプロパティが例えば以下のようになっているのを、
    If文を使って(0,0)の場合に保存しないようにしてください。

    Me("FormClientSize") = Value
         ↓
    If Value.Height <> 0 AndAlso Value.Width <> 0 Then Me("FormClientSize") = Value

    但しSettings.Desiner.vbは設定を増やすと元に戻ってしまいます。
    #もっといいことが思いついたらまた書き込みますね。

    2006年11月9日 8:54
  •  サメの餌 さんからの引用
    僕が行ったのはフォームのプロパティの一番上にある"ApplicationSettings"の中にある"PropertyBinding"から「アプリケーション設定にバインドする」項目として"ClientSize"項目と"Location"項目の2つを任意の名前をつけて指定しただけなのです。

    あ、ApplicationSettingsのお話でしたか。

     えムナウ さんからの引用
    Me("FormClientSize") = Value
         ↓
    If Value.Height <> 0 AndAlso Value.Width <> 0 Then Me("FormClientSize") = Value

    あーなるほどその手はアリですね。


    ApplicationSettingsで設定した項目は、該当するプロパティのOnPropertyChangedイベントにハンドルされます。ので、プロパティの値が変更されるたびにMySettingsの中に保持されることになります。
    で、user.configへの保存はApplication.Shutdownに紐づいたAutoSaveSettingsプロシージャが行いますので、アプリケーションの終了時のタイミングになります。

    で、ClientSize / Locationのどちらかひとつを設定するとそれなりの動作するんですが、両方設定すると、どういうわけか片方の値を設定する時にもう片方の値をFormに反映するという動作を取ります。

      ClientSizeが変化→ClientSizeのGetが走る→LocationのSetが走る
      Locationが変化→LocationのGetが走る→ClientSizeのSetが走る

    なぜこんなコンボになるのか、あまり納得できない部分ではあります。

    どうもApplicationSettingsはあまり実用的な機能のようには思えません。使い込んでいくほど、予想しない動作をしてくれるような気がします。
    また、今回の例で言えばClientSizeはあるがSizeはないなど、仕様としても?なところがあります。

     サメの餌 さんからの引用
    MDIのアプリを考えていまして個々の子フォームでそれぞれのプロパティを管理しても良いのですが、出来ればその辺りに手間を掛けずに実現出来ればとこの機能に目をつけた次第です。

    お気持ちはよくわかりますが、予想しにくい動作に対するデバッグコストまで考え併せると、ApplicationSettingsはあまり「手間いらず」のレベルまで洗練された機能ではないように思います。

    My.Settingsを自力でRead/Writeするコードを書いた方が動作タイミングを手元で制御できるので安全・確実です。またあらゆるプロパティ(プロパティ以外のデータも)に例外なく対応できるので、対象となるプロパティによって手法を変えなければならないというような不統一さもなくなります。
    私はいつもこちらの手法を使っていますよ。

    2006年11月9日 20:35
  • えムナウさん、さるべーじさん、ご回答ありがとうございます。

     さるべーじ さんからの引用

    両方設定すると、どういうわけか片方の値を設定する時にもう片方の値をFormに反映するという動作を取ります。

      ClientSizeが変化→ClientSizeのGetが走る→LocationのSetが走る
      Locationが変化→LocationのGetが走る→ClientSizeのSetが走る

    なぜこんなコンボになるのか、あまり納得できない部分ではあります。

    これってVB2005EE(他のエディションでも同様?)のバグなんですかね? 書き込み拝見してから以前のアドバイスも参考にしながら試しにWindowStateもバインドしてみる(3つバインドするとどうかなっと)と、最小化すると終了する以外手がなくなりましたヽ(;´Д`)ノ

     さるべーじ さんからの引用

    どうもApplicationSettingsはあまり実用的な機能のようには思えません。使い込んでいくほど、予想しない動作をしてくれるような気がします。

    「実用的な機能のようには思えません」という表現は本来の動作を確実にしてくれるなら実用的だけど、「予想しない動作」をするからって事ですよね?もし、バグ(って表現が正しいかは分かりませんが)ならMSが対処してくれれば「実用的な機能」になる可能性も有り?以前のバージョンには無かった機能だったと思いますので今後のバージョンアップなりでの改善に期待でしょうか?

     さるべーじ さんからの引用

    お気持ちはよくわかりますが、予想しにくい動作に対するデバッグコストまで考え併せると、ApplicationSettingsはあまり「手間いらず」のレベルまで洗練された機能ではないように思います。

    My.Settingsを自力でRead/Writeするコードを書いた方が動作タイミングを手元で制御できるので安全・確実です。またあらゆるプロパティ(プロパティ以外のデータも)に例外なく対応できるので、対象となるプロパティによって手法を変えなければならないというような不統一さもなくなります。

    デバッグコストと個々に自分でコードを書いた場合を天秤に掛けると現状の動作では確かに後者でしょうね^^; 現状仮にバグだとしてもMSのこれまでの対応としても素早い修正は期待出来ませんからね(T_T)

    えムナウさんのアドバイスを採用する事も検討しながら、今回はこの機能部分は保留で開発進めて最終的に仕上がった時点でどうするか決めたいと思います。えムナウさん、さるべーじさん、ありがとうございましたm(__)m

    2006年11月11日 1:36
  • ?????????????????????????????????????????????????????
    ???????????



        Private Sub Form1_ClientSizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.ClientSizeChanged
            Static restoredSize As Size = My.Settings.FormClientSize
            If Me.ClientSize.Height <> 0 AndAlso Me.WindowState = FormWindowState.Normal Then
                restoredSize = Me.ClientSize
            End If
            If Me.ClientSize.Height = 0 AndAlso Me.WindowState = FormWindowState.Normal Then
                If restoredSize.Height = 0 Then
                    restoredSize.Height = 1
                End If
                Me.ClientSize = restoredSize
            End If
        End Sub
     
    ???

        Private Sub WmWindowPosChanged(ByRef m As Message)
            Static restoredSize As Size  = My.Settings.FormClientSize 
            If Me.ClientSize.Height <> 0 AndAlso Me.WindowState = FormWindowState.Normal Then
                restoredSize = Me.ClientSize
            End If
            MyBase.WndProc(m)
            If Me.ClientSize.Height = 0 AndAlso Me.WindowState = FormWindowState.Normal Then 
                If restoredSize.Height = 0 Then
                    restoredSize.Height = 1
                End If 
                Me.ClientSize = restoredSize
            End If
        End Sub
     
        Protected Overrides Sub WndProc(ByRef m As Message)
            Const WM_WINDOWPOSCHANGED As Integer = &H47
            If m.Msg = WM_WINDOWPOSCHANGED Then
                WmWindowPosChanged(m)
                Return
            End If
            MyBase.WndProc(m)
        End Sub
    2006年11月11日 7:50
  • 編集したら文字化けした。

    前のほうの文:
    何とか回避はできたのですがこんなコーディングをするならさるぺーじさんの言うとおり自力でやったほうがいいんですかね。
    二通り考えてみました。

    プログラム中の文:
    または

    2006年11月11日 8:02