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

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

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

Re[10]: vbのaddとremoveについて


(過去ログ 144 を表示中)

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

■84199 / inTopicNo.1)  vbのaddとremoveについて
  
□投稿者/ KAZ (1回)-(2017/05/30(Tue) 14:49:19)

分類:[VB.NET/VB2005 以降] 

vb2010での質問です。イマイチ インスタンス というものがしっかり理解できてないせいだと思うのですが、お願いします。
例えば、Panel1にあるPictureBoxをクリックしたらPanel2に移るという処理の時に、

Sub Test(略) Handles PictureBox.Click
Dim Ctrl As Control =Ctype(sender,Control)
Me.Panel2.Controls.add(Ctrl)
End Sub

上記の処理で目的は達成できるのですが、Removeとか、Remove入れたらDisposeとか入れなくても大丈夫なのでしょうか?
また、Removeを入れる時は、Ctrl自身をRemoveしなきゃいけないのですが、
Ctrl.parent.Contrls.Remove(Ctrl)
このような処理で後々不具合が生じることってありませんか?なんか自分自身をRemoveって。。。と考えてしまいます。

引用返信 編集キー/
■84201 / inTopicNo.2)  Re[1]: vbのaddとremoveについて
□投稿者/ 魔界の仮面弁士 (1293回)-(2017/05/30(Tue) 16:35:23)
2017/05/30(Tue) 16:39:35 編集(投稿者)

No84199 (KAZ さん) に返信
> イマイチ インスタンス というものがしっかり理解できてない
ツールボックスに並んでいる Label や TextBox が「クラス」。
フォームに貼られた TextBox1 や TextBox2 は「インスタンス」です。

TextBox1 も TextBox2 も、TextBox クラスの特性を備えていますが、
それぞれは異なるインスタンスなので、異なるデータを管理します。


> 上記の処理で目的は達成できるのですが、Removeとか、Remove入れたらDisposeとか入れなくても大丈夫なのでしょうか?
いいえ。Controls から子コントロールを取り除いた場合、
取り除かれた子コントロールのそれぞれに対して
必ず Dispose しておく必要があります。

ただし孫コントロールは Dispose しなくても大丈夫です。
これは、親コントロールが Dispose される際に、
子コントロールも Dispose されるようになっているためです。


> また、Removeを入れる時は、Ctrl自身をRemoveしなきゃいけないのですが、
> Ctrl.parent.Contrls.Remove(Ctrl)
上記のようにするのであれば、
  If Ctrl.Parent IsNot Nothing Then
も必要でしょう。

他の箇所で Controls.Clear されていた場合や、
そもそも Controls.Add されていなかった場合には
Parent が空になりえますので。


> なんか自分自身をRemoveって。。。
内部的には、
 Ctrl.Parent = Nothing
は、
 Ctrl.Parent.Controls.Remove(Ctrl)
と同義です。

逆に Controls.Add も、内部的には
Parent プロパティの書き換えが行われています。

ですから、子が自身を処分するような設計にしたとしても、
処理手順としては問題無いと思います。
個人的には、親が子を処分する階層設計の方が好みですが。
引用返信 編集キー/
■84207 / inTopicNo.3)  Re[2]: vbのaddとremoveについて
□投稿者/ KAZ (2回)-(2017/05/31(Wed) 03:42:57)
No84201 (魔界の仮面弁士 さん) に返信
早速の返信、詳しい説明ありがとうございます。

>>上記の処理で目的は達成できるのですが、Removeとか、Remove入れたらDisposeとか入れなくても大丈夫なのでしょうか?
> いいえ。Controls から子コントロールを取り除いた場合、取り除かれた子コントロールのそれぞれに対して必ず Dispose しておく必要があります。
やっぱり前記の状態だと手抜きになるんですね。きちんとした処理にするなら、

  Sub Test(略) Handles PictrueBox.Click
    Dim Ctrl as Control = Ctype(sender,Control)
    Me.Panel1.Controls.Remove(Ctrl)
    Ctrl.Dispose()
    Me.Panel2.Controls.Add(Ctrl)
  End Sub

こんな形でしょうか。実際はPanel1→Panel2の場合とPanel2→Panel1の場合があるので、もう一工夫必要だとは思いますが。

>>Ctrl.parent.Contrls.Remove(Ctrl)
> 上記のようにするのであれば、
>   If Ctrl.Parent IsNot Nothing Then
> も必要でしょう。
今回に関してはPanelが削除される心配はないので必要ないですが、そこまで気を配らないといけないんですね。ありがとうございます。


> 逆に Controls.Add も、内部的にはParent プロパティの書き換えが行われています。
> ですから、子が自身を処分するような設計にしたとしても、処理手順としては問題無いと思います。
???もしかして、前述のようなコードではなく、
    Ctrl.Parent = Panel2
の1行で処理が済んでしまったりしますか?

> 個人的には、親が子を処分する階層設計の方が好みですが。
その方が直感的にもいいなぁと思うのですが、前述の通り「Panel上のPictureBoxをクリックした時」の処理として考えると、他の記述方法が思いつかなかったのです。

色々と参考になりました。ありがとうございました。

引用返信 編集キー/
■84208 / inTopicNo.4)  Re[3]: vbのaddとremoveについて
□投稿者/ Azulean (824回)-(2017/05/31(Wed) 06:23:01)
No84207 (KAZ さん) に返信
> Sub Test(略) Handles PictrueBox.Click
> Dim Ctrl as Control = Ctype(sender,Control)
> Me.Panel1.Controls.Remove(Ctrl)
> Ctrl.Dispose()
> Me.Panel2.Controls.Add(Ctrl)
> End Sub

これはダメです。
Dispose はそのインスタンスを二度と利用しないことを宣言するようなものですから、Add するつもりなら Dispose してはいけません。

魔界の仮面弁士さんが言われていたのは「Remove して二度と利用しない場合は、必ず Dispose しておく必要があります」ということです。


> ???もしかして、前述のようなコードではなく、
> Ctrl.Parent = Panel2
> の1行で処理が済んでしまったりしますか?

そうなります。
引用返信 編集キー/
■84209 / inTopicNo.5)  Re[4]: vbのaddとremoveについて
□投稿者/ KAZ (3回)-(2017/05/31(Wed) 09:07:07)
No84208 (Azulean さん) に返信
早速の返信ありがとうございます。

> これはダメです。
> Dispose はそのインスタンスを二度と利用しないことを宣言するようなものですから、Add するつもりなら Dispose してはいけません。
> 魔界の仮面弁士さんが言われていたのは「Remove して二度と利用しない場合は、必ず Dispose しておく必要があります」ということです。
訂正ありがとうございます。つまり、あるインスタンス(という表現であってますかね?)に対して
 ○Add → 設置場所(.Parent)を設定する
 ○Remove → 設置場所(.Parent)をリセットする(ゴミ箱に移動)
 ○Dispose → インスタンスを廃棄する(ゴミ箱から消去する)
 ○.Parentを直接設定 → 設置場所(.Parent)を変更する(フォルダーの移動)
こんなイメージでよろしいでしょうか。そうすると下記にもある通り当初の処理のままでも問題なさそうですね。

>>???もしかして、前述のようなコードではなく、
>> Ctrl.Parent = Panel2
>>の1行で処理が済んでしまったりしますか?
> そうなります。
引用返信 編集キー/
■84210 / inTopicNo.6)  Re[3]: vbのaddとremoveについて
□投稿者/ 魔界の仮面弁士 (1296回)-(2017/05/31(Wed) 09:51:25)
No84207 (KAZ さん) に返信
> きちんとした処理にするなら、
Azulean さんが補足してくださったように、このケースでは、
PictureBox1 を破棄(Dispose)してはいけません。
Dispose してしまうと、そのオブジェクトは再利用できなくなります。


> ???もしかして、前述のようなコードではなく、
> Ctrl.Parent = Panel2
> の1行で処理が済んでしまったりしますか?

その通りです。親コンテナを Panel1 から Panel2 に変更するだけなら、
Controls コレクションの操作は不要で、単純に
 PictureBox1.Parent = Panel2
の一行だけで OK です。

もしくは、
 Panel2.Controls.Add(PictureBox1)
という一行でも構いません。


しかも親コンテナの差し替え時には、事前に Remove する必要すらありません。
PictureBox1 が Panel2 上に再配置される際には、
自動的に Panel1.Controls への割り当ても解除される仕様です。



> Panel2→Panel1の場合があるので、もう一工夫必要だとは思いますが。
こういうことですかね?

Private Sub PictureBoxes_Click(sender As PictureBox, e As EventArgs) Handles PictureBox1.Click, PictureBox2.Click
 If sender.Parent Is Panel1 Then
  sender.Parent = Panel2
 ElseIf sender.Parent Is Panel2 Then
  sender.Parent = Panel1
 End If
 sender.BringToFront() 'sender を一番手前に配置
End Sub

ちなみに、最後の sender.BringToFront() を呼ばなかった場合、sender は最奥側に配置されます。
(親コンテナを書き換えた直後は、sender.SendToBack() が呼ばれた状態になっているため)



>>> Ctrl.parent.Contrls.Remove(Ctrl)
>> If Ctrl.Parent IsNot Nothing Then
> 今回に関してはPanelが削除される心配はないので必要ないですが、
「Panel が削除される」ケースよりも、
「Panel から Control が取り除かれたタイミング」を心配していました。

もちろん、その心配が無いのであれば Nothing チェックも不要です。



> 「Panel上のPictureBoxをクリックした時」の処理として考えると、他の記述方法が思いつかなかったのです。

「クリックした時」の処理を Form1 上に書くのであれば、
いずれを基点とした記述方法でも大差無いと思います。
Form1 にとってみれば、Panel1 も PictureBox1 も等しく管理対象ですので。


これがたとえば、コントロールの GenerateMenber というデザイン時プロパティを False にして、
親から直接、コントロール変数名でアクセスできないようにしていた場合であるとか、あるいは
Panel や PictureBox を継承したコントールを作り、それらの OnClick をオーバーライドして
処理していたような場合であれば、親が子を管理するのか、子が親を操作するのかまで
考慮した方が良いかも知れませんが。
引用返信 編集キー/
■84212 / inTopicNo.7)  Re[4]: vbのaddとremoveについて
□投稿者/ KAZ (4回)-(2017/05/31(Wed) 12:43:13)
No84210 (魔界の仮面弁士 さん) に返信
度々のご指摘ありがとうございます。

> Azulean さんが補足してくださったように、このケースでは、PictureBox1 を破棄(Dispose)してはいけません。
> Dispose してしまうと、そのオブジェクトは再利用できなくなります。
学びました。

>>    Ctrl.Parent = Panel2
>>の1行で処理が済んでしまったりしますか?
> その通りです。親コンテナを Panel1 から Panel2 に変更するだけなら、Controls コレクションの操作は不要で、単純に
>  PictureBox1.Parent = Panel2
> の一行だけで OK です。
> しかも親コンテナの差し替え時には、事前に Remove する必要すらありません。PictureBox1 が Panel2 上に再配置される際には、
> 自動的に Panel1.Controls への割り当ても解除される仕様です。
学びました。

>>Panel2→Panel1の場合があるので、もう一工夫必要だとは思いますが。
> こういうことですかね?
> Private Sub PictureBoxes_Click(sender As PictureBox, e As EventArgs) Handles PictureBox1.Click, PictureBox2.Click
>  If sender.Parent Is Panel1 Then
>   sender.Parent = Panel2
>  ElseIf sender.Parent Is Panel2 Then
>   sender.Parent = Panel1
>  End If
>  sender.BringToFront() 'sender を一番手前に配置
> End Sub
そうです。こんな感じです。変数で 1→2・2→1 なら i=3-i とかで済むんですが、インスタンスだとやっぱり無理ですよね。
Panelも2択なので素直に上記を使わせて頂きます。

>>今回に関してはPanelが削除される心配はないので必要ないですが、
> 「Panel が削除される」ケースよりも、「Panel から Control が取り除かれたタイミング」を心配していました。
これは目から鱗でした。主観的な解釈になりますが、この場合の If Ctrl.Parent IsNot Nothing Then は
 × 「Ctrl の Parent(親コントロール) が存在する」の判定
 ○ 「Ctrl.Parent(プロパティ) の値が Nothing」の判定
ということですよね。

> これがたとえば、コントロールの GenerateMenber というデザイン時プロパティを False にして、
> 親から直接、コントロール変数名でアクセスできないようにしていた場合であるとか、あるいは
> Panel や PictureBox を継承したコントールを作り、それらの OnClick をオーバーライドして
> 処理していたような場合であれば、親が子を管理するのか、子が親を操作するのかまで
> 考慮した方が良いかも知れませんが。
ご忠告ありがとうございます。文面の60%ぐらいしか理解できてないと思いますが、字面でどんな操作なのかを把握できたとは思います。


お二方の丁寧な説明を頂き、少し賢くなった気がするので、もう少しコードを進めてみようと思います。ありがとうございました。

解決済み
引用返信 編集キー/
■84213 / inTopicNo.8)  Re[5]: vbのaddとremoveについて
□投稿者/ 魔界の仮面弁士 (1297回)-(2017/05/31(Wed) 13:07:18)
# 解決済みマークはチェックしたままにしておきます。

No84212 (KAZ さん) に返信
> 変数で 1→2・2→1 なら i=3-i とかで済むんですが、インスタンスだとやっぱり無理ですよね。

配列や List(Of ) で管理すれば OK かと。
たとえばパネルを 3 枚にして、1→2→3→1→2→3→…と遷移させるならこんな感じです。

Private panels As New List(Of Control)()
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
 panels.Add(Panel1)
 panels.Add(Panel2)
 panels.Add(Panel3)
 panels.Add(Panel1) '1→2→3→1 と戻すため、最後にもう一度 Panel1 を加える
End Sub

Private Sub PictureBoxes_Click(sender As Object, e As EventArgs) Handles PictureBox1.Click, PictureBox2.Click, PictureBox3.Click
 Dim c = DirectCast(sender, Control)
 c.Parent = panels(panels.IndexOf(c.Parent) + 1)
 c.BringToFront()
End Sub


PictureBox の数が多い場合は、Handles 句で列挙するのではなく、
AddHandler で対処した方が良いかもしれません。


> これは目から鱗でした。主観的な解釈になりますが、この場合の If Ctrl.Parent IsNot Nothing Then は
>  × 「Ctrl の Parent(親コントロール) が存在する」の判定
>  ○ 「Ctrl.Parent(プロパティ) の値が Nothing」の判定
> ということですよね。

Parent Is Nothing なら、「まだ親コントロール上に配置されていない状態」を意味しますし、
Parent IsNot Nothing や Not Parent Is Nothing なら、配置済みということです。


親コントロール上に配置されていない状態というのは、すなわち
生成された直後のコントロールや、Controls.Remove された直後の子コントロールのことです。

たとえば、実行時にテキストボックスを動的生成して
 Dim newText As New TextBox() With {.Text = "Sample"}
などとした場合、他のコントロール(Form や Panel など)の上に配置されるまで、
newText.Parent が Nothing の状態になっているわけです。
解決済み
引用返信 編集キー/
■84214 / inTopicNo.9)  Re[6]: vbのaddとremoveについて
□投稿者/ KAZ (5回)-(2017/05/31(Wed) 20:39:40)
No84213 (魔界の仮面弁士 さん) に返信
> # 解決済みマークはチェックしたままにしておきます。
追加説明ありがとうございます。


>>変数で 1→2・2→1 なら i=3-i とかで済むんですが、インスタンスだとやっぱり無理ですよね。
> 配列や List(Of ) で管理すれば OK かと。
List関数ですか。。。使ったことなかったので、これを機会にコードを研究してみたいと思います。イメージとしては、変数の配列(Array())に対して、
コントロールの配列って感じですかね。扱いが変数の配列と同様であればマスターできそうな予感がします。

> PictureBox の数が多い場合は、Handles 句で列挙するのではなく、
> AddHandler で対処した方が良いかもしれません。
今回の質問では、内容を抽出していたので PictureBox が少数でしたが、PanelもPictureBoxも両手でありあまるほどの量を考えているので、大変参考になりました。
ホントにありがとうございます。
最後に、理解が悪くて申し訳ないんですが、Remove には Dispose がつきもので、廃棄に必要な事は学びましたが、Ctrl.Clear とした場合は Dispose は必要ないのでしょうか?


>>これは目から鱗でした。主観的な解釈になりますが、この場合の If Ctrl.Parent IsNot Nothing Then は
>> × 「Ctrl の Parent(親コントロール) が存在する」の判定
>> ○ 「Ctrl.Parent(プロパティ) の値が Nothing」の判定
>>ということですよね。
> Parent Is Nothing なら、「まだ親コントロール上に配置されていない状態」を意味しますし、
> Parent IsNot Nothing や Not Parent Is Nothing なら、配置済みということです。
> たとえば、実行時にテキストボックスを動的生成して
>  Dim newText As New TextBox() With {.Text = "Sample"}
> などとした場合、他のコントロール(Form や Panel など)の上に配置されるまで、
> newText.Parent が Nothing の状態になっているわけです。
イメージとして Ctrl.Parent が示すものは Control だと思っていたので、これが単なるプロパティなんだというのはホントに目鱗でした。
ネットとか参考書とかで独学を進めてきたものの、他の方の見方を教えてもらえて、少しは視野が広くなる思いです。
また行き詰ったら質問をしたいと思いますので、今後ともよしなにお願いいたします。

解決済み
引用返信 編集キー/
■84219 / inTopicNo.10)  Re[7]: vbのaddとremoveについて
□投稿者/ 魔界の仮面弁士 (1300回)-(2017/06/01(Thu) 00:05:57)
# 追加質問があったようなので、解決済みチェックを外しておきます。

No84214 (KAZ さん) に返信
>>配列や List(Of ) で管理すれば OK かと。
> List関数ですか。。。
List は関数ではありません。ジェネリックなクラスです。

配列はコレクションの一種です。List もコレクションです。
Controls プロパティの戻り値もコレクションですね。



> 扱いが変数の配列と同様であればマスターできそうな予感がします。
配列でも同じことができますね。

Private panels() As Control
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
  panels = New Control() {Panel1, Panel2, Panel3, Panel1}
End Sub
Private Sub PictureBoxes_Click(sender As Object, e As EventArgs) Handles PictureBox1.Click, PictureBox2.Click, PictureBox3.Click
  Dim c As Control = DirectCast(sender, Control)
  Dim i As Integer = Array.IndexOf(panels, sender)
  c.Parent = panels(i + 1)
  c.BringToFront()
End Sub


> イメージとして Ctrl.Parent が示すものは Control だと思っていたので、これが単なるプロパティなんだというのはホントに目鱗でした。
はい。Parent プロパティが示すものは Control クラスです。


ご存知のように、Panel や Form では、その上に他のコントロール(Button など)を
載せることができるわけですが、やろうと思えば Form の上に Button を貼るのではなく、
その逆に Button の上に Form を貼ることさえできます。

以下サンプル。Button1 は少し大きめに貼っておいてください。

 Dim f As New Form()
 f.TopLevel = False
 f.Parent = Button1  'または Button1.Controls.Add(f)
 f.Show()

といっても、実際にのような画面デザインが必要になる機会はそうそう無いでしょうけれどね。


> Remove には Dispose がつきもので、廃棄に必要な事は学びましたが、Ctrl.Clear とした場合は Dispose は必要ないのでしょうか?

Ctrl.Clear ではなく、Controls.Clear ですよね?

Ctrl.Clear というと、たとえば TextBox1.Clear() などが該当するかと思います、
たとえばこの場合は「TextBox1.Text = Nothing」と同義であり、Dispose とは無関係です。

一方、Panel1.Controls.Clear() の場合は、先の回答でも述べましたように、
かつて Panel1 上に載っていた子コントロール達を Dispose する責務があります。
(それらの子コントールを Panel1 以外に載せ直して再利用するという場合は Dispose は不要ですが)


具体的にはこんな感じ。

 'Panel1 の上に載っていたコントロールへの参照を、配列に退避しておく
 Dim children = Panel1.Controls.OfType(Of Control)().ToArray()
 
 'Panel1 の上に載っていたすべての子コントロールを取り除く
 Panel1.Controls.Clear()
 
 'Clear しただけでは、それらの子コントロールは Dispose されないので
 'それぞれ Dispose しておかなければならない
 For Each child In children
   child.Dispose()
 Next


改めて、コントロールの Dispose について整理してみますと:


(1) 生成されたコントロールは、『使い終わった時点で』必ず Dispose しなければなりません。
 (引き続き使用されるコントロールについては、まだ Dispose で処分してはいけません)
 なお、ここでいうコントロールとは、System.Windows.Forms.Control を継承したクラスを指します。

(2) 今回の Panel と PictureBox のように、親子関係にあるコントロールの場合、
 親が Dispose された時点で、子も自動的に Dispose される仕様です。
 (再帰的に処理されますので、子が Dispose されれば 孫も Dispose されます)

(3) そして Form もコントロールの一種であるため、フォームが破棄された時点で
 フォーム上に貼られていたコントロールも一緒に破棄されます。

(4) そのため、通常の使い方をしている分には、各コントロールの Dispose を明示的に呼ぶ必要は生じません。
 しかし、Contols.Clear() を呼んでいたり、Parent = Nothing などを実行していた場合には、
 その親子関係が切れてしまった状態となるため、個別に Dispose して処分する必要が生じるというわけです。

(5) なお、Form がモードレス表示されていた場合、Form が閉じられる際に、直ちに Dispose されるようになっています。
 モードレスな Form とは、Show メソッドで表示されたフォームやスタートアップフォームのことです。

(6) 一方、Form がモーダル表示されていた場合、Form が閉じられたとしても、直ちに Dispose されませんので、
 Form を呼び出した側で、明示的に Dispose しなければなりません。(Using ステートメントを使うと良いでしょう)
 なおモーダルな Form とは、ShowDialog メソッドで表示された Form のことです。
引用返信 編集キー/
■84223 / inTopicNo.11)  Re[8]: vbのaddとremoveについて
□投稿者/ KAZ (6回)-(2017/06/01(Thu) 11:07:19)
No84219 (魔界の仮面弁士 さん) に返信
> # 追加質問があったようなので、解決済みチェックを外しておきます。
詳細な説明ありがごうございます。


>>扱いが変数の配列と同様であればマスターできそうな予感がします。
> 配列でも同じことができますね。
追加はAdd、呼び出しは引数、探索はIndexOf、下記にあるのを見ると廃棄はDisposeあたりですね。

>>Remove には Dispose がつきもので、廃棄に必要な事は学びましたが、Ctrl.Clear とした場合は Dispose は必要ないのでしょうか?
> Ctrl.Clear ではなく、Controls.Clear ですよね?
そうです。Ctrl.Controls.Clearですね。

> Panel1.Controls.Clear() の場合は、先の回答でも述べましたように、
> かつて Panel1 上に載っていた子コントロール達を Dispose する責務があります。
> (それらの子コントールを Panel1 以外に載せ直して再利用するという場合は Dispose は不要ですが)
やっぱり必要なんですね。学びました。

>  'Panel1 の上に載っていたコントロールへの参照を、配列に退避しておく
>  Dim children = Panel1.Controls.OfType(Of Control)().ToArray()
>  'Panel1 の上に載っていたすべての子コントロールを取り除く
>  Panel1.Controls.Clear()
>  'Clear しただけでは、それらの子コントロールは Dispose されないので
>  'それぞれ Dispose しておかなければならない
>  For Each child In children
>    child.Dispose()
>  Next
Panel上のコントロール全体をDisposeするのに For Each が使えないと思っていたのですが、こんなやり方があるんですね。
実際、最後の3行だけで実行すると半分しかDisposeされないからClearって便利だなとか思ってたんですが、結局Disposeの必要性はあるみたいですし。
あきらめて、親コントロールを一旦Disposeして再度作りなおすとかしなきゃと思ってました。


> 改めて、コントロールの Dispose について整理してみますと:
詳しくまとめていただきありがとうございます。まだまだ使い勝手に慣れてないので、実際に入力・デバッグをしながら学びたいと思います。

解決済み
引用返信 編集キー/
■84225 / inTopicNo.12)  Re[9]: vbのaddとremoveについて
□投稿者/ 魔界の仮面弁士 (1304回)-(2017/06/01(Thu) 11:33:47)
No84223 (KAZ さん) に返信
>>> 扱いが変数の配列と同様であればマスターできそうな予感がします。
>> 配列でも同じことができますね。
> 追加はAdd、呼び出しは引数、探索はIndexOf、下記にあるのを見ると廃棄はDisposeあたりですね。

配列や List は IDisposable インターフェイスを有していないので
Dispose メソッドはありません。
廃棄しているのは配列や List ではなく、そこに格納されている Control 達です。


> 実際、最後の3行だけで実行すると半分しかDisposeされないから

コレクションの列挙中に、Add や Remove することは厳禁ですね。

 ' これは NG
 For Each c As Control In Panel1.Controls
   Panel1.Controls.Remove(c) 'または「c.Parent = Nothing」
   c.Dispose()
 Next


しかし、下記のように列挙すれば大丈夫です。
これらの方法であれば、削除前に配列に事前退避しておく必要もなくなります。

 '案1:常に 0 番目のコントロールを処分し続ける
 Do Until Panel1.Controls.Count = 0
  Using c = Panel1.Controls(0)
   Panel1.Controls.RemoveAt(0)
  End Using
 Loop

 '案2:コレクションの末尾から先頭方向に破棄していく
 For n As Integer = Panel1.Controls.Count - 1 To 0 Step -1
  Using c = Panel1.Controls(n)
   Panel1.Controls.RemoveAt(n)
  End Using
 Next


> Clearって便利だなとか思ってたんですが、結局Disposeの必要性はあるみたいですし。

Panel1.Controls.Clear() だけで Dispose されるようにすることもできます。

 Private Sub Panel1_ControlRemoved(sender As Object, e As ControlEventArgs) Handles Panel1.ControlRemoved
   e.Control.Dispose()
 End Sub


ただし上記は、Clear 後、即座に子コントロールを Dispose して良い場合に限ります。
当初の目的のように、
  PictureBox1.Parent = Panel2
などとする可能性がある場合は、フラグ判定等で回避する必要があるでしょう。
解決済み
引用返信 編集キー/
■84226 / inTopicNo.13)  Re[10]: vbのaddとremoveについて
□投稿者/ KAZ (7回)-(2017/06/01(Thu) 14:40:21)
No84225 (魔界の仮面弁士 さん) に返信

> 配列や List は IDisposable インターフェイスを有していないので Dispose メソッドはありません。
> 廃棄しているのは配列や List ではなく、そこに格納されている Control 達です。
配列の要素を廃棄するってことですよね。理解できてると思います。


> コレクションの列挙中に、Add や Remove することは厳禁ですね。
> しかし、下記のように列挙すれば大丈夫です。
> これらの方法であれば、削除前に配列に事前退避しておく必要もなくなります。
書いた後、気になって別のサイトも調べたら、8年程前に似たような質問をしてる方がいて。。。お答えになっていた方が同じ名前でしたが(笑)
この手の事が苦手なのが私だけではなくて安心しました。

>>実際、最後の3行だけで実行すると半分しかDisposeされないから
>  '案2:コレクションの末尾から先頭方向に破棄していく
>  For n As Integer = Panel1.Controls.Count - 1 To 0 Step -1
>   Using c = Panel1.Controls(n)
>    Panel1.Controls.RemoveAt(n)
>   End Using
>  Next
そうです、そうです。これがしたかったのです。でも、Controls に対してインデックスを付ける位置がわからなくて断念してました。
特に Dim とかで明示しなくても、Control.Controls()←ここにインデックスを入れれば大丈夫なんですね。
どうもコントロールの扱いがなれていなくて、A は単数、A(n) は配列で複数っていう表記上のルールに捕らわれていて、Controls の表記だと
インデックスを付ける場所がないと思っていました。
何かとアフターサービスまで頂き、ありがとうございました。


解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -