LoginSignup
2
2

More than 3 years have passed since last update.

イベントハンドラまで対応したコントロール配列を作る

Last updated at Posted at 2019-11-25

只今絶賛VB6からVB.NET (VS2017)への移行作業中です。
移行作業で非互換となる機能の一つにコントロール配列があります。
Microsoft.VisualBasic.Compatibility.VB6互換ライブラリを使用すればいいのですが
Deprecatedというわけで使用禁止。

止む無くTextBoxのコントロール配列クラスを自作することとなりました。

目標は


public WithEvents Text1 As Microsoft.VisualBasic.Compatibility.VB6.TextBoxArray

public WithEvents Text1 As MyLib.TextBoxArray

のように置き換えるだけで済むクラスを作りたいというものです。
ネット検索では次のようなイベントハンドラにまで対応した例を見つけることが出来ませんでしたのでこれに対応するのが第一となります。

コントロール配列に対するイベントハンドラの例
'Text1はコントロール配列
Private Sub Text1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles Text1.KeyPress
    Console.WriteLine("KeyPress")
End Sub

クラスの定義は

Microsoft.VisualBasic.Compatibility.VB6.TextBoxArrayのドキュメント
https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.visualbasic.compatibility.vb6.textboxarray?view=netframework-4.8
および
Microsoft.VisualBasic.Compatibility.VB6.BaseControllArrayのドキュメント
https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.visualbasic.compatibility.vb6.basecontrolarray.hookupcontrolevents?view=netframework-4.8#Microsoft_VisualBasic_Compatibility_VB6_BaseControlArray_HookUpControlEvents_System_Object_

に準拠させるとして

Designer.vbファイルの中身

'中略
public WithEvents Text1 As Microsoft.VisualBasic.Compatibility.TextBoxArray
'中略
Me.Text1 = New  Microsoft.VisualBasic.Compatibility.TextBoxArray(Me.components)
'中略
CType(Me.Text1, System.ComponentModel.ISupportInitialize).BeginInit()
'中略

Me.Text1.SetIndex(Me._Text1_3, CType(3, Short))
Me.Text1.SetIndex(Me._Text1_2, CType(2, Short))
Me.Text1.SetIndex(Me._Text1_1, CType(1, Short))
Me.Text1.SetIndex(Me._Text1_0, CType(0, Short))
'中略
CType(Me.Text1, System.ComponentModel.ISupportInitialize).EndInit()
'中略

を参考に必要最小限に絞って作成した互換クラスが以下の通り
(ここに至るまで紆余曲折ありましたが全部省略)

BaseControlArray.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

namespace MyLib
{
    public abstract class BaseControlArray : Component, ISupportInitialize
    {
        // コントロール配列で管理するクラスをDictionaryに入れる
        // (Listとかに使用と思ったらインデックス-1で登録されてくるケースがあったので
        // Dictionaryにしました。)
        protected Dictionary<int, Control> items = new Dictionary<int, Control>();
        //  コントロール配列内のコントロール数を返します。
        public short Count()
        {
            return checked((short)this.items.Count);
        }

        // 何もしないがこれがないとコンパイルエラー
        public void BeginInit()
        {

        }

        // 何もしないがこれがないとコンパイルエラー
        public void EndInit()
        {

        }

        // 気持ちの問題か
        protected override void Dispose(bool disposing) 
        {
            if(disposing)
            {
                items.Clear();
            }
            base.Dispose(disposing);
        }
        // 必要かどうか迷ったが入れておく
        public short LBound()
        {
            return 0;
        }

        // 必要かどうか迷ったが入れておく
        public short UBound()
        {
            return (short)(items.Count - 1);
        }

        public IEnumerator GetEnumerator()
        {
            return items.GetEnumerator();
        }      
    }
}
TextBoxArray.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

namespace MyLib
{
    [ProvideProperty("Index", typeof(TextBox))]
    public class TextBoxArray : BaseControlArray, IExtenderProvider
    {
        // コンストラクタの中で何かする必要はなかった
        public TextBoxArray()
        {
        }
        // コンストラクタの中で何かする必要はなかった
        public TextBoxArray(IContainer Container)
        {
        }


        // KeyPressイベントハンドラ
        public event KeyPressEventHandler KeyPress;

        // 与えられたこのコントロール配列に入れることが出来るかどうかを返す
        public bool CanExtend(object extendee)
        {
            return extendee is TextBox;
        }
        // コントロール配列の型を返す
        protected Type GetControlInstanceType()
        {
            return typeof(TextBox);
        }

        // コントロール配列にコントロールを登録
        public void SetIndex(TextBox item, short index)
        {
            items[index] = item;
            // コントロール配列のイベントを個々のコントロールに結び付ける
            if (KeyPress != null) item.KeyPress += KeyPress;
        }

        public short GetIndex(TextBox item)
        {
            IEnumerator<KeyValuePair<int, Control>> enumerator = items.GetEnumerator();
            while (enumerator.MoveNext())
            {
                if (enumerator.Current.Value == item) return (short)enumerator.Current.Key;
            }
            return (short)0;
        }

        public TextBox this[short Index]
        {
            get
            {
                return (TextBox)items[Index];
            }
        }

    }
}

イベントハンドラはお好みで追加してください。
ほかの種類のコントロール配列はTextBoxArrayのコピペで行けると思います。

以上

2
2
0

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
2
2