多:1のイベント処理

タグの編集
投稿者 あせたけ  (社会人) 投稿日時 2020/11/3 16:23:19
雑談的と言うか…技術的と言うか…な話題になりますが…^^;

多:1のイベント処理で、通常は…
    Private Sub lblMoving_Click(sender As Object, e As EventArgs) Handles lblMovingUp.Click, lblMovingDown.Click, lblMovingLeft.Click, lblMovingRight.Click
        Dim dir As Map.Dir
        If sender Is lblMovingUp Then
            dir = Map.Dir.Up
        ElseIf sender Is lblMovingDown then
            dir = Map.Dir.Down
        ElseIf sender Is lblMovingLeftthen
            dir = Map.Dir.Left
        ElseIf sender Is lblMovingRightthen
            dir = Map.Dir.Right
        End If
        m.Map.Map_Move(Direction:=dir)
    End Sub

…とするところを…

    Private Sub lblMoving_Click(sender As Object, e As EventArgs) Handles lblMovingUp.Click, lblMovingDown.Click, lblMovingLeft.Click, lblMovingRight.Click
        Dim dir As Map.Dir
        Select Case sender
            Case lblMovingUp
                dir = Map.Dir.Up
            Case lblMovingDown
                dir = Map.Dir.Down
            Case lblMovingLeft
                dir = Map.Dir.Left
            Case lblMovingRight
                dir = Map.Dir.Right
        End Select
        m.Map.Map_Move(Direction:=dir)
    End Sub

…と言う感じには書けないものでしょうか…
(ちなみにこのままではSystem.InvalidCastExeptionが出ます)

Select Case CType(sender,Label) …としてみましたが、今度は「演算子 '=' は、型 'Label' に対して定義されていません…と出ます。

素直にタグネームを入れてやれよと言う話もあるとは思いましたが、
気になりましたので、投稿させて頂きました^^;

<参考>タグネームを付けて処理させて例(これはエラーは出ず、期待通りに処理する)
    Private Sub lblMoving_Click(sender As Object, e As EventArgs) Handles lblMovingUp.Click, lblMovingDown.Click, lblMovingLeft.Click, lblMovingRight.Click
        Dim dir As Map.Dir
        Select Case sender.Tag
            Case "UP"
                dir = Map.Dir.Up
            Case "DOWN"
                dir = Map.Dir.Down
            Case "LEFT"
                dir = Map.Dir.Left
            Case "RIGHT"
                dir = Map.Dir.Right
        End Select
        m.Map.Map_Move(Direction:=dir)
    End Sub
投稿者 (削除されました)  () 投稿日時 2020/11/4 10:31:28
(削除されました)
投稿者 (削除されました)  () 投稿日時 2020/11/4 10:32:44
(削除されました)
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2020/11/4 10:40:13
> Dim dir As Map.Dir
VB には「Dir 関数」が標準で組み込まれているので、別の変数名にした方が良いかと思います。
また、lblMovingUp と lblMovingUp が混在している点も気になりますし、
If/ElseIf 句が lblMovingLeftthen / lblMovingRightthen なのに、
Handles 句が lblMovingLeft / lblMovingRight なのも不自然ですね。


> 多:1のイベント処理で、通常は…
自分ならこう書きます。

Private Direction As New Dictionary(Of Object, Map.Dir)()
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
 Direction.Add(lblMovingUp, Map.Dir.Up)
 Direction.Add(lblMovingDown, Map.Dir.Down)
 Direction.Add(lblMovingLeft, Map.Dir.Left)
 Direction.Add(lblMovingRight, Map.Dir.Right)
End Sub
Private Sub lblMoving_Click(sender As Object, e As EventArgs) Handles lblMovingUp.Click, lblMovingDown.Click, lblMovingLeft.Click, lblMovingRight.Click
    m.Map.Map_Move(Direction:=Direction(sender))
End Sub


> …と言う感じには書けないものでしょうか…
強いて言えば次のような書き方がありますが、参照の一致を見るのであれば、
Dictionary 等を使うか、If 判定した方が素直だと思います。

Select Case True
    Case sender Is lblMovingUp
        dir = Map.Dir.Up
    Case sender Is lblMovingDown
        dir = Map.Dir.Down
End Select
' https://github.com/dotnet/vblang/issues/568 


> タグネームを付けて処理させて例(これはエラーは出ず、期待通りに処理する)
Tag プロパティは Object 型のプロパティです。
デザイン時には文字列しかセットできませんが、実際には任意のデータを格納できますから、
Load イベントなどで最初から Map.Dir 型の値を Tag にセットしておけば、下記のように書けますよ。

m.Map.Map_Move(Direction:=sender.Tag)
'あるいは 
m.Map.Map_Move(Direction:=DirectCast(sender, Control).Tag)
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2020/11/4 11:11:35
書き漏らしたので追記。
m.Map.Map_Move(Direction:=sender.Tag)
'あるいは  
m.Map.Map_Move(Direction:=DirectCast(sender, Control).Tag)
'あるいは  
m.Map.Map_Move(Direction:=DirectCast(DirectCast(sender, Control).Tag, Map.Dir))
投稿者 あせたけ  (社会人) 投稿日時 2020/11/4 11:16:55
魔界の仮面弁士様
いつもお世話になります。

>VB には「Dir 関数」が標準で組み込まれているので、別の変数名にした方が良いかと思います。

良い変数名が思い浮かばずつい…^^:


>また、lblMovingUp と lblMovingUp が混在している点も気になりますし、
>If/ElseIf 句が lblMovingLeftthen / lblMovingRightthen なのに、
>Handles 句が lblMovingLeft / lblMovingRight なのも不自然ですね。

直接手打ちした為の入力ミスです^^;
ご容赦ください^^;;;


辞書を使って書く方法が一番スマートそうです。

Select Case Trueと言う書き方があると言う事も知る事が出来ました。

最近はオブジェクト指向のプログラムがある程度は書ける様にはなりましたが、
VB.NETが出来てからもしばらくはVB6.0で組んでいたもので、
オブジェクトについてはまだまだ勉強が足りないなと痛感しています^^;
このコードを見た時、目から鱗でした…w

ありがとうございました。
投稿者 あせたけ  (社会人) 投稿日時 2020/11/4 11:27:28
>書き漏らしたので追記。

頭が混乱してきましたw

>m.Map.Map_Move(Direction:=sender.Tag)

これはTagの内容を直接渡しているので、Tagの内容を
Map.Dir.UpやMap.Dir.Downなどにすれば動作するとすぐ解りました。


>m.Map.Map_Move(Direction:=DirectCast(sender, Control).Tag)


これもLabelはControlなので、上記を丁寧に書いたやり方だと理解出来ます。


>m.Map.Map_Move(Direction:=DirectCast(DirectCast(sender, Control).Tag, Map.Dir))

これ!
(Label)コントロールのタグをMap.Dirにキャストする???
…とどうなるか今の私には想像が出来ません…
    Public Enum Dir
        None
        Up
        Down
        Left
        Right
    End Enum
こうなっておりまして…

Enumにキャストする…
?????
勉強不足で理解不能です^^;
投稿者 あせたけ  (社会人) 投稿日時 2020/11/4 11:41:30
オブジェクト指向…
奥が深い…

魔界の仮面弁士様のコードを参考にして…

------------------------------------------------------------------------------
    Private Sub lblMoving_MouseEnter(sender As Object, e As EventArgs) Handles lblMovingUp.MouseEnter, lblMovingDown.MouseEnter, lblMovingLeft.MouseEnter, lblMovingRight.MouseEnter
        Select Case sender.Tag
            Case "UP"
                lblMovingUp.BackColor = Color.LightPink
            Case "DOWN"
                lblMovingDown.BackColor = Color.LightPink
            Case "LEFT"
                lblMovingLeft.BackColor = Color.LightPink
            Case "RIGHT"
                lblMovingRight.BackColor = Color.LightPink
        End Select
    End Sub
------------------------------------------------------------------------------
これも…

------------------------------------------------------------------------------
    Private Sub lblMoving_MouseEnter(sender As Object, e As EventArgs) Handles lblMovingUp.MouseEnter, lblMovingDown.MouseEnter, lblMovingLeft.MouseEnter, lblMovingRight.MouseEnter
        sender.BackColor = Color.LightPink
    End Sub
------------------------------------------------------------------------------
こうなりましたw

プログラム的には
DirectCast(Sender,Label).BackColor
…とした方がスマートなのかも知れませんが…
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2020/11/4 12:35:32
> プログラム的には
> DirectCast(Sender,Label).BackColor
> …とした方がスマートなのかも知れませんが…

あるいは
Sub lblMoving_MouseEnter(sender As Object, e As EventArgs)

Sub lblMoving_MouseEnter(sender As Label, e As EventArgs)
に変更するという手もあります。

※ Option Strict Off の場合のみ有効
投稿者 (削除されました)  () 投稿日時 2020/11/4 12:43:14
(削除されました)
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2020/11/4 13:06:53
>> m.Map.Map_Move(Direction:=sender.Tag)
> これはTagの内容を直接渡しているので、Tagの内容を
> Map.Dir.UpやMap.Dir.Downなどにすれば動作するとすぐ解りました。

Map_Move の引数が Direction As Object の場合には、
 m.Map.Map_Move(Direction:=sender.Tag)
のままで構いませんが、恐らくは Direction As Map.Dir なのですよね。


sender 引数の型は As Object ですし、
Tag プロパティの型も As Object です。

初期設定では Option Strict Off モードでビルドされているので問題になりませんが、
Option Strict On モードでビルドされていた場合、
Map.Dir 型の仮引数に渡す値は、Object 側の値を実引数として渡すのではなく、
Map.Dir 型の実引数を渡す必要があります。そのため、 DirectCast を使って
データ型を揃えてやる必要があるというわけです。


なお、このパターンを実行する場合には、Form の Load イベントにおいて、
 lblMovingUp.Tag = Map.Dir.Up
などのように、「Tag プロパティに Map.Dir 列挙型の値をセットしておく」必要があります。


>> m.Map.Map_Move(Direction:=DirectCast(sender, Control).Tag)
> これもLabelはControlなので、上記を丁寧に書いたやり方だと理解出来ます。

下記いずれも、同じ結果が得られます。

m.Map.Map_Move(Direction:=DirectCast(sender, Control).Tag)
m.Map.Map_Move(Direction:=DirectCast(sender, Label).Tag)


Tag プロパティを実装しているのは Label ではなく、その親クラスである Control なので、
今回はあえて Control 型にキャストしてありますが、Label にキャストしても問題ありません。
(Label クラスは Control の Tag プロパティをそのまま受け継いでいます)


>> m.Map.Map_Move(Direction:=DirectCast(DirectCast(sender, Control).Tag, Map.Dir))
> これ!
> (Label)コントロールのタグをMap.Dirにキャストする???

sender 引数同様、Tag プロパティも As Object なデータ型なので、DirectCast あるいは CType が必要になります。
もしも sender に Label 以外が渡される可能性がある場合には、TryCast を使うこともできます。

Dim lbl As Label = TryCast(sender, Label)
If lbl IsNot Nothing Then
   Dim direction As Map.Dir = CType(lbl.Tag, Map.Dir)
   m.Map.Map_Move(Direction:=direction)
End If
投稿者 あせたけ  (社会人) 投稿日時 2020/11/4 22:01:19
丁寧な解説ありがとうございますm(__)m

>Sub lblMoving_MouseEnter(sender As Label, e As EventArgs)

こう言う書き方も出来るのですね!


>恐らくは Direction As Map.Dir なのですよね。

はい、そうです。


>Tag プロパティを実装しているのは Label ではなく、その親クラスである Control なので、
>今回はあえて Control 型にキャストしてありますが、Label にキャストしても問題ありません。
>(Label クラスは Control の Tag プロパティをそのまま受け継いでいます)

どこからの派生クラスかと言うのも知っていた方が良いみたいですね^^;;;;


>> (Label)コントロールのタグをMap.Dirにキャストする???
------------------------------------------------------------------------------
Dim lbl As Label = TryCast(sender, Label)
If lbl IsNot Nothing Then
   Dim direction As Map.Dir = CType(lbl.Tag, Map.Dir)
   m.Map.Map_Move(Direction:=direction)
End If
------------------------------------------------------------------------------
Control←Labelの説明と、上記のソースコードで何となく理解できました。