LoginSignup
4
3

More than 3 years have passed since last update.

【VB6・VB】古いコードのリプレース その1 コントロール配列

Last updated at Posted at 2018-11-10

※この記事は【VB6・VB】古いコードのリプレース のシリーズその1です。

その1 コントロール配列(VB6)

まあVB6ではよくあるパターン。むしろ無いほうが珍しい。
VB6には表みたいな機能がろくになかったので、表のようにラベルやテキストをコントロール配列でぺたぺた貼ってぐるぐる回して処理してたんですよねー。

対処法:手動で配列にセットして処理する。

※以下、"Button1","Button2","Button3"という名前のボタンコントロール3つが画面で宣言されており、
これをコントロール配列として扱いたいとする。

Form.vb

    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
Form.cs
        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));
        }

大体はこれで解決するんですが、コメント内にあるように、いくつか注意点があります。

1.順番を考慮して配列にセットする必要がある

2.イベントをまとめたい場合、ForEachで回す以外方法がない

3.イベント内で配列の何番目かを取得するには、実際に配列の中身を探しに行かなくてはいけない

以下、注意点について追記します。


1.順番を考慮して配列にセットする必要がある

このうち1が多分一番面倒。場合によっては何百個も入れることになるので、手書きは辛い。
ということで以下に自動で配列に入れる例を紹介します。

特定の条件を満たすものを自動で配列に入れたい!
全て手動で配列に入れるにはたくさんあって面倒!

そういうときはこんな感じ。

VB:特定のコントロールだけコントロール配列に入れる
        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
c#:特定のコントロールだけコントロール配列に入れる
            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を宣言しておくこと

VB:全てラムダ式に
BtnArray = Me.Controls.OfType(Of Button) _
                      .Where(Function(b) b.Name Like "B*") _
                      .OrderBy(Function(p) p.TabIndex).ToArray()
c#:全てラムダ式に
//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などに配列のインデックスとなる値を入れておくというズルはできますが、デザイナから変えられるため確実性が無い。)

4
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3