次の方法で共有


Visual Basic .NET での独自の動的プロパティの作成とプロパティ設定の保存

Steve Hoag
Visual Studio Team
Microsoft Corporation

February 2002
日本語版最終更新日 2002 年 5 月 30 日

概要: このペーパーでは、Microsoft® Visual Basic® .NET が公開しているもの以外の独自の動的プロパティを作成する方法と、動的プロパティを使ってアプリケーションのインスタンス間でユーザーによる構成が可能なプロパティを永続化する方法について説明します。

目次

はじめに
動的プロパティの動作
ユーザーによる構成が可能な動的プロパティの永続化
新しい動的プロパティの作成
結論

はじめに

Visual Basic .NET の動的プロパティを使用すると、レジストリ設定や .ini ファイルを使わずに、アプリケーションのインスタンス間で簡単にプロパティ設定を保存することができます。Visual Basic .NET はデフォルトで多数の動的プロパティを用意しており、プログラマはコードを追加することで、他のプロパティを簡単に動的プロパティにすることができます。

たとえば、Windows® フォームはデフォルトでは MaximizeBoxMinimizeBox、および ShowInTaskbar などの多数の動的プロパティを公開していますが、SizeLocation などの他の有用なプロパティは公開していません。

動的プロパティは構成ファイルに格納されます。設定を保存するためには、構成ファイルを編集する必要があります。エンド ユーザーに、アプリケーションを実行するたびに構成ファイルを変更するように求めるのは現実的ではありません。このため、フォームの最後の位置やカラー設定などのユーザー構成が可能なプロパティを保存する方法はないように思えるかもしれません。

しかし、アプリケーションにわずかな量のコードを追加するだけで、任意のプロパティを動的プロパティのように動作させ、ユーザーによる構成も可能にすることができます。この記事では、動的プロパティの設定方法、動的プロパティのユーザーによる構成を可能にする方法、そして新しい動的プロパティを作成する方法について説明します。

動的プロパティの動作

動的プロパティは、プロパティ値をアプリケーションの構成ファイル (Windows アプリケーションでは app.config、Web アプリケーションでは web.config) に格納します。[プロパティ] ウィンドウで動的プロパティが追加されると、構成ファイルの appSettings セクションにキーと値のペアが追加されます。さらに、InitializeComponent プロシージャに configurationAppSettings.GetValue への呼び出しが追加されます。戻り値は、プロパティの初期値の設定に使用されます。構成ファイルの値を編集すれば、InitializeComponent プロシージャのコードを変更せずに、プロパティの初期値を変更することができます。

たとえば、Windows フォームの TopMost プロパティは、フォームがつねに他のウィンドウの上に表示されるかどうかを決定します。通常、このプロパティはデザイン時に設定しますが、アプリケーションに柔軟性を持たせると便利なこともあります。TopMost プロパティを動的プロパティに設定すれば、アプリケーションを配置するまでこの決定を遅らせることができます。

動的プロパティの動作を理解するには

  1. DynamicProps という名前の新しい Windows アプリケーションを作成し、フォーム デザイナを選択します。

  2. [プロパティ] ウィンドウの (DynamicProperties) ノードを展開し、詳細 プロパティの横の省略記号ボタンをクリックして、[動的プロパティ] ダイアログ ボックスを開きます。

  3. [プロパティ] リストで TopMost プロパティを選択します。

    キー マップは既定では Form1.TopMost に設定されていることに注意してください。ここにはキーとして使用する任意の名前を入力することができますが、この例では既定値を使用します。

  4. ソリューション エクスプローラで app.config ファイルを選択し、開きます。

    <appSettings> セクションに <add key="Form1.TopMost" value="false" /> という行があるはずです。key はダイアログ ボックスで設定した既定のキー マップに対応しており、value は TopMost プロパティの既定値 (false) です。

  5. Form1 のコード エディタを開き、Windows フォーム デザイナで生成されたコード と記されている領域を展開します。InitializeComponent プロシージャには次の宣言があるはずです。

    Dim configurationAppSettings As _
       System.Configuration.AppSettingsReader = New _
       System.Configuration.AppSettingsReader()
    

    この宣言は、構成ファイルを解析する AppSettingsReader クラスを作成します。

    このプロシージャのさらに下の方には、次の行があります。

    Me.TopMost = CType(configurationAppSettings.GetValue("Form1.TopMost", _
       GetType(System.Boolean)), Boolean) 
    

    この行は、構成ファイルからキー Form1.TopMost の値を取り出し、構成ファイルへの格納に使用されている Text データ型から、TopMost プロパティに必要な Boolean 型に変換しています。

  6. アプリケーションを実行し、フォームが一番上に表示されないことを確認して、アプリケーションを閉じます。

  7. app.config ファイルを開き、Form1.TopMost キーの値を true に変更します。

  8. アプリケーションを再び実行します。

    今回は、フォームは一番上に表示されます。

    [プロパティ] ウィンドウで TopMost プロパティを見ると、このプロパティが true に変更されているのがわかります。これは、プロパティと構成ファイルの間に動的なリンクが確立されているためです。

次のセクションでは、TopMost プロパティのユーザーによる実行時の構成を可能にする方法を示します。

ユーザーによる構成が可能な動的プロパティの永続化

構成ファイルを編集して動的プロパティを変更できるのは便利ですが、プロパティのユーザーによる構成が可能で、ユーザーがアプリケーションから動的プロパティを変更できるようになっているとさらに便利です。また、アプリケーションに設定を保存させ、次のインスタンスでこれを復元させることもできます。このためには、まずプロパティを設定するためのユーザー インターフェイス要素を追加する必要があります。

ユーザーによる構成が可能な動的プロパティを永続化するには

  1. フォームに CheckBox コントロールを追加し、その Text プロパティを Stay on top に設定します。

  2. CheckBox1_CheckedChanged イベント ハンドラに次のコードを追加します。

    Private Sub CheckBox1_CheckedChanged(ByVal sender As System.Object, _
       ByVal e As System.EventArgs) Handles CheckBox1.CheckedChanged
          Me.TopMost = CheckBox1.Checked
    End Sub
    
  3. チェック ボックスの Checked プロパティを true に変更し、チェック ボックスの初期状態を TopMost プロパティの初期設定に合わせます (前のセクションで true に変更しています)。

  4. アプリケーションを実行します。

    チェック ボックスが選択されると、フォームは一番上に表示されます。これが選択されなければ、フォームは一番上に表示されません。

  5. チェック ボックスがオフになっていることを確認して、アプリケーションを閉じます。

  6. app.config ファイルを開き、TopMost プロパティの値が依然として true であることを確認します。

    何が起こっているのでしょうか? アプリケーションは初期化の際に構成ファイルを読み込むことができますが、値が変化したときに、それを自動的に構成ファイルに書き込むことはできません。このための独自のコードを追加する必要があります。

    このコードは、CheckedChanged イベント ハンドラに追加して、プロパティが変更されるたびに構成ファイルを更新することもできます。しかし、アプリケーションが閉じられる際に構成ファイルを更新するようにした方が効率的でしょう。

  7. Form1_Closing イベント ハンドラに次のコードを追加します。

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As _
       System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
       ' リフレクションを使用して、構成ファイルの位置を探す。 
       Dim Asm As System.Reflection.Assembly = _
          System.Reflection.Assembly.GetExecutingAssembly
       Dim strConfigLoc As String
       strConfigLoc = Asm.Location
    
       ' 構成ファイルはアプリケーションの bin ディレクトリに置かれているので、
       ' ファイル名を削除する必要がある。
       Dim strTemp As String
       strTemp = strConfigLoc
       strTemp = System.IO.Path.GetDirectoryName(strConfigLoc)
    
       ' 構成ファイルの FileInfo オブジェクトを宣言する。
       Dim FileInfo As System.IO.FileInfo = New _
    System.IO.FileInfo(strTemp & "\DynamicProps.exe.config")
    
       ' 構成ファイルを XML DOM に読み込む。
       Dim XmlDocument As New System.Xml.XmlDocument()
       XmlDocument.Load(FileInfo.FullName)
    
       ' 正しいノードを発見し、新しい値に変更する。
       Dim Node As System.Xml.XmlNode
       For Each Node In XmlDocument.Item("configuration").Item("appSettings")
          ' コメントはスキップする。
          If Node.Name = "add" Then
             If Node.Attributes.GetNamedItem("key").Value = _
                "Form1.TopMost" Then
                Node.Attributes.GetNamedItem("value").Value _
                   = CType(Me.TopMost, String)
             End If
          End If
       Next Node
    
       ' 変更された構成ファイルを保存する。
       XmlDocument.Save(FileInfo.FullName)
    End Sub
    
  8. アプリケーションを再び実行し、チェック ボックスをオフにして、アプリケーションを閉じます。

  9. bin ディレクトリの中の appname.exe.config ファイルを開きます。Form1.TopMost の値は false になっているはずです。

    アプリケーションを再び実行すると、フォームは一番上に表示されなくなります。

    チェック ボックスが選択されたままになっているのはなぜでしょうか? フォームの動作をテストすると、一番上には表示されないので、プロパティ設定が有効になっているのは確かです。問題は、チェック ボックスの Checked プロパティとの同期がとれていないことにあります。

  10. Sub_New プロシージャの、InitializeCompoment の呼び出しの直後に次のコードを追加して、Checked プロパティの同期をとります。

    CheckBox1.Checked = Me.TopMost
    

    これで、アプリケーションを実行すると、チェック ボックスの状態は TopMost の動作を正確に反映するようになります。しかし、問題はまだ 1 つ残っています。チェック ボックスを選択し、アプリケーションを閉じて再起動すると、チェック ボックスはオフになっています。これは、実際には 2 つの構成ファイルが存在するためです。ソリューション エクスプローラに表示される app.config ファイルと、bin ディレクトリの中の appname.exe.config ファイルです。コードを慎重に眺めると、値は DynamicProps.exe.config ファイルに保存されていることがわかります。このファイルは、ソリューション エクスプローラ ツールバーの [すべてのファイルを表示] をクリックすると表示されます。

    プロジェクトがビルドされるたびに、app.config ファイルの内容が DynamicProps.exe.config ファイルにコピーされ、変更点が上書きされます。アプリケーションを配置すると、DynamicProps.exe.config ファイルはアプリケーションとともにアプリケーション ディレクトリに配置されます。app.config ファイルに直接書き込みを行うことは可能ですが、このファイルはアプリケーションの 1 つ下のレベルに置かれているため、配置後にはコードからアクセスできなくなっています。デザイン時に変更を適用するには、DynamicProps.exe.config を開き、app.config ファイルの内容をコピーした上で、アプリケーションを再実行する必要があります。

動的プロパティとして公開されないプロパティを保存したい場合には、どうすればいいのでしょうか? 次のセクションでは、新たなプロパティを動的プロパティへと変更します。

新しい動的プロパティの作成

デフォルトで動的プロパティとして公開されるプロパティに加えて、他のプロパティも保存したい場合があります。一般的なシナリオの例としては、フォームの位置を保存しておき、ユーザーがフォームを移動した場合、次にフォームを開くと移動先の位置に開かれるようにするというものがあります。フォームの Location プロパティは動的プロパティとしては公開されていませんが、app.config ファイルを編集することで動的プロパティとして動作させることができます。

Location プロパティは、実際には Location.XLocation.Y の 2 つのプロパティから構成されており、この 2 つを個別に扱う必要があります。

新しい動的プロパティを作成するには

  1. app.config ファイルの TopMost プロパティの行のすぐ下に、2 つの新しい行を追加します。

    <add key="Form1.X" value="0" />
    <add key="Form1.Y" value="0" />
    
  2. app.config ファイルを閉じて保存します。さもないと、アプリケーションを実行するたびにファイルを閉じるように求められます。

  3. プロシージャの一番下に次のコードを追加します。このコードは、Sub_New イベント ハンドラを変更して、構成ファイルから値を読み込むようにしています。

    Dim configReader As System.Configuration.AppSettingsReader = New _
    System.Configuration.AppSettingsReader()
    Dim x As Integer, y As Integer
    ' 構成ファイルから値を取り出し、Integer に変換する。
    x = CType(configReader.GetValue("Form1.X", _
       GetType(System.Int32)), Integer)
    y = CType(configReader.GetValue("Form1.Y", _
       GetType(System.Int32)), Integer)
    ' 新しい x、y 座標を使って位置を設定する。
    Me.Location = New System.Drawing.Point(x, y)
    

    新しい AppSettingsReader オブジェクトを作成したのは、InitializeComponent プロシージャで使用されているものはアクセス不可能だからです。X および Y プロパティは構成ファイルに異なるキーを持っているため、個別に設定する必要があります。最後に、Location プロパティは引数として Point オブジェクトを取るので、X および Y 座標を指定する点を作成します。

  4. Form1_Closing イベント ハンドラを変更して、Location.XLocation.Y の値を構成ファイルに保存するようにします。 If Node.Name = "add" Then の行の後に、次のコードを追加します。

    If Node.Attributes.GetNamedItem("key").Value = "Form1.X" Then
       ' X の値を文字列に変換する。
       Node.Attributes.GetNamedItem("value").Value = _
          CType(Me.Location.X, String)
    End If
    If Node.Attributes.GetNamedItem("key").Value = "Form1.Y" Then
       Node.Attributes.GetNamedItem("value").Value = CType(Me.Location.Y, _
          String)
    End If
    
  5. アプリケーションを実行し、フォームを移動し、アプリケーションを閉じた後に再起動します。

    フォームは前回の位置で開かれるはずですが、現実にはそうなりません。なぜでしょうか? 初期化の際に、Location プロパティは StartPosition プロパティによってオーバーライドされます。StartPosition の既定値は WindowsDefault ですが、これはフォームの初期位置を Windows に決定させることを意味しています。

  6. Sub_New プロシージャに次の行を追加して、プロパティ設定が有効になるようにします。

    Me.StartPosition = FormStartPosition.Manual
    

アプリケーションを実行し、再起動すると、フォームは期待どおりに前回の位置で開かれるようになります。

結論

この記事の説明からわかるように、独自の動的プロパティを作成するのは難しいことではなく、初期化プロシージャと終了プロシージャに数行のコードを追加するだけで済みます。この記事では Windows アプリケーションに焦点を当てましたが、Web アプリケーションでも簡単に同じテクニックを利用できます。ユーザー設定を保存するアプリケーションと保存しないアプリケーションがあったら、ほとんどのユーザーは前者を選ぶことでしょう。

ページのトップへ ページのトップへ