C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

ContextMenuStripで引数を渡す方法

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■91956 / inTopicNo.1)  ContextMenuStripで引数を渡す方法
  
□投稿者/ CCCO (1回)-(2019/08/14(Wed) 21:58:11)

分類:[.NET 全般] 

ContextMenuStripで同じSubを使って引数だけを変えたいと思います

以下のような感じです


    Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load

        Me.ContextMenuStrip1.Items.Add("Test1", Nothing, New EventHandler(AddressOf test(1)))
        Me.ContextMenuStrip1.Items.Add("Test2", Nothing, New EventHandler(AddressOf test(2)))


        PictureBox1.ContextMenuStrip = Me.ContextMenuStrip1


    End Sub


    Private Sub test(i As Integer)


    End Sub


しかし、

エラー	BC30577	'AddressOf' オペランドはメソッドの名前でなければなりません。かっこは不要です。

というエラーが出てしまいます。
括弧を外して、カンマ区切りにしてもやはりエラーが出ます

どのようにすれば引数を受け取ってくれますでしょうか?



引用返信 編集キー/
■91957 / inTopicNo.2)  Re[1]: ContextMenuStripで引数を渡す方法
□投稿者/ Hongliang (860回)-(2019/08/14(Wed) 22:57:41)
まず、New EventHandlerに渡すメソッドは、
Sub Method(ByVal sender As Object, ByVal e As EventArgs)
という形でなければなりません(メソッド名や引数名は任意です)。
参考:
https://docs.microsoft.com/ja-jp/dotnet/api/system.eventhandler?view=netframework-4.8

VBの場合、異なる引数を持つメソッドをもとにEventHandlerをNewしてもコンパイルできたりすることもありますが、
実行時例外になったりすることもあるのでできるかぎり上記ルールを守るべきです。

なので素朴には引数ごとにメソッドを書くことになるわけですが。
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
    Me.ContextMenuStrip1.Items.Add("Test1", Nothing, New EventHandler(AddressOf test1))
    Me.ContextMenuStrip1.Items.Add("Test2", Nothing, AddressOf test2) ' New EventHandlerは省略可
End Sub
Sub Test1(ByVal sender As Object, ByVal e As EventArgs)
    Test(1)
End Sub
Sub Test2(ByVal sender As Object, ByVal e As EventArgs)
    Test(2)
End Sub
Sub Test(ByVal x As Integer)
End Sub

VB10(Visual Studio 2010に搭載されたVB)で、ラムダ式というのを使うことができるようになりました。
// 厳密には、ラムダ式はVB9(VS2008)で使えるようになり、VB10でSubをラムダ式で使えるようになりました。
ラムダ式を使うと、以下のように記述できるようになります。

Me.ContextMenuStrip1.Items.Add("Test1", Nothing, Sub(sender, e) test(1))

Sub部分を省略なく記述すると、以下のようになります。
New EventHandler(Sub(ByVal sender As Object, ByVal e As EventArgs)
    test(1)
End Sub)

処理を1行で記述できる場合、Sub(...)に続けて記述することでEnd Subを省略できます。
New EventHandler(Sub(ByVal sender As Object, ByVal e As EventArgs) test(1))

EventHandlerは Sub(Object, EventArgs) を要求するので、第1引数はObject型、第2引数はEventArgsであるのが自明です。
そのため、
New EventHandler(Sub(ByVal sender, ByVal e) test(1))
と記述すればコンパイラはsenderがObject、eがEventArgsであると推論してくれます(型推論)。

New EventHandlerを省略できるのも、.Items.Addの第3引数がEventHandlerであるから、
第3引数に渡されたデリゲート(AddressOfとか、ラムダ式とか)がEventHandlerであると型推論してくれるからです。
Sub(ByVal sender, ByVal e) test(1)

最後に、ByValは既定の呼び出しなので省略でき、最終的にこうなります。
Sub(sender, e) test(1)

引用返信 編集キー/
■91958 / inTopicNo.3)  Re[2]: ContextMenuStripで引数を渡す方法
□投稿者/ CCCO (2回)-(2019/08/14(Wed) 23:07:42)

ありがとうございます。


Me.ContextMenuStrip1.Items.Add("Test1", Nothing, Sub(sender, e) test(1))
を試してみたのですが

エラー BC36641 ラムダ パラメーター 'sender' により、それを囲むブロック内の変数、以前に定義された範囲変数、またはクエリ式内で暗黙的に宣言された変数が隠ぺいされます。
エラー BC36641 ラムダ パラメーター 'e' により、それを囲むブロック内の変数、以前に定義された範囲変数、またはクエリ式内で暗黙的に宣言された変数が隠ぺいされます。

というエラーが出て実行できません。

何が原因でしょうか?


引用返信 編集キー/
■91959 / inTopicNo.4)  Re[3]: ContextMenuStripで引数を渡す方法
□投稿者/ Hongliang (861回)-(2019/08/14(Wed) 23:23:50)
あー、
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
内で
Me.ContextMenuStrip1.Items.Add("Test1", Nothing, Sub(sender, e) test(1))
とすると、senderとeが名前被りしちゃうわけですね。
先述の通り引数名は自由にしていいので、Form1_Loadの引数名かSubの引数名かどちらかを適当に変更すればいいです。
引用返信 編集キー/
■91967 / inTopicNo.5)  Re[4]: ContextMenuStripで引数を渡す方法
□投稿者/ CCCO (3回)-(2019/08/15(Thu) 11:14:17)
しょへええええ
うまくいやした

どうもありがとうございました。

解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ