只今絶賛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()
'中略
を参考に必要最小限に絞って作成した互換クラスが以下の通り
(ここに至るまで紆余曲折ありましたが全部省略)
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();
}
}
}
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のコピペで行けると思います。
以上