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

子コントロール(又はコンポーネント)のイベントを継承する

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

SplitContainerコントロールのプロパティ(イベントタブ)ウィンドウで、 SplitContainer.Panel1.Enter
といった、階層構造を持つイベント項目を作成したいのですが、Googleって見ましたが見当たりません。
(検索方法が悪いのカモですが・・)

現在、子コントロールまたは子フォームのイベントを親コンポーネントがキャッチして、そのまま親コンポーネントはOwnerへRaiseEventで通知しております。

これを、
@プロパティ(イベントタブ)ウィンドウで、イベント処理を定義し、
A親コンポーネントを介さずに、Ownerでイベントをキャッチし処理
を行なえる様にしたい。
(今後、各子フォームで機能追加しても親コンポーネントに影響させない様に)
と思っております。

何卒、ご教授宜しくお願い致します。
■No23826に返信(Ritaさんの記事)
> 階層構造を持つイベント項目を作成したいのですが
たとえば、
 AddHandler SplitContainer1.Panel1.Click, 〜
というコードと同様に、通常のフォームでも
 AddHandler Me.Button1.Click, 〜
 AddHandler Me.Panel1.Controls("Button1").Click, 〜
のようなコードを書けますよね。

そのため、最低限の手抜き実装で済ますのであれば、UserControl 側では
特に特別な処理を設ける必要は無く、単に、公開したいイベントを持ったクラスを
プロパティとして公開するだけでも十分です。

そこに手を加えて、SplitContainer.Panel1 のように子クラスのプロパティも
デザイナ側で認識されるようにしたいのであれば、そのプロパティに対して
System.ComponentModel.DesignerSerializationVisibilityAttribute 属性で
Content を指定しておけば OK です。


<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
Public ReadOnly Property Sample() As TextBox
 Get
  Return Me.TextBox1
 End Get
End Property
2009/01/20(Tue) 14:59:18 編集(投稿者)
2009/01/20(Tue) 12:58:08 編集(投稿者)


> そのため、最低限の手抜き実装で済ますのであれば、UserControl 側では
> 特に特別な処理を設ける必要は無く、単に、公開したいイベントを持ったクラスを
> プロパティとして公開するだけでも十分です。
public withevent で公開してました・・・

> そこに手を加えて、SplitContainer.Panel1 のように子クラスのプロパティも
> デザイナ側で認識されるようにしたいのであれば、そのプロパティに対して
> System.ComponentModel.DesignerSerializationVisibilityAttribute 属性で
> Content を指定しておけば OK です。
なる程です。


> <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
> Public ReadOnly Property Sample() As TextBox
属性について、学び始めたばかりで思いつきませんでした。
有難う御座いました。

そこで、コーディングしてデザイナ.プロパティウィンドウよりイベント登録しようとすると、以下のメッセージが出力され解決できませんでした。

「サービス IDictionaryService が必要ですが、見つかりませんでした。このサービスを削除した場合、必ず置換したサービスを指定してください。」

そこで、
"DesignerSerializationVisibility"などで、検索してみたのですが、イベント関連でのサンプルや実装方法についてMSNの?なページや外国語のページだったりで、努力している所です・・・が・・・

重々ご教授の程宜しくお願い致します。
2009/01/20(Tue) 15:45:54 編集(投稿者)

ちなみにですが、
以下のソースで試してみました。

Imports System.ComponentModel

Public Class Component1
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
    Public ReadOnly Property BSource() As BindingSource
        Get
            Return Me.BindingSource1
        End Get
    End Property
End Class

そこで、コンパイル後ツールボックスからフォームへドロップ、プロパティの入力は出来たのだが、イベントを入力・・・で、エラーです。
そこで、フォームデザイナ.vbで入力したプロパティ値を確認してみたが、記述がない。
保存して、ソリューションのクリーンをして、開き直して、プロパティウィンドウで先のプロパティの値を確認してみると残っていなかった。
・・・
とすると、
・・・
    <Editor(GetType(TestCollectionEditor), GetType(System.Drawing.Design.UITypeEditor))> _
のような属性&クラスが必要なのでしょうか?
2009/01/20(Tue) 18:14:15 編集(投稿者)

■No23836に返信(Ritaさんの記事)
> イベントを入力・・・で、エラーです。

正しい対応方法なのかどうかわかりませんが、一応できました。
http://www.vb-user.net/junk/replySamples/2009.01.20.17.12/Sample20090120.zip


# エラーの原因等は調査中…。
2009/01/22(Thu) 13:10:04 編集(投稿者)

魔界の仮面弁士さん度々有難う御座います。
 
ちなみに手書き実装も、試行してみました。
 
Public Class Component1
    Private _BSource2 As New BindingSource

    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
    Public ReadOnly Property BSource2() As BindingSource
        Get
            Return _BSource2
        End Get
    End Property
End Class
 
こちらも同様に、実装できました。
(プロパティ値もデザイナファイルに書き込まれていました)
 
 
・・とすると、「共通点は?」と考えると
 
Partial Class Form1
    Private Sub InitializeComponent()
           :
        Me.Component11 = New Sample20090120.Component1(Me.components)
           :
    End Sub
End Class
 
Property BSource() As BindingSource
           :
  Me.components.Remove(Me.BindingSource1)
           :
End Property
 
とする点では、コンポーネントに乗っかっているコントロール所有しない?
つまりイベントを継承する場合「継承するものは乗っけない」とする所でしょうか・・・
 
推測ですが・・
 デザイナでプロパティウィンドでイベント登録しようとすると、
  VS2005では・・
   その所有者(実装先)のソースを探しに行こうとするが"Form1.vb"と"Component1.vb"のどっちに?
  でエラーとなる?
  でも・・・、じゃぁプロパティも一緒では?という疑問も出てきます。
  ("Component1.vb"でプロパティ定義してるから"Form1.Designer.vb"にコーディングする。・・謎は深まるばかりです。)
 
ちなみに、私の方ではコンストラクタにてコンポーネントを破棄する様にしました。
 
    '<System.Diagnostics.DebuggerNonUserCode()> _
    Public Sub New()
        MyBase.New()

        'この呼び出しは、コンポーネント デザイナで必要です。
        InitializeComponent()

        Me.components.Remove(Me.BindingSource1)
    End Sub
 
ところで実装先がDisposeする時、ちゃんと解放してくれているのか?
と気になります。
 
一応、なにが足りないのか?正式な方法があるのか?調査を続けてみます。
以下の構造図の様に、更にネストした構造で試しました。
ネストできるイベントの階層としては孫までのようです。

構造図
Form1
└ Public Class Component1
  └ Public Class cmp0
    └ BindingSource1
--------------------------------------------------------------------------------
以下、コード。
Imports System.ComponentModel

Public Class cmp0
    Implements ISupportInitialize

    Public Event NameChanged(ByVal sender As Object, ByVal e As System.EventArgs)
    Public Event AddingNew(ByVal sender As System.Object, ByVal e As System.ComponentModel.AddingNewEventArgs)
    Private _Name As String
    Public Property Name() As String
        Get
            Return _Name
        End Get
        Set(ByVal value As String)
            If _Name = value Then Exit Property
            RaiseEvent NameChanged(Me, New EventArgs)
            _Name = value
        End Set
    End Property

    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
    Public ReadOnly Property BSource() As BindingSource
        Get
            Return Me.BindingSource1
        End Get
    End Property

    '<System.Diagnostics.DebuggerNonUserCode()> _
    Public Sub New()
        MyBase.New()

        'この呼び出しは、コンポーネント デザイナで必要です。
        InitializeComponent()

        Me.components.Remove(Me.BindingSource1)
    End Sub

    Public Sub BeginInit() Implements ISupportInitialize.BeginInit
        _Name = ""
    End Sub

    Public Sub EndInit() Implements ISupportInitialize.EndInit
    End Sub

    Private Sub BindingSource1_AddingNew(ByVal sender As System.Object, ByVal e As System.ComponentModel.AddingNewEventArgs) Handles BindingSource1.AddingNew
        RaiseEvent AddingNew(Me, New AddingNewEventArgs)
    End Sub
End Class


Public Class Component1

    '<System.Diagnostics.DebuggerNonUserCode()> _
    Public Sub New()
        MyBase.New()

        'この呼び出しは、コンポーネント デザイナで必要です。
        InitializeComponent()

        Me.components.Remove(Me.Cmp01)
    End Sub

    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
    Public ReadOnly Property cmp() As cmp0
        Get
            Return Me.Cmp01
        End Get
    End Property

End Class


Public Class Form1

    Private Sub Component11_cmp_NameChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Component11.cmp.NameChanged
        MsgBox("Component11_cmp_NameChanged->" & Me.Component11.Cmp01.Name)
    End Sub

    Private Sub Component11_cmp_AddingNew(ByVal sender As System.Object, ByVal e As System.ComponentModel.AddingNewEventArgs) Handles Component11.cmp.AddingNew
        MsgBox("Component11_cmp_AddingNew")
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.Component11.Cmp01.BSource.AddNew()
        Me.Component11.Cmp01.Name = "123"
    End Sub

End Class

とりあえず、解決とさせて頂きます。

魔界の仮面弁士さん、有難う御座いました。
解決済み!

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