C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[6]: ユーザーコントロールのプロパティ値の保存


(過去ログ 30 を表示中)

[トピック内 13 記事 (1 - 13 表示)]  << 0 >>

■14237 / inTopicNo.1)  ユーザーコントロールのプロパティ値の保存
  
□投稿者/ あき (3回)-(2008/02/13(Wed) 18:27:14)

分類:[.NET 全般] 

開発環境、使用言語
 WinXp, VB2005

こんばんわ。ユーザーコントロールで苦労しております。

VB6.0での「UserControl_ReadProperties」「UserControl_WriteProperties」と同様の機能をVB2005で実現したいのですが、
実装方法がわかりません。(この機能によりデザイン時のユーザーコントロールの設定を記憶しています)
ヘルプ等で調べるとMy.Settingオブジェクトを使用して実現するような事を書いてあるのですが、
いまいちどのように実装すれば良いのか方法がわかりません。

参考までにVB6のコードを以下に載せておきます。よろしくお願いします。
------------------------------------------------------------------------------------------------
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)

lblCaption.Caption = PropBag.ReadProperty("Caption", "CTX")
Call CaptionChange

txtText.Text = PropBag.ReadProperty("Text", "")
m_OldText = txtText.Text

UserControl.Enabled = PropBag.ReadProperty("Enabled", True)
If UserControl.Enabled Then
txtText.BackColor = vbWhite
Else
txtText.BackColor = vb3DFace
End If

m_length = PropBag.ReadProperty("Length", 64)
lblNameText.Caption = PropBag.ReadProperty("NameText", "")

txtText.Width = PropBag.ReadProperty("TextWidth", 0)
Call WidthSet

Set Font = UserControl.Parent.Font

BackColor = PropBag.ReadProperty("BackColor", vbWhite)
CaptionBackColor = PropBag.ReadProperty("CaptionBackColor", vbButtonFace)

End Sub

'記憶領域にプロパティ値を書き込みます。
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)

Call PropBag.WriteProperty("Caption", lblCaption.Caption, "CTX")
Call PropBag.WriteProperty("Text", txtText.Text, "")
Call PropBag.WriteProperty("Enabled", UserControl.Enabled, True)
Call PropBag.WriteProperty("Length", m_length, 64)
Call PropBag.WriteProperty("NameText", lblNameText.Caption, "")
Call PropBag.WriteProperty("TextWidth", txtText.Width, 0)
Call PropBag.WriteProperty("BackColor", txtText.BackColor, vbWhite)
Call PropBag.WriteProperty("CaptionBackColor", lblCaption.BackColor, vbButtonFace)

End Sub
引用返信 編集キー/
■14240 / inTopicNo.2)  Re[1]: ユーザーコントロールのプロパティ値の保存
□投稿者/ 魔界の仮面弁士 (615回)-(2008/02/13(Wed) 18:51:18)
2008/02/13(Wed) 19:19:33 編集(投稿者)
No14237 (あき さん) に返信
> VB6.0での「UserControl_ReadProperties」「UserControl_WriteProperties」と同様の機能をVB2005で実現したいのですが、
> 実装方法がわかりません。(この機能によりデザイン時のユーザーコントロールの設定を記憶しています)

VB6 でいうところの PropertyBag 相当のデータは、*.Designer.vb ファイルに
自動的にシリアライズされるようになっています。


たとえば、Length プロパティを例にとると、
>     m_length = PropBag.ReadProperty("Length", 64)
(中略)
>     Call PropBag.WriteProperty("Length", m_length, 64)                                      
これらはそのまま、『Public Property Length() As Integer』として実装すれば OK です。
初期値の 64 を表すには、<DefaultValue(規定値)> 属性を利用します。

単純な DefaultValue としては扱えないような場合、たとえば、
VB6 でいうところの、(Font や BackColor などの)『Ambient』なプロパティのような
場合においては、DefaultValue 属性を使う代わりに、
 『Private Function ShouldSerializeLength() As Boolean』…規定値かどうかを返す
 『Public Overridable Sub ResetLength()』…初期値に戻すための処理を記述
のメソッドを用意する事で対応できます。

また余裕があれば、プロパティの変更通知のための、
 『Public Event LengthChanged(ByVal sender As Object, ByVal E As EventArgs)』…プロパティ変更イベント
 『Protected Overrides Sub OnLengthChanged(ByVal E As EventArgs)』…イベントを発生させるメソッド
も用意しておいてください。


なお、プロパティ値をシリアライズさせるかどうかを制御したいのであれば、
そのプロパティに DesignerSerializationVisibility 属性を割り当てれば OK です。


それ以外では、
 EditorBrowsable属性 … コードの入力補完(IntelliSense)に表示させるかどうか
 Browsable属性 … PropertyGrid の表示させるかどうか
 Category属性 … PropertyGrid でのカテゴリ名
 Description属性 … PropertyGrid 等に表示される説明文
あたりも調べとくと良いかも。

引用返信 編集キー/
■14244 / inTopicNo.3)  Re[2]: ユーザーコントロールのプロパティ値の保存
□投稿者/ あき (5回)-(2008/02/13(Wed) 19:15:11)
早速のお返事ありがとうございます。
重ねて質問することをご了承下さい。

> たとえば、Length プロパティを例にとると、
>> m_length = PropBag.ReadProperty("Length", 64)
>> Call PropBag.WriteProperty("Length", m_length, 64)
> これらはそのまま、『Public Property Length() As Integer』として実装すれば OK です。

具体的には、以下のようなプロパティプロシージャを実装するだけで良いということでしょうか?
--------------------------------------------------------
Public Property Length() As Short
Get
Length = m_length
End Get
Set(ByVal Value As Short)

RaiseEvent LengthChange()

End Set
End Property
--------------------------------------------------------

> また余裕があれば、プロパティの変更通知用に、「LengthChanged イベント」も
> 実装すると良いでしょう。
 VB6では、PropertyChanged "プロパティ名"と記述するだけで、VB自体に変更通知が伝わるのですが、
 VB2005の場合は、どの様に実装するのでしょうか?(上記コード内の記述ではうまく動作しませんでした)

普通にプロパティを実装しただけでは、フォーム上に貼り付けたユーザーコントロールに対して
デザイナ上で設定を行った後、フォームウィンドを閉じて再度開くと設定内容が初期化されてしまいました。

余談ですが、魔界の仮面弁士さんが教えて下さった内容を記載した書籍等はありますか?
色々本屋に足を運び捜したのですが、有益な情報を記載した書籍は見つけることが出来ませんでした。
もしご存知でしたら教えてください。(私の頭ではライブラリの記載内容では理解出来ません。。。)

以上、よろしくお願いいたします。


引用返信 編集キー/
■14245 / inTopicNo.4)  Re[3]: ユーザーコントロールのプロパティ値の保存
□投稿者/ 魔界の仮面弁士 (616回)-(2008/02/13(Wed) 19:39:34)
2008/02/13(Wed) 20:34:06 編集(投稿者)

No14244 (あき さん) に返信
> 具体的には、以下のようなプロパティプロシージャを実装するだけで良いということでしょうか?

(1) Set 節に、肝心の「m_length の更新処理」が抜けています。

(2) LengthChange イベントではなく、LengthChanged イベントという名前にしてください。
 また、その引数は他のコントロールと同様に、第1引数=Object型, 第2引数=EventArgsあるいはその派生型 とします。

(3) プロパティから直接 RaiseEvent させるのではなく、OnLengthChanged メソッドを呼び出すようにします。

なお、2,3 のイベント通知は必須ではありませんが、個人的には、入れておく事をお薦めします。


> 普通にプロパティを実装しただけでは、フォーム上に貼り付けたユーザーコントロールに対して
> デザイナ上で設定を行った後、フォームウィンドを閉じて再度開くと設定内容が初期化されてしまいました。
Property Set に「m_length = Value」が無いからでは無いでしょうか。

ソリューション エクスプローラの[すべてのファイルを表示]アイコンを押して、
Form1.Designer.vb に、Length プロパティの保存処理が書き込まれているかどうかをチェックしてみてください。


> 余談ですが、魔界の仮面弁士さんが教えて下さった内容を記載した書籍等はありますか?
書籍の有無は分かりません。(参考にした書籍はありません)
私は、MSDN ライブラリのチュートリアルを見ながら、Try & Error を繰り返して覚えましたので。(^^;


> 私の頭ではライブラリの記載内容では理解出来ません。。。
『ライブラリのどこを見れば良いのか分からない』とか、
『○○を見たけれど、そこに書かれている××の意味が分からない』など、
具体的な質問を頂ければ、分かる範囲で回答しますよ。
引用返信 編集キー/
■14262 / inTopicNo.5)  Re[4]: ユーザーコントロールのプロパティ値の保存
□投稿者/ あき (6回)-(2008/02/14(Thu) 10:43:19)
No14245 (魔界の仮面弁士 さん) に返信
 引き続きご指導お願い致します。

> (3) プロパティから直接 RaiseEvent させるのではなく、OnLengthChanged メソッドを呼び出すようにします。
 教えて頂いた、@イベント宣言、Aプロパティ、Bイベント発生メソッドをどのように使用して実装するかが
 良くわかりません。一つ具体例を示して頂けるとありがたいです。
 下記コードの☆マーク部分の記載がよくわかりません。

------------------------------------------------------------------------------------------------------
--@宣言
Public Event LengthChanged(ByVal e As System.EventArgs)

--Aプロパティ
Public Property Length() As Integer
Get
Return m_length
End Get
Set(ByVal New_Lengtn As Integer)
m_length = New_Lengtn

☆☆☆☆☆☆☆☆☆☆☆

End Set
End Property

--Bイベント発生メソッド
(Overridesキーワードを使用するとベースClassのSubをオーバーライドしないためとエラーが出ます)
Protected Sub OnLengthChanged(ByVal E As EventArgs)
☆☆☆☆☆☆☆☆☆☆☆
End Sub
------------------------------------------------------------------------------------------------------

> 『ライブラリのどこを見れば良いのか分からない』とか、
> 『○○を見たけれど、そこに書かれている××の意味が分からない』など、
> 具体的な質問を頂ければ、分かる範囲で回答しますよ。
 例えば、TextBox.OnBackColorChanged メソッドのヘルプを参照すると、
 以下の様に記載があるのですが、実際にユーザーコントロールに独自実装したプロパティとの
 関連づいた使用方法が記載されていないためよく使用方法が理解できません。

Visual Basic (宣言)
Protected Overrides Sub OnBackColorChanged ( _
e As EventArgs _
)

Visual Basic (使用法)
Dim e As EventArgs

Me.OnBackColorChanged(e)







引用返信 編集キー/
■14264 / inTopicNo.6)  Re[5]: ユーザーコントロールのプロパティ値の保存
□投稿者/ まどか (442回)-(2008/02/14(Thu) 11:13:23)
クラスライブラリ開発のデザインガイドライン
http://msdn2.microsoft.com/ja-jp/library/ms229042(VS.80).aspx
イベントのデザイン
http://msdn2.microsoft.com/ja-jp/library/ms229011(VS.80).aspx

イベント実装側は基本はこんな感じ。

'Public Event TextChanged(ByVal sender As Object, ByVal e As EventArgs)

'Protected Overridable Sub OnTextChanged(ByVal e As EventArgs)
' RaiseEvent TextChanged(Me, e)
'End Sub

'Private _Text As String
'Public Property Text() As String
' Set(ByVal value As String)
' If value <> _Text Then   ※値が異なる場合のみ発生させる
' OnTextChanged(EventArgs.Empty)
' End If
' End Set
'End Property

On〜の役目は、派生側で基底クラスのイベントを発生させたり動作を変更するため。

'Public Class Class1
' Inherites OriginalClass

' 基底クラスのイベントを発生
' 利用者はClass1.TextChangedを受信
' 処理を追加すればClass1独自の動作を追加することになる
'Protected Overrides Sub OnTextChanged(ByVal e As EventArgs)
' MyBase.OnTextChanged(e)  ※呼ばなければClass1.TextChangedは発生しない。
'End Sub

引用返信 編集キー/
■14268 / inTopicNo.7)  Re[5]: ユーザーコントロールのプロパティ値の保存
□投稿者/ 魔界の仮面弁士 (617回)-(2008/02/14(Thu) 11:37:48)
No14262 (あき さん) に返信
> Public Event LengthChanged(ByVal e As System.EventArgs)
引数は 2 つ用意してください。自身を表す Object と、イベント自体の引数 EventArgs です。

すなわち、以下のいずれかの表記となります。
    Public Event LengthChanged As EventHandler
    Public Event LengthChanged(ByVal sender As Object, ByVal e As EventArgs)


> Public Property Length() As Integer
>     Get
>         Return m_length
>     End Get
>     Set(ByVal New_Lengtn As Integer)
>         m_length = New_Lengtn
>     	☆☆☆☆☆☆☆☆☆☆☆
>     End Set
> End Property
☆部では、直接 RaiseEvent するかわりに、Me.OnLengthChanged(EventArgs.Empty) を呼び出します。


> (Overridesキーワードを使用するとベースClassのSubをオーバーライドしないためとエラーが出ます)
> Protected Sub OnLengthChanged(ByVal E As EventArgs)
> 	☆☆☆☆☆☆☆☆☆☆☆
> End Sub
Overrides ではなく、Overridable です。
Overrides が必要なのは、Length プロパティを持ったクラスを継承している場合だけです。

☆部では、そのまま RaiseEvent のコードを書くだけです。
すなわち、RaiseEvent LengthChanged(Me, e) です。


> 例えば、TextBox.OnBackColorChanged メソッドのヘルプを参照すると、
> 以下の様に記載があるのですが、実際にユーザーコントロールに独自実装したプロパティとの
> 関連づいた使用方法が記載されていないためよく使用方法が理解できません。
まず、これが[Overrides]であるのは、TextBox の継承元のクラスが、
OnBackColorChanged を(オーバーライド可能なメソッドとして)実装済みだからです。
独自に追加する場合は、[Overridable] です。

TextBox.OnBackColorChanged は Overrides と書かれていますが、
Control.OnBackColorChanged は Overridable になっていますよね。

引用返信 編集キー/
■14269 / inTopicNo.8)  Re[6]: ユーザーコントロールのプロパティ値の保存
□投稿者/ 魔界の仮面弁士 (618回)-(2008/02/14(Thu) 11:50:37)
No14268 (魔界の仮面弁士) に追記

ミニマムコードとして書くと、これだけです。
(VB6 の PropertyBag にあたる処理は自動的に行われるため、今回は特に実装する必要はありません)

Private _Length As Short
Public Property Length() As Short
    Get
        Return _Length
    End Get
    Set(ByVal value As Short)
        _Length = value
    End Set
End Property

=============================================================================
イベント制御を含めた場合は、こんな感じ。
サンプルということで、あえて属性を付けて冗長的に書いています。


#Region "Length プロパティの定義"
    Private Const DefaultLength As Short = 64S
    Private _Length As Short = DefaultLength

    ''' <summary>Length プロパティの概要説明をここに記述</summary>
    <Browsable(True)> _
    <EditorBrowsable(EditorBrowsableState.Always)> _
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
    <DefaultValue(DefaultLength)> _
    <Category("Behavior")> _
    <Description("プロパティの概要説明をここに記述")> _
    Public Property Length() As Short
        Get
            Return _Length
        End Get
        Set(ByVal value As Short)
            _Length = value
            '
            ' TODO: 状態変更コードをここに記述します。
            '   (画面の再描画や、内包コントロールの制御など)
            '
            OnLengthChanged(EventArgs.Empty)
        End Set
    End Property

    ''' <summary><see cref="P:Length"/>プロパティの内容が変更されたときに発生します。</summary>
    <Browsable(True)> _
    <EditorBrowsable(EditorBrowsableState.Always)> _
    <Category("プロパティ変更")> _
    <Description("Length プロパティの内容が変更されたときに発生します。")> _
    Public Event LengthChanged As EventHandler

    ''' <summary><see cref="E:LengthChanged"/>イベントを発生させます。</summary>
    <EditorBrowsable(EditorBrowsableState.Always)> _
    Protected Overridable Sub OnLengthChanged(ByVal e As EventArgs)
        RaiseEvent LengthChanged(Me, e)
    End Sub
#End Region

=============================================================================
また、VB6 ヘルプでいうところの「アンビエント プロパティ」の実装が必要な場合は、
No14240 で解説したように、ShouldSerialize* と Reset* を実装しましょう。
http://msdn2.microsoft.com/ja-jp/library/53b8022e.aspx


なお、今回は Short 型であるため、属性指定が全く無くても問題ありませんでしたが
コレクションなどをシリアライズさせたい場合には、DesignerSerializationVisibility 属性が
意味を持ってきます。こちらについても調べておいてください。

引用返信 編集キー/
■14284 / inTopicNo.9)  Re[6]: ユーザーコントロールのプロパティ値の保存
□投稿者/ あき (7回)-(2008/02/14(Thu) 16:57:58)
No14264 (まどか さん) に返信

> クラスライブラリ開発のデザインガイドライン
> http://msdn2.microsoft.com/ja-jp/library/ms229042(VS.80).aspx
> イベントのデザイン
> http://msdn2.microsoft.com/ja-jp/library/ms229011(VS.80).aspx
 参考にさしてもらいます。
 また、サンプルコードの記載ありがとうございます。
 
 改めて報告させて頂きます。
引用返信 編集キー/
■14285 / inTopicNo.10)  Re[7]: ユーザーコントロールのプロパティ値の保存
□投稿者/ あき (8回)-(2008/02/14(Thu) 17:29:24)
No14269 (魔界の仮面弁士 さん) に返信

 丁寧な解説およびサンプルコードありがとうございます。
 プロパティ実装と動作確認が無事できました。

> =============================================================================
> イベント制御を含めた場合は、こんな感じ。
> サンプルということで、あえて属性を付けて冗長的に書いています。
> Protected Overridable Sub OnLengthChanged(ByVal e As EventArgs)
> RaiseEvent LengthChanged(Me, e)
> End Sub
 最後は、RaiseEventでイベントを発生させる事には変わりないのですね。
 これにより、ユーザーコントロールを使用している側(フォーム)でイベントを受取る事が出来ると解釈しております。
 (プロパティ内から直接RaiseEventしただけではユーザーコントロールのプロパティ変更イベントは受取る事が出来ない)

あともうひとつご教授下さい。
ユーザーコントロール内からユーザーコントロールが張り付いているフォーム(またはフォーム上のコントロール)を参照する場合は、
どういった記述になるでしょうか?

例1)
VB6.0
 Extender.TabIndex
VB2005
@Me.Parent.TabIndex
AMyBase.Parent.TabIndex

例2)
VB6.0
 Private Sub UserControl_InitProperties
VB2005
 Private Sub UserControl_InitProperties(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load/MyBase.Load

以上、よろしくお願い致します。


引用返信 編集キー/
■14286 / inTopicNo.11)  Re[8]: ユーザーコントロールのプロパティ値の保存
□投稿者/ まどか (443回)-(2008/02/14(Thu) 17:40:19)
>  (プロパティ内から直接RaiseEventしただけではユーザーコントロールのプロパティ変更イベントは受取る事が出来ない)

いえ、RaiseEventするのだから発生しますよ。
On〜の実装はガイドラインです。
なぜそうするかは、先に書きましたし、またリンクのドキュメントを読んでください。

引用返信 編集キー/
■14288 / inTopicNo.12)  Re[8]: ユーザーコントロールのプロパティ値の保存
□投稿者/ 魔界の仮面弁士 (621回)-(2008/02/14(Thu) 18:35:08)
2008/02/14(Thu) 18:36:59 編集(投稿者)

No14285 (あき さん) に返信
> 最後は、RaiseEventでイベントを発生させる事には変わりないのですね。
ですます。
(デリゲートを通じて発生させる方法もありますが、RaiseEvent の方が楽でしょう)


> これにより、ユーザーコントロールを使用している側(フォーム)で
> イベントを受取る事が出来ると解釈しております。
OnLengthChanged を介さずに RaiseEvent したとしても、イベントは通知されます。

わざわざ、イベント発生のためのメソッドを用意するのは、どちらかというと、
継承時に都合が良いから…というガイドラインのようなものです。


たとえばフォームの Load イベントについて

 Public Class Form1
  Inherits Form
  Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
   MsgBox("前")
   MyBase.OnLoad(e)
   MsgBox("後")
  End Sub
  Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
   MsgBox("イベント")
  End Sub
 End Class

のようなコードを書くと、[前],[イベント],[後]の順でメッセージが出ますよね。
そして OnLoad メソッドで、「MyBase.OnLoad(e)」の行をコメントにすると、
Load イベントは発生しなくなります。

このように、 OnEventName メソッドを用意しておくと、派生先のクラスで、
イベントの通知タイミングを細かく制御させることができるようになるわけです。
(だからこそ、派生先でカスタマイズできるよう "Protected Overridable" で実装するのです)

たとえば Excel だと、「Application.EnableEvents プロパティ」で、
イベントの抑制ができますが、それと同様の機能を、派生先で実装する事もできます。
しかし、プロパティ内部から直接 RaiseEvent していると、そうした制御を
派生先のクラスが実装できなくなってしまいます。


> ユーザーコントロール内からユーザーコントロールが張り付いているフォーム
> (またはフォーム上のコントロール)を参照する場合は、
> どういった記述になるでしょうか?
通常の Controlと同様に、ParentForm や Parent プロパティで取得できます。

また、.Parent.Controls のようにすれば、VB6 でいうところの
「UserControl.ParentControls」相当の機能にもなります。
引用返信 編集キー/
■14292 / inTopicNo.13)  Re[9]: ユーザーコントロールのプロパティ値の保存
□投稿者/ あき (9回)-(2008/02/14(Thu) 19:16:41)
No14288 (魔界の仮面弁士 さん) に返信
> 2008/02/14(Thu) 18:36:59 編集(投稿者)

 丁寧な解説ありがとうございました。やっと理解できました。
 教えて頂いた事を踏まえてもう一度ヘルプを読んでみます。

 長々とお付き合い頂きありがとうございました。
 また行き詰った時にはご質問させてもらいます。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -