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

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

ログ内検索
  • キーワードを複数指定する場合は 半角スペース で区切ってください。
  • 検索条件は、(AND)=[A かつ B] (OR)=[A または B] となっています。
  • [返信]をクリックすると返信ページへ移動します。
キーワード/ 検索条件 /
検索範囲/ 強調表示/ ON (自動リンクOFF)
結果表示件数/ 記事No検索/ ON
大文字と小文字を区別する

No.102127 の関連記事表示

<< 0 >>
■102127  VBでのイベント未定義の処理
□投稿者/ ぴよ -(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);
    }
    }
親記事 /過去ログ178より / 関連記事表示
削除チェック/

■102128  Re[1]: VBでのイベント未定義の処理
□投稿者/ WebSurfer -(2023/07/06(Thu) 15:41:16)
    No102127 (ぴよ さん) に返信

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

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

    X も書いてください。

    そうしてもらえれば、Y はできないけど、X はこうすれば実現できるというよう
    な回答が出てくるかもしれません。
記事No.102127 のレス /過去ログ178より / 関連記事表示
削除チェック/

■102131  Re[1]: VBでのイベント未定義の処理
□投稿者/ 魔界の仮面弁士 -(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』ブロックを使えば
    イベントのデリゲートを自己管理できますので、それに相当する分岐を実装させることも
    一応可能ですが…そもそも何故、そのような分岐が必要なのですか?

記事No.102127 のレス /過去ログ178より / 関連記事表示
削除チェック/

■102130  Re[2]: VBでのイベント未定義の処理
□投稿者/ ??? -(2023/07/06(Thu) 16:14:39)
    No102128 (WebSurfer さん) に返信
    
    上記コードには書いていませんが 変数に画像をセットするだけです
    MyEventが定義されていれば、そっちで画像をセット
    MyEventが定義されていなければ、ベース側で画像をセットしたいです。
    
    変数名 img とします。
    
    img = 画像
    if (MyEvent !=null)
        MyEvent.Invoke(this, EventArgs.Empty);
         ↑定義された側でimgに画像をセット
    
    上記のように画像を上書きすれば目的は達成するのですが
    画像取得に時間がかかるため、一回の処理で済ませたいです。
記事No.102127 のレス /過去ログ178より / 関連記事表示
削除チェック/

■102132  Re[3]: VBでのイベント未定義の処理
□投稿者/ 魔界の仮面弁士 -(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以降
    の方がパフォーマンスが良かったりします。
記事No.102127 のレス /過去ログ178より / 関連記事表示
削除チェック/

■102135  Re[3]: VBでのイベント未定義の処理
□投稿者/ 魔界の仮面弁士 -(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


    要件によっては、同一イベントに対して複数のイベントハンドラが
    同時に割り当てられていた場合についての考慮も必要かもしれません。
記事No.102127 のレス /過去ログ178より / 関連記事表示
削除チェック/

■102137  Re[4]: VBでのイベント未定義の処理
□投稿者/ ぴよ -(2023/07/06(Thu) 17:16:48)
    No102135 (魔界の仮面弁士 さん) に返信
    > そのイベントハンドラー側が、クラス側に画像を伝える部分について、
    > どのように実装されるのかがイメージがわきません。
    >
    > イベント引数で画像を受け渡せるようにしては駄目なのでしょうか。
    Form1はクラスライブラリにあり、複数のプログラムで使用しています。
    基本的にはForm1に定義してある画像の取得方法でいいのですが
    特定のプログラムのみ、画像の取得方法が異なるため
    イベントが定義されているかされていないかで分岐したかったのです。
記事No.102127 のレス /過去ログ178より / 関連記事表示
削除チェック/

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

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

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

    特殊なデフォルト値を考慮したいような場合によく使う手法の一つです。
記事No.102127 のレス /過去ログ178より / 関連記事表示
削除チェック/

■102138  Re[3]: VBでのイベント未定義の処理
□投稿者/ WebSurfer -(2023/07/06(Thu) 17:30:04)
    No102130 (??? さん) に返信

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

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

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

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

    それとどう考えてもつながらないです。
記事No.102127 のレス /過去ログ178より / 関連記事表示
削除チェック/

■102139  Re[4]: VBでのイベント未定義の処理
□投稿者/ ぴよ -(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;
    }
    }
記事No.102127 のレス /過去ログ178より / 関連記事表示
削除チェック/

■102140  Re[5]: VBでのイベント未定義の処理
□投稿者/ KOZ -(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
記事No.102127 のレス /過去ログ178より / 関連記事表示
削除チェック/

■102144  Re[5]: VBでのイベント未定義の処理
□投稿者/ WebSurfer -(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
    
記事No.102127 のレス /過去ログ178より / 関連記事表示
削除チェック/

■102145  Re[6]: VBでのイベント未定義の処理
□投稿者/ piyo -(2023/07/10(Mon) 10:16:14)
    2023/07/10(Mon) 10:17:37 編集(投稿者)

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

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

    Action型を使用することで、目的とすることができました。
    ありがとうございました。
記事No.102127 のレス / END /過去ログ178より / 関連記事表示
削除チェック/

■102133  Re[2]: VBでのイベント未定義の処理
□投稿者/ piyo -(2023/07/06(Thu) 16:33:22)
    No102131 (魔界の仮面弁士 さん) に返信
記事No.102127 のレス /過去ログ178より / 関連記事表示
削除チェック/

■102134  Re[3]: VBでのイベント未定義の処理
□投稿者/ ぴよ -(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判定は今後の参考にさせていただきます。ありがとうございます。
記事No.102127 のレス /過去ログ178より / 関連記事表示
削除チェック/

■102136  Re[4]: VBでのイベント未定義の処理
□投稿者/ 魔界の仮面弁士 -(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,) などで管理した方が良いかもしれませんね。
記事No.102127 のレス /過去ログ178より / 関連記事表示
削除チェック/

■102143  Re[5]: VBでのイベント未定義の処理
□投稿者/ shu -(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
記事No.102127 のレス /過去ログ178より / 関連記事表示
削除チェック/



<< 0 >>

パスワード/

- Child Tree -