※この記事は【VB6・VB】古いコードのリプレース のシリーズその1です。
その1 コントロール配列(VB6)
まあVB6ではよくあるパターン。むしろ無いほうが珍しい。
VB6には表みたいな機能がろくになかったので、表のようにラベルやテキストをコントロール配列でぺたぺた貼ってぐるぐる回して処理してたんですよねー。
##対処法:手動で配列にセットして処理する。
※以下、"Button1","Button2","Button3"という名前のボタンコントロール3つが画面で宣言されており、
これをコントロール配列として扱いたいとする。
Private BtnArray() As Button 'セットする配列
Public Sub Form1_Load() Handles Me.Load
InitializeComponent()
'順番を考慮して配列にセットする必要がある
BtnArray = {Button1, Button2, Button3}
'イベントをまとめたい場合、ForEachで回す以外方法がない
For Each Btn In BtnArray
AddHandler Btn.Click, AddressOf Me.testButtons_Click
Next
End Sub
Private Sub testButtons_Click(ByVal sender As Object,ByVal e As EventArgs)
'イベント内で配列の何番目かを取得するには、実際に配列の中身を探しに行かなくてはいけない
Dim index As Integer = Array.IndexOf(BtnArray, CType(sender, Button))
End Sub
private Button[] BtnArray;//セットする配列
public Form1()
{
InitializeComponent();
//順番を考慮して配列にセットする必要がある
BtnArray = new Button[] { Button1, Button2, Button3 };
//イベントをまとめたい場合、ForEachで回す以外方法がない
foreach (Button Btn in BtnArray)
{
Btn.Click += new EventHandler(testButtons_Click);
}
}
private void testButtons_Click(object sender, EventArgs e)
{
//イベント内で配列の何番目かを取得するには、実際に配列の中身を探しに行かなくてはいけない
int index = Array.IndexOf(BtnArray, ((Button)sender));
}
大体はこれで解決するんですが、コメント内にあるように、いくつか注意点があります。
2.イベントをまとめたい場合、ForEachで回す以外方法がない
3.イベント内で配列の何番目かを取得するには、実際に配列の中身を探しに行かなくてはいけない
以下、注意点について追記します。
####1.順番を考慮して配列にセットする必要がある
このうち1が多分一番面倒。場合によっては何百個も入れることになるので、手書きは辛い。
ということで以下に自動で配列に入れる例を紹介します。
特定の条件を満たすものを自動で配列に入れたい!
全て手動で配列に入れるにはたくさんあって面倒!
そういうときはこんな感じ。
Dim BtnList As New List(Of Button) 'セットするリスト
'フォーム内のすべてのコントロールを取得する
For Each con As Control In Me.Controls
'それがボタンである
If IsNothing(TryCast(con, Button)) = False Then
'それが特定の名前である
If con.Name Like "B*" Then
BtnList.Add(con)
End If
End If
Next
'タブインデックス順に並び替えて配列に入れる
BtnArray = BtnList.OrderBy(Function(p) p.TabIndex).ToArray
var BtnList = new List<Button>();//セットするリスト
//フォーム内のすべてのコントロールを取得する
foreach (Control con in this.Controls)
{
//それがボタンである
if (con is Button)
{
//それが特定の名前である
if (Regex.IsMatch(con.Name, "B*"))
{
BtnList.Add((Button)con);
}
}
}
//タブインデックス順に並び替える
BtnArray = BtnList.OrderBy(p => p.TabIndex).ToArray();
こうやって条件に合うコントロールだけを配列に入れていけば良い。
例では、"B"から始まるボタンコントロールをタブインデックス順に放り込んでいる。
*なお、Me.Controlsから取得するControlCollectionクラスはIEnumerable(Of T)を実装してないので全部まとめるのは無理。
追記:Me.ControlsはIEnumerable(Of T)は実装していませんが、IEnumerableは実装しています。
IEnumerableにはOfTypeやCastメソッドが用意されており、これはIEnumerable(Of T)を出力します。
そのため、以下のように全てラムダ式に書き換えることが可能です。
System.Linqを宣言しておくこと
BtnArray = Me.Controls.OfType(Of Button) _
.Where(Function(b) b.Name Like "B*") _
.OrderBy(Function(p) p.TabIndex).ToArray()
//c#にはLike文が無いので面倒
BtnArray = this.Controls.OfType<Button>()
.Where(p => System.Text.RegularExpressions.Regex.IsMatch(p.Name, "^B.*", RegexOptions.Singleline))
.OrderBy(q => q.TabIndex).ToArray();
####2.イベントをまとめたい場合、ForEachで回す以外方法がない
また、2.は割とどうしようもないです。
全てのイベントを取得し、そのうち使用されているものだけを探す…ような処理自体はあるみたいですが、かなりややこしいです。
結局1つ1つ書くほうが早いです。
####3.イベント内で配列の何番目かを取得するには、実際に配列の中身を探しに行かなくてはいけない
3.もこれ以上の短縮は面倒です。
どうしても短縮したい場合は、Indexを保存した拡張コントロールを作成して、それに全部差し替えることになると思います。
(TagやTabIndexなどに配列のインデックスとなる値を入れておくというズルはできますが、デザイナから変えられるため確実性が無い。)