.NETプログラミング研究 第31号 †
.NET Tips †
コントロールの配列を作成する †
コントロールの配列を作成する方法は、私の作成しているサイトDOBON.NETの.NET Tipsでは、「コントロールの配列を作成する」で説明しています。
ここで紹介している方法は、基本的にVS.NETのフォームデザイナを一切使わない方法です。このページをすでにご覧いただいた方には申し訳ありませんが、まずはこの方法を簡単に紹介させていただきます。
次のサンプルは、フォーム(Form1)にボタンコントロールの配列を作成し、ボタンをクリックするとそのボタンのTextを表示するものです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| | Friend testButtons(4) As System.Windows.Forms.Button
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Dim i As Integer
For i = 0 To 4
testButtons(i) = New System.Windows.Forms.Button()
testButtons(i).Text = i.ToString()
testButtons(i).Size = New Size(30, 30)
testButtons(i).Location = New Point(i * 30, 10)
AddHandler testButtons(i).Click, AddressOf Me.testButtons_Click
Next
Me.Controls.AddRange(testButtons)
End Sub
Private Sub testButtons_Click(ByVal sender As System.Object, ByVal e As EventArgs)
MsgBox(sender.Text)
End Sub
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| | private System.Windows.Forms.Button[] testButtons =
new System.Windows.Forms.Button[5];
private void Form1_Load(object sender, System.EventArgs e)
{
for (int i = 0; i < 5; i++)
{
testButtons[i] = new System.Windows.Forms.Button();
testButtons[i].Text = i.ToString();
testButtons[i].Size = new Size(30, 30);
testButtons[i].Location = new Point(i * 30, 10);
testButtons[i].Click += new EventHandler(testButtons_Click);
}
this.Controls.AddRange(testButtons);
}
private void testButtons_Click(object sender, EventArgs e)
{
MessageBox.Show(((System.Windows.Forms.Button) sender).Text);
}
|
また、VS.NETのフォームデザイナで追加してあるコントロールを配列にする例として、次のようなサンプルも紹介しています。ここではフォームデザイナでフォームにボタンコントロールが5つ(Button1〜5)追加されており、それらを配列に入れています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| | Private testButtons(4) As System.Windows.Forms.Button
Private Sub Form1_Load(sender As Object, e As System.EventArgs)
Handles MyBase.Load
testButtons(0) = Button1
testButtons(1) = Button2
testButtons(2) = Button3
testButtons(3) = Button4
testButtons(4) = Button5
Dim i As Integer
For i = 0 To 4
AddHandler testButtons(i).Click, AddressOf testButtons_Click
Next i
End Sub
Private Sub testButtons_Click(sender As Object, e As EventArgs)
MessageBox.Show(CType(sender, System.Windows.Forms.Button).Text)
End Sub
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| | private System.Windows.Forms.Button[] testButtons =
new System.Windows.Forms.Button[5];
private void Form1_Load(object sender, System.EventArgs e)
{
testButtons[0] = Button1;
testButtons[1] = Button2;
testButtons[2] = Button3;
testButtons[3] = Button4;
testButtons[4] = Button5;
for (int i = 0; i < 5; i++)
testButtons[i].Click += new EventHandler(testButtons_Click);
}
private void testButtons_Click(object sender, EventArgs e)
{
MessageBox.Show(((System.Windows.Forms.Button) sender).Text);
}
|
以上が今まで私のサイトで紹介していた方法でした。しかしこれらの方法はVB6ユーザーの方には扱いにくいようで、掲示板には相変わらずコントロール配列に関する質問が多く寄せられます。
そこで新たな第3の方法を考えてみました。前号で紹介した「フォームに配置されているコントロールを名前で探すには?」の方法を使い、「"特定の名前" + "1から連続する数字"」という名前を持つコントロールを配列にするメソッドを作ってみます。このメソッドは、例えばフォームに"TextBox1"、"TextBox2"、"TextBox3"...という名前の複数のTextBoxコントロールがあったとき、"TextBox"という文字列を指定することにより、TextBoxコントロールの配列を返すという機能を持ちます。(ただし、"TextBox1"のインデックスが0になります。また、数字が連続しており、途中が抜けたりしていない必要があります。)
以下にコントロール配列を作成するメソッド"GetControlArrayByName"を示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
| | Public Function GetControlArrayByName(ByVal name As String) As Object
Dim ctrs As New System.Collections.ArrayList
Dim obj As Object
Dim i As Integer = 1
While True
obj = FindControlByFieldName(name + i.ToString())
i += 1
If obj Is Nothing Then
Exit While
Else
ctrs.Add(obj)
End If
End While
If ctrs.Count = 0 Then
Return Nothing
Else
Return ctrs.ToArray(ctrs(0).GetType())
End If
End Function
Public Function FindControlByFieldName(ByVal name As String) As Object
Dim t As System.Type = Me.GetType()
Dim pi As System.Reflection.PropertyInfo = _
t.GetProperty(name, _
System.Reflection.BindingFlags.Public Or _
System.Reflection.BindingFlags.NonPublic Or _
System.Reflection.BindingFlags.Instance Or _
System.Reflection.BindingFlags.DeclaredOnly)
If Not pi Is Nothing Then
Return pi.GetValue(Me, Nothing)
End If
Dim fi As System.Reflection.FieldInfo = _
t.GetField(name, _
System.Reflection.BindingFlags.Public Or _
System.Reflection.BindingFlags.NonPublic Or _
System.Reflection.BindingFlags.Instance Or _
System.Reflection.BindingFlags.DeclaredOnly)
If fi Is Nothing Then
Return Nothing
End If
Return fi.GetValue(Me)
End Function
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| | public object GetControlArrayByName(string name)
{
System.Collections.ArrayList ctrs =
new System.Collections.ArrayList();
object obj;
for (int i = 1;
(obj = FindControlByFieldName(name + i.ToString())) != null;
i++)
ctrs.Add(obj);
if (ctrs.Count == 0)
return null;
else
return ctrs.ToArray(ctrs[0].GetType());
}
public object FindControlByFieldName(string name)
{
System.Type t = this.GetType();
System.Reflection.FieldInfo fi = t.GetField(
name,
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.DeclaredOnly);
if (fi == null)
return null;
return fi.GetValue(this);
}
|
このGetControlArrayByNameメソッドは、配列にしたいコントロールのあるフォームのクラスのメソッドとして記述します。
以下に具体的な使用法を示します。ここではフォーム(Form1)にテキストボックスコントロール"TextBox1"、"TextBox2"、"TextBox3"と、さらに同じ数のボタンコントロール"Button1"、"Button2"、"Button3"があるものとし、これらのコントロールをGetControlArrayByNameメソッドで配列(textBoxArrayとbuttonArrayフィールド)にしています(インデックス番号は"TextBox1"が0、"TextBox2"が1、"TextBox3"が2となります)。ボタンコントロールをクリックすると、同じインデックスのテキストボックスのTextを表示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| | Dim textBoxArray() As TextBox
Dim buttonArray() As Button
Private Sub Form1_Load(ByVal sender As Object, _
ByVal e As EventArgs) Handles MyBase.Load
textBoxArray = _
CType(GetControlArrayByName("TextBox"), TextBox())
buttonArray = _
CType(GetControlArrayByName("Button"), Button())
Dim btn As Button
For Each btn In buttonArray
AddHandler btn.Click, AddressOf Button_Click
Next btn
End Sub
Private Sub Button_Click( _
ByVal sender As Object, ByVal e As EventArgs)
Dim index As Integer = -1
Dim i As Integer
For i = 0 To buttonArray.Length - 1
If buttonArray(i).Equals(sender) Then
index = i
Exit For
End If
Next i
If index > -1 Then
MessageBox.Show(textBoxArray(index).Text)
End If
End Sub
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| | TextBox[] textBoxArray;
Button[] buttonArray;
private void Form1_Load(object sender, System.EventArgs e)
{
textBoxArray = (TextBox[]) GetControlArrayByName("TextBox");
buttonArray = (Button[]) GetControlArrayByName("Button");
foreach (Button btn in buttonArray)
btn.Click += new EventHandler(Button_Click);
}
private void Button_Click(object sender, EventArgs e)
{
int index = -1;
for (int i = 0; i < buttonArray.Length; i++)
{
if (buttonArray[i].Equals(sender))
{
index = i;
break;
}
}
if (index > -1)
{
MessageBox.Show(textBoxArray[index].Text);
}
}
|
.NET質問箱 †
「.NET質問箱」では、「どぼん!のプログラミング掲示板」に書き込まれた.NETプログラミングに関する投稿をQ&A形式にまとめ、紹介します。
SmtpMailクラスでメールを送るとQuoted-Printableでエンコードされる †
【質問】
SmtpMailクラスのSendメソッドを使用してメールを送ると、メールがQuoted-Printableでエンコードされることがあります。なぜでしょうか?
【回答】
SmtpMailクラスはCDOSYS(Collaboration Data Objects for Windows 2000)メッセージコンポーネントを使用してメールを送信しますが、なかさんからのご報告によると、マイクロソフトサポート技術情報412833の「[IIS]CDONTSで送信するメールがQuoted-Printableでエンコードされる」で説明されているのと同じことがCDOSYSでも起こるようです。
サポート技術情報412833での説明によると、メール本文の1行の文字数が76バイト以上になることが予想される場合、Quoted-Printableを適用し、転送時のみ75バイト以内に折り返す仕様になっているということです。さらに、なかさんからのご報告によると、半角文字と全角文字を何回か繰り返した場合もエンコードされるそうです(また同じ内容のメールであっても環境によって、エンコードされたりされなかったりすることがあるそうです)。
サポート技術情報412833で提示されている解決法は、あらかじめメールの本文をチェックし、一行が75バイト以下になるように改行を入れておくというものです。
この解決法が適切なのだろうと思いますが、なかさんからのご報告では、メールメッセージの"Content-Transfer-Encoding"ヘッダを"7bit"に変更すると、Quoted-Printableエンコードされなくなったとのことです。
"Content-Transfer-Encoding"ヘッダを"7bit"に変更してメールを送信する例を以下に示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| | Dim mm As New System.Web.Mail.MailMessage()
mm.From = "sender@xxx.xx.com"
mm.To = "recipient1@xxx.xx.com"
mm.Subject = "テスト"
mm.Body = "こんにちは。これはテストです。"
mm.BodyEncoding = System.Text.Encoding.GetEncoding(50220)
mm.Headers("Content-Transfer-Encoding") = "7bit"
System.Web.Mail.SmtpMail.SmtpServer = "(SMTPサーバーを指定する)"
System.Web.Mail.SmtpMail.Send(mm)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| | System.Web.Mail.MailMessage mm = new System.Web.Mail.MailMessage();
mm.From = "sender@xxx.xx.com";
mm.To = "recipient1@xxx.xx.com";
mm.Subject = "テスト";
mm.Body = "こんにちは。これはテストです。";
mm.BodyEncoding = System.Text.Encoding.GetEncoding(50220);
mm.Headers("Content-Transfer-Encoding") = "7bit";
System.Web.Mail.SmtpMail.SmtpServer = "(SMTPサーバーを指定する)";
System.Web.Mail.SmtpMail.Send(mm);
|
○この記事の基になった掲示板のスレッド
「印刷中...」ダイアログを表示しないようにするには? †
【質問】
PrintDocumentクラスのPrintメソッドで印刷をすると、「印刷中...」というダイアログが表示されますが、このダイアログを表示させない方法はありませんか?
【回答】
PrintDocumentクラスのPrintControllerプロパティはデフォルトではPrintControllerWithStatusDialogオブジェクトとなっていますが、これをStandardPrintControllerに変更することにより、「印刷中...」ダイアログを表示することなく印刷できるようになります。
なお、プリントコントローラに関しては、ヘルプをご覧ください。
またこの方法ではPrintPreviewDialogなど印刷プレビューに表示させる時に表示されるダイアログは消すことができません。(この場合にダイアログを表示させない方法は現在不明です。)
「印刷中...」ダイアログを表示せずに印刷をする例を示します。この例は、フォームにあるボタン(Button1)をクリックすると、ページ余白の内側の部分いっぱいに画像'test.bmp'を表示するものです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| | Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim pd As New System.Drawing.Printing.PrintDocument
pd.PrintController = _
New System.Drawing.Printing.StandardPrintController
AddHandler pd.PrintPage, AddressOf pd_PrintPage
pd.Print()
End Sub
Private Sub pd_PrintPage(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintPageEventArgs)
Dim img As Image = Image.FromFile("test.bmp")
e.Graphics.DrawImage(img, e.MarginBounds)
e.HasMorePages = False
img.Dispose()
End Sub
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| | private void button1_Click(object sender, System.EventArgs e)
{
System.Drawing.Printing.PrintDocument pd =
new System.Drawing.Printing.PrintDocument();
pd.PrintController =
new System.Drawing.Printing.StandardPrintController();
pd.PrintPage +=
new System.Drawing.Printing.PrintPageEventHandler(pd_PrintPage);
pd.Print();
}
private void pd_PrintPage(object sender,
System.Drawing.Printing.PrintPageEventArgs e)
{
Image img = Image.FromFile("test.bmp");
e.Graphics.DrawImage(img, e.MarginBounds);
e.HasMorePages = false;
img.Dispose();
}
|
○この記事の基になった掲示板のスレッド
コメント †