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

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

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

Re[5]: VBでのイベント未定義の処理


(過去ログ 178 を表示中)

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

■102127 / inTopicNo.1)  VBでのイベント未定義の処理
  
□投稿者/ ぴよ (1回)-(2023/07/06(Thu) 15:28:32)

分類:[VB.NET/VB2005 以降] 

開発環境:VS2005 VB.net
下記ソースはVS2022 C#です。

VBでC#の if (MyEvent != null) のような分岐方法をしたいのですが分かりません。

「// ここで別処理を記述したい」のところに
MyEventが定義されていない場合の別処理を行ないたいのですが
VBでのイベント発生方法は RaiseEventと書いているのしか見つからず困っています。
よろしくお願いします。

public partial class Form1 : Form
{
    public event EventHandler MyEvent;

    protected override void OnMouseDown(MouseEventArgs e)
    {
        if (MyEvent != null)
            MyEvent.Invoke(this, EventArgs.Empty);
        else
            // ここで別処理を記述したい

        base.OnMouseDown(e);
    }
}

引用返信 編集キー/
■102128 / inTopicNo.2)  Re[1]: VBでのイベント未定義の処理
□投稿者/ WebSurfer (2732回)-(2023/07/06(Thu) 15:41:16)
No102127 (ぴよ さん) に返信

そもそも何がしたいのでしょうか? XY 問題のような気がします。

XY 問題とは、質問者に X という課題があって、質問者が Y という解決策を考え
ついて Y について質問したが(質問には X は書かないで)、Y は X の解決策と
はなっておらず、回答者と質問者間で話がかみ合わず、一向に解決にならないと
いうことです。

X も書いてください。

そうしてもらえれば、Y はできないけど、X はこうすれば実現できるというよう
な回答が出てくるかもしれません。

引用返信 編集キー/
■102130 / inTopicNo.3)  Re[2]: VBでのイベント未定義の処理
□投稿者/ ??? (1回)-(2023/07/06(Thu) 16:14:39)
No102128 (WebSurfer さん) に返信

上記コードには書いていませんが 変数に画像をセットするだけです
MyEventが定義されていれば、そっちで画像をセット
MyEventが定義されていなければ、ベース側で画像をセットしたいです。

変数名 img とします。

img = 画像
if (MyEvent !=null)
    MyEvent.Invoke(this, EventArgs.Empty);
     ↑定義された側でimgに画像をセット

上記のように画像を上書きすれば目的は達成するのですが
画像取得に時間がかかるため、一回の処理で済ませたいです。

引用返信 編集キー/
■102131 / inTopicNo.4)  Re[1]: VBでのイベント未定義の処理
□投稿者/ 魔界の仮面弁士 (3663回)-(2023/07/06(Thu) 16:18:26)
No102127 (ぴよ さん) に返信
> VBでC#の if (MyEvent != null) のような分岐方法をしたいのですが分かりません。

VB8 以降であれば、「Public Event MyEvent As EventHandler」の代わりに、
『Public Custom Event MyEvent As EventHandler』〜『End Event』ブロックを使えば
イベントのデリゲートを自己管理できますので、それに相当する分岐を実装させることも
一応可能ですが…そもそも何故、そのような分岐が必要なのですか?


引用返信 編集キー/
■102132 / inTopicNo.5)  Re[3]: VBでのイベント未定義の処理
□投稿者/ 魔界の仮面弁士 (3664回)-(2023/07/06(Thu) 16:33:04)
2023/07/06(Thu) 16:35:56 編集(投稿者)

No102130 (??? さん) に返信
??? さんは、ぴよさんですか?
(文字コードの関係で、FireFox でアクセスすると Cookie が化けるらしいです)

> MyEventが定義されていれば、そっちで画像をセット
> MyEventが定義されていなければ、ベース側で画像をセットしたいです。

VB だと、クラス利用側は WithEvents 変数でイベント処理することも
多いと思いますが、その場合も考慮されていますか?

ちなみに Custom Event の場合、WithEvents されたイベントハンドラに対しても
AddHandler〜End AddHandler ブロックが処理されます。



> 上記コードには書いていませんが 変数に画像をセットするだけです

今時の C# ならば
> if (MyEvent !=null)
> MyEvent.Invoke(this, EventArgs.Empty);
ではなく、
 MyEvent?.Invoke(this, EventArgs.Empty);
と書く方が多いかと思いますよ。


蛇足ですが、非 null 判定については、
 if (MyEvent != null)
よりは、
 if (!(MyEvent is null)) // C#7.0以降
 if (MyEvent is not null) // C#9.0以降
 if (MyEvent is {}) // C#8.0以降
の方がパフォーマンスが良かったりします。
引用返信 編集キー/
■102133 / inTopicNo.6)  Re[2]: VBでのイベント未定義の処理
□投稿者/ piyo (1回)-(2023/07/06(Thu) 16:33:22)
No102131 (魔界の仮面弁士 さん) に返信
引用返信 編集キー/
■102134 / inTopicNo.7)  Re[3]: VBでのイベント未定義の処理
□投稿者/ ぴよ (2回)-(2023/07/06(Thu) 16:46:16)
No102132 (魔界の仮面弁士 さん) に返信

> ■No102130 (??? さん) に返信
???は私(ぴよ)です。文字化けしているのに気付きませんでした。

> VB だと、クラス利用側は WithEvents 変数でイベント処理することも
> 多いと思いますが、その場合も考慮されていますか?
VBはあまり触ったことがなく、あまり理解していません。
RaiseEventを調べていた際に WithEventsも出てきたのですがあまり意味が分からず…

> 今時の C# ならば
>>if (MyEvent !=null)
>> MyEvent.Invoke(this, EventArgs.Empty);
> ではなく、
>  MyEvent?.Invoke(this, EventArgs.Empty);
> と書く方が多いかと思いますよ。
イベント定義時と定義していない時で処理を分岐したいため上記の書き方です。
非null判定は今後の参考にさせていただきます。ありがとうございます。
引用返信 編集キー/
■102135 / inTopicNo.8)  Re[3]: VBでのイベント未定義の処理
□投稿者/ 魔界の仮面弁士 (3665回)-(2023/07/06(Thu) 16:54:25)
No102130 (??? さん) に返信
> 上記コードには書いていませんが 変数に画像をセットするだけです
> MyEventが定義されていれば、そっちで画像をセット
> MyEventが定義されていなければ、ベース側で画像をセットしたいです。

そのイベントハンドラー側が、クラス側に画像を伝える部分について、
どのように実装されるのかがイメージがわきません。

イベント引数で画像を受け渡せるようにしては駄目なのでしょうか。


<案1>
Me.img = 画像
Dim e As New イベント名EventArgs(Me.img)
RaiseEvent イベント名(Me, e)
If e.Handles Then
 Me.img = e.NewImage
End If


<案2>
Dim e As New イベント名EventArgs(Image:=Nothing)
RaiseEvent イベント名(Me, e)
If e.Image Is Nothing Then
 Me.img = 画像
Else
 Me.img = e.Image
End If


要件によっては、同一イベントに対して複数のイベントハンドラが
同時に割り当てられていた場合についての考慮も必要かもしれません。
引用返信 編集キー/
■102136 / inTopicNo.9)  Re[4]: VBでのイベント未定義の処理
□投稿者/ 魔界の仮面弁士 (3666回)-(2023/07/06(Thu) 17:16:30)
No102134 (ぴよ さん) に返信
> RaiseEventを調べていた際に WithEventsも出てきたのですがあまり意味が分からず…
VB でイベントを利用する場合は、むしろ WithEvents / Handles で使うのが普通ですよ。
Visual Studio のデザイナでも、既定の設定では WithEvents 方式が優先されますし。
(デザイン時に GenerateMember プロパティを False にすれば、AddHandler/RemoveHandler 方式にもなりますが)


VB で「if (MyEvent != null)」方式の判定を望むのであれば、いっそのことイベントは使わずに、
呼び出し側から直接 delegate インスタンスを渡す方針にする手もあるかと。



> VBはあまり触ったことがなく、あまり理解していません。
ということは、C# 側の知識はあるということですね。

御存じの通り、C# のイベントではマルチキャストデリゲートのインスタンスを直接扱いますが、
VB ではイベント処理用の専用ステートメントが用意されているため、デリゲートインスタンスを直接扱えません。

VB で、イベントハンドラが示すデリゲートを直接扱うには、
先に述べた「Custom Event」を利用する必要があります。


Custom Event を用いた実装例を 2 つ紹介しておきます。
いずれも、value As EventHandler にて渡されたデリゲートを、
フィールド変数のコレクションに保持しています。
https://learn.microsoft.com/ja-jp/dotnet/visual-basic/programming-guide/language-features/events/how-to-declare-custom-events-to-conserve-memory
https://learn.microsoft.com/ja-jp/dotnet/visual-basic/programming-guide/language-features/events/how-to-declare-custom-events-to-avoid-blocking


前者は、EventHandler デリゲートのインスタンスを EventHandlerList にて管理しています。
後者は、EventHandler デリゲートのインスタンスを ArrayList で管理しています。(今なら List(Of)の方が良いですが)
そのデリゲートを Invoke で呼ぶか BeginInvoke で呼ぶべきかは要件次第。


今回は、「イベント ハンドラーが一つ以上登録済みかどうか」を判定したいとのことなので、
ArrayList / List(Of ) / Dictionary(Of,) などで管理した方が良いかもしれませんね。
引用返信 編集キー/
■102137 / inTopicNo.10)  Re[4]: VBでのイベント未定義の処理
□投稿者/ ぴよ (3回)-(2023/07/06(Thu) 17:16:48)
No102135 (魔界の仮面弁士 さん) に返信
> そのイベントハンドラー側が、クラス側に画像を伝える部分について、
> どのように実装されるのかがイメージがわきません。
>
> イベント引数で画像を受け渡せるようにしては駄目なのでしょうか。
Form1はクラスライブラリにあり、複数のプログラムで使用しています。
基本的にはForm1に定義してある画像の取得方法でいいのですが
特定のプログラムのみ、画像の取得方法が異なるため
イベントが定義されているかされていないかで分岐したかったのです。
引用返信 編集キー/
■102138 / inTopicNo.11)  Re[3]: VBでのイベント未定義の処理
□投稿者/ WebSurfer (2734回)-(2023/07/06(Thu) 17:30:04)
No102130 (??? さん) に返信

> MyEventが定義されていれば、そっちで画像をセット
> MyEventが定義されていなければ、ベース側で画像をセットしたいです

すみませんが理解できないです。

普通に .NET でイベントを実装した場合、イベント(質問者さんの例では MyEvent)に
ハンドラがアタッチされてない場合イベントは null になり、それ以外の場合はイベン
ト起動時に呼び出すハンドラへの参照となります。

そして、イベントが起動される場合はまずイベントが null かどうかを調べ、null で
なければイベントを呼び出して(質問者さんの例では MyEvent(this, e) というように
して)アタッチされているすべてのハンドラを起動するということになるはずです。

それとどう考えてもつながらないです。
引用返信 編集キー/
■102139 / inTopicNo.12)  Re[4]: VBでのイベント未定義の処理
□投稿者/ ぴよ (4回)-(2023/07/06(Thu) 17:42:47)
2023/07/06(Thu) 17:44:48 編集(投稿者)
No102138 (WebSurfer さん) に返信

これでどうでしょうか?イメージとしてはこんな感じです。
Form2にTestがあれば、Test内で処理
TestがなければForm1のOnMouseDown内でValueにセットしたいのです。

public partial class Form1 : Form
{
    public EventHandler MyEvent;

    public int Value = 0;

    protected override void OnMouseDown(MouseEventArgs e)
    {
        if (MyEvent is null)
        {
        }

        if (MyEvent != null)
        {
            MyEvent.Invoke(this, EventArgs.Empty);
        }
        else
        {
            Value = 100;
        }

        base.OnMouseDown(e);
    }
}

public partial class Form2 : Form
{
    public Form1 frm1 = new Form1();
    public Form2()
    {
        this.Controls.Add(frm1);
        frm1.MyEvent += Test;
    }

    public void Test(object sender,EventArgs e)
    {
        frm1.Value = 1;
    }
}

引用返信 編集キー/
■102140 / inTopicNo.13)  Re[5]: VBでのイベント未定義の処理
□投稿者/ KOZ (406回)-(2023/07/07(Fri) 01:42:55)
2023/07/07(Fri) 01:48:05 編集(投稿者)
No102139 (ぴよ さん) に返信

VB だとこんな感じです。

Partial Public Class Form1

    Private Shared MyEventKey As New Object()

    Public Custom Event MyEvent As EventHandler
        AddHandler(value As EventHandler)
            Events.AddHandler(MyEventKey, value)
        End AddHandler
        RemoveHandler(value As EventHandler)
            Events.RemoveHandler(MyEventKey, value)
        End RemoveHandler
        RaiseEvent(sender As Object, e As EventArgs)
            Dim handler As EventHandler = DirectCast(Events(MyEventKey), EventHandler)
            If handler IsNot Nothing Then
                handler.Invoke(sender, e)
            End If
        End RaiseEvent
    End Event

    Public Value As Integer

    Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
        Dim handler As EventHandler = DirectCast(Events(MyEventKey), EventHandler)
        If handler IsNot Nothing Then
            handler.Invoke(Me, e)
        Else
            Value = 100
        End If
        MyBase.OnMouseDown(e)
    End Sub

End Class

Partial Public Class Form2

    Public WithEvents frm1 As New Form1

    Public Sub New()
        InitializeComponent()
        frm1.TopLevel = False
        frm1.Dock = DockStyle.Fill
        frm1.Visible = True
        Me.Controls.Add(frm1)
    End Sub

    Public Sub Test(sender As Object, e As EventArgs) Handles frm1.MyEvent
        frm1.Value = 1
    End Sub

End Class

引用返信 編集キー/
■102141 / inTopicNo.14)  Re[5]: VBでのイベント未定義の処理
□投稿者/ とっちゃん (783回)-(2023/07/07(Fri) 01:56:57)
No102137 (ぴよ さん) に返信
> Form1はクラスライブラリにあり、複数のプログラムで使用しています。
> 基本的にはForm1に定義してある画像の取得方法でいいのですが
> 特定のプログラムのみ、画像の取得方法が異なるため
> イベントが定義されているかされていないかで分岐したかったのです。

イベントが呼ばれたであろう後、一番最初に画像を取得しようとするところで
画像がなければ、元の方法を使うというのはどうでしょう?

画像保持しているのは今はおそらくメンバーフィールドだと思いますが
これをプロパティに変更し、get のタイミングでまだsetが呼ばれていないなら
時間がかかるが自分でロードするという処理を行うようにすれば
イベントの有無を考慮しなくても済みますし
将来的に段取り変えるようなことがあっても
プロパティ部分は手を入れずにそのまま利用できると思います。

特殊なデフォルト値を考慮したいような場合によく使う手法の一つです。

引用返信 編集キー/
■102143 / inTopicNo.15)  Re[5]: VBでのイベント未定義の処理
□投稿者/ shu (1296回)-(2023/07/07(Fri) 20:36:19)
EventではなくAction型で定義すればNothingの判断が出来るので可能かと思います。

'--- Button1, 2を配置
Public Class Form1

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Using fm2 As New Form2()
            fm2.ShowDialog(Me)
        End Using
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Using fm2 As New Form2()
            fm2.TestEvent = Sub()
                                fm2.Label1.Text = "Form1側で設定処理を実行"
                            End Sub
            fm2.ShowDialog(Me)
        End Using
    End Sub
End Class


'--- Button1とLabel1を配置
Public Class Form2

    Public Property TestEvent As Action = Nothing

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If TestEvent Is Nothing Then
            Label1.Text = "Form2側で設定処理を実行"
        Else
            TestEvent.Invoke()
        End If
    End Sub
End Class

引用返信 編集キー/
■102144 / inTopicNo.16)  Re[5]: VBでのイベント未定義の処理
□投稿者/ WebSurfer (2735回)-(2023/07/09(Sun) 18:42:06)
No102139 (ぴよ さん) に返信

> Form2にTestがあれば、Test内で処理
> TestがなければForm1のOnMouseDown内でValueにセットしたいのです。

イベント MyEvent にハンドラがアタッチされてなければ Form1 の OnMouseDown メソッドで
処理を行い、ハンドラ Test がアタッチされていればそのハンドラで処理を行いたいのだと
理解しました。

その理解で合っているのであれば、イベントを使うのは、XY 問題とまでは言えないものの、
適切ではないと思います。

デリゲートを使ってはいかがですか?

質問者さんのコードを動くように直して(動かないコードを貼るのは止めましょう)、イベ
ントに代えてデリゲートを使って書き直すと以下のようになります。下のコードでは Action 
がデリゲートです。


using System;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
                
        public Action p;

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (p != null)
            {
                // デリゲートのポイントするメソッドで処理
                p();
            }
            else
            {
                MessageBox.Show("Form1 の OnMouseDown で処理");
            }

            base.OnMouseDown(e);
        }
    }
}


using System;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form2 : Form
    {
        public Form1 frm1 = new Form1();
        
        public Form2()
        {
            InitializeComponent();

            frm1.TopLevel = false;
            frm1.Height = 100;
            frm1.Width = 100;
            frm1.Visible = true;
            this.Controls.Add(frm1);

            // 以下の設定で Test メソッドで処理される
            // コメントアウトすれば From1 の OnMouseDown で処理
            frm1.p = new Action(Test);
        }

        public void Test()
        {
            MessageBox.Show("Form2 の Test メソッドで処理");
        }
    }
}

デリゲートの方が目的に合っているし、上のコードであれば C# ⇒ VB.NET 変換サービスで変換し
たコードをほぼそのまま使えますので、「VBでのイベント発生方法は RaiseEventと書いているの
しか見つからず困っています」とかで悩むこともないです。

例えば、上のコードを以下の変換サービスで変換したコードを、

Telerik Code Converter
https://converter.telerik.com/

ほぼそのまま使って以下のようにできます。


Public Class Form1
    Public Sub New()
        InitializeComponent()
    End Sub

    Public p As Action

    Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
        If p IsNot Nothing Then
            p()
        Else
            MessageBox.Show("Form1 の OnMouseDown で処理")
        End If

        MyBase.OnMouseDown(e)
    End Sub
End Class


Public Class Form2
    Public frm1 As Form1 = New Form1()

    Public Sub New()
        InitializeComponent()
        frm1.TopLevel = False
        frm1.Height = 100
        frm1.Width = 100
        frm1.Visible = True
        Me.Controls.Add(frm1)

        '以下の設定で Test メソッドで処理される
        'コメントアウトすれば From2 の OnMouseDown で処理
        'frm1.p = New Action(AddressOf Test)
    End Sub

    Public Sub Test()
        MessageBox.Show("Form2 の Test メソッドで処理")
    End Sub
End Class

引用返信 編集キー/
■102145 / inTopicNo.17)  Re[6]: VBでのイベント未定義の処理
□投稿者/ piyo (3回)-(2023/07/10(Mon) 10:16:14)
2023/07/10(Mon) 10:17:37 編集(投稿者)

名前piyoとなっていますが、ぴよです。

No102143 (shu さん) に返信
No102144 (WebSurfer さん) に返信

Action型を使用することで、目的とすることができました。
ありがとうございました。
解決済み
引用返信 編集キー/


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

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -