自作クラスのイベントを外部ハンドラでスレッドセーフにする方法

このQ&Aのポイント
  • 自作クラスのイベントを外部ハンドラでスレッドセーフにする方法を紹介します
  • .NETモジュールプロジェクトとWindows Formアプリケーションプロジェクトを含むソリューションを作成しました
  • 実行時にエラーが発生し、スレッド間の操作が無効であるというメッセージが表示されます
回答を見る
  • ベストアンサー

自作クラスのイベントを外部ハンドラでスレッドセーフ

■.NETモジュールプロジェクト(DLL) Public Class MyClass   Public Event hoge( ByVal sender As Object, ByVal e As EventArgs )   Private WithEvents Timer As Timers.Timer   Private Sub New()     Timer = New Timers.Timer : Timer.Interval = 10 : Timer.Start()   End Sub   Private Sub fuga( ByVal sender As Object, ByVal e As EventArgs ) Handles Timer.Elapsed     RaiseEvent hoge( Me, New EventArgs ) ' 一定時間ごとにイベントを発生させる   End Sub End Class ■上の.NETモジュールを参照している Windows Form アプリケーションプロジェクト(EXE) Public Class Form1   Private WithEvents foo As MyClass.MyClass   Public Sub New()     InitializeComponent()     foo = New MyClass.MyClass   End Sub   Private Sub bar() Handles foo.hoge     TextBox1.Text = "baz" ' TextBox1 は デザイナで Form1 に貼り付け済み   End Sub End Class という 2 プロジェクトを含むソリューションを作成しました。実行すると、 有効ではないスレッド間の操作: コントロールが作成されたスレッド以外のスレッドからコントロール 'TextBox1' がアクセスされました。 というエラーが出てきます。 foo が MyClass ではなく、system.windows.forms.dll などに入っている Button や Form といったコントロールの場合は、上記の bar() のような書き方でもスレッドセーフに扱えるので、MyClass もForm1 のコードを修正する事なく、利用できたらなと思っています。 その場合、どのように MyClass を書けばいいでしょうか。環境は VS2008 で、.NET2.0 ベースです。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

別スレッドで動作するタイマーによってイベントが発生するのが仕様なのですから, それにあわせて使う側が処理します。 ControlをUIスレッド以外から扱うことはできません。 具体的には,barの中でControl.InvokeRequiredが真であれば, Control.InvokeまたはControl.BeginInvokeを呼び出して, その中でControlへアクセスする,というものです。 ButtonやFormのイベントは,UIスレッド上で発生します。 そのため,スレッドの問題は関係してきません。

sumire_kanou
質問者

お礼

遅くなりましたが回答ありがとうございました

関連するQ&A

  • VB.NET スレッドからのイベント受信について

    はじめて質問させていただく、VB.NET初心者です。 ただいまスレッド、イベント処理を作成中で Form1にButton1、Label1を貼り付け以下の様なプログラムを記述しました。 (スレッドにて5秒ごとにイベントを発生させます。) 'イベント引数 Public Class EventArgs Inherits System.EventArgs Public nowTime As String End Class 'イベント発行 Public Class EventTest Public Event _event(ByVal sender As Object, ByVal e As EventArgs) Public Sub Go() Dim args As New EventArgs() args.nowTime = Now.ToString RaiseEvent _event(Me, args) End Sub End Class 'フォーム内処理 'スレッド宣言 Dim MyThread As New System.Threading.Thread(AddressOf _Thread) Private WithEvents _test As New EventTest() 'イベント受信   Private Sub Handler(ByVal sender As System.Object, ByVal e As EventArgs) Handles _test._event Label1.Text = e.nowTime End Sub 'スレッド(5秒間隔でイベント発行) Private Sub _Thread() Dim i As Integer For i = 0 To 99 System.Threading.Thread.Sleep(5000) _test.Go() Next End Sub 'スレッド起動 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click MyThread.Start() End Sub End Class 開発環境から普通に実行すれば正常に動作している様なのですが、 イベント受信部(Handler)のLabel1.Text = e.nowTime部に ブレークポイントを置いてLabel1のウォッチをするとその時点で 処理がとまってしまいます。なぜとまるのかが知りたいです。 作成方法がまずいのでしょうか? 皆様よろしくお願いいたします。

  • テキストファイルを読み込んで文字の動的表示をする方法を教えてください。

    Visual basic2005 Express Editionで、文字を動的に表示する方法は、 TextBoxとTimerをFormに貼り付けて、Timerのプロパティの動作の項目のEnabledをTrueにしてコードに Public Class Form1 Private hyouji As String = "テスト" Private nagasa As Integer = 0 Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick TextBox1.Text = Microsoft.VisualBasic.Left(hyouji, nagasa) nagasa += 1 If nagasa > Len(hyouji) Then nagasa = 0 End If End Sub End Class と入力すると出来ますが、テキストファイルを読み込んで文字を動的に表示する方法が分かりません。 教えてください。よろしくお願いします。

  • Form間のデータ渡しについて

    申し訳ありません。VB.NET初心者です。 Form1から、ボタンAをクリックするとForm2がオープンします。 Form1から、ボタンBをクリックするとForm3がオープンします。 Form1では、Form2またはForm3で設定した値をそれぞれ演算に使おうとしています。 MicrosoftのHPからパクってForm1 - Form2間のデータの引渡しを行うことはできたの ですが、新規でForm3を作成して、Form1 - Form3間のデータの引渡しを行おうとする とForm3の立ち上がり時に "NullReferenceException はハンドルされませんでした"となり、 困ってしまいました。 使われている方から見ると簡単かもしれず 申し訳ありませんが、どなたか教えていただけないでしょうか。 ==================== Form1.vb ======================= Form1には、Label1、Label2、Button1、Button2があります。 Public Class Form1 Inherits System.Windows.Forms.Form Private m_form2 As Form2 Private m_form3 As Form3 Public Property LabelText() As String Get Return Label1.Text End Get Set(ByVal Value As String) Label1.Text = Value End Set End Property Public Property LabelText2() As String Get Return Label2.Text End Get Set(ByVal Value As String) Label2.Text = Value End Set End Property Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ScaleYokusou.Click m_form2 = New Form2(Me) m_form2.ShowDialog() m_form2.Dispose() End Sub Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ScaleHikito.Click m_form3 = New Form3() m_form3.ShowDialog() m_form3.Dispose() End Sub End Class ==================== Form2.vb ======================= Form2には、TextBox1、Button1があります。 Public Class Form2 Inherits System.Windows.Forms.Form Private m_form1 As Form1 Private Sub TextBox1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged If m_form1 Is Nothing = False Then m_form1.LabelText = Me.TextBox1.Text End If End Sub Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load If m_form1 Is Nothing = False Then Me.TextBox1.Text = m_form1.LabelText End If End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Me.Close() End Sub End Class ==================== Form3.vb ======================= Form3には、TextBox1、Button1があります。 Public Class Form3 Inherits System.Windows.Forms.Form Private m_form1 As Form1 Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged If m_form1 Is Nothing = False Then m_form1.LabelText2 = Me.TextBox1.Text End If End Sub Private Sub Form3_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Me.TextBox1.Text = m_form1.LabelText2 End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Me.Close() End Sub End Class

  • VB初心者です。コードの書き方が分かりません。

    VB初心者です。 VBで(zのn乗)-(xのn乗+yのn乗)の計算が出来るようにしたいのですが、答えが必ず-1になってしまいます。 Option Explicit On Public Class Form1 Dim x As Long Dim y As Long Dim z As Long Dim n As Long Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Me.Close() End Sub Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged End Sub Private Sub TextBox2_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox2.TextChanged End Sub Private Sub TextBox3_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox3.TextChanged End Sub Private Sub TextBox4_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox4.TextChanged End Sub Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click TextBox5.Text = (z ^ n) - (x ^ n + y ^ n) End Sub End Class 正しいコードの書き方を教えて下さい。 また特定の答えのときにメッセージを表示したいのですが、どうすればいいですか?

  • このコードはどこが間違っていますか?(至急)

    急ぎのため再度の質問失礼します。 (zのn乗)-(xのn乗+yのn乗)の計算をさせて、答えが0のときにメッセージを表示したいのですが、どのようなコードを書けばいいのでしょうか? Option Explicit On Public Class Form1 Dim x As Long Dim y As Long Dim z As Long Dim n As Long Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Me.Close() End Sub Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged End Sub Private Sub TextBox2_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox2.TextChanged End Sub Private Sub TextBox3_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox3.TextChanged End Sub Private Sub TextBox4_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox4.TextChanged End Sub Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click x = TextBox1.Text y = TextBox2.Text z = TextBox3.Text n = TextBox4.Text TextBox5.Text = (z ^ n) - (x ^ n + y ^ n) If (TextBox5 .Text= 0) Then Label6.Visible = True End If End Sub Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load End Sub Private Sub Label6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Label6.Click End Sub End Class このコードだと答えが必ず-1になってしまうのですが、どこを直せばいいのでしょうか? 正しいコードを教えて下さい。 よろしくお願いします。

  • クラス間(Form間?)で使える変数の設定方法(VB.NET)

    VB.net(Visual Studio)で現在プログラムの勉強をしています。 現在のスキルとしまして、変数,引数,グローバル変数,サブルーチン等を勉強しました。 残念ながら、他のプログラム言語等は勉強した事がありません。 <目的> 現在1つのアプリケーション内でForm1,Form2,Form3と作り Form1のText.Boxに入力された値を変数としてボタンを押すと各Formのラベルに 変数を渡し表示させたいと考えております。 <問題点> しかしプログラムを作っても波下線が出てプログラムのデバックが開始できません。 おそらくどこかがおかしいと思うのですが判りません。 <質問内容> 下記のサンプルの中でおかしいコードや根本からやり直す必要なコードがあれば ご教授願えますでしょうか? <サンプル> -----Form1------ Public Class Form1 Public TextBox1noNakami as strig Private Sub Button1_click(Byval sender As System.Object,Byval e AS System.EventArgs) Handles Button1_click TextBox1noNakami = TextBox1.text Form2.show() Form3.show() End Sub End Class -----Form2----- Public Class Form2 Public TextBox1noNakami as Form1 Private Sub Form2_Losd(Byval sender As System.Object,Byval e AS System.EventArgs) Handles MyBase.Load label1.text = TextBox1noNakami End Sub End Class -----Form3----- Public Class Form3 Public TextBox1noNakami as Form1 Private Sub Form3_Losd(Byval sender As System.Object,Byval e AS System.EventArgs) Handles MyBase.Load label2.text = TextBox1noNakami End Sub End Class

  • VB2008 Form間の計算について

    VB勉強中のものです。 次のようにプログラムを作成したいですので よろしくお願いします。 要望: 1 From2のTextbox1 or Textbox2に"2001/05/05"ような書式で日付を入力 2 RadioButton1かRadioButton2の選択して 3 Form1の「DateTimePicker」を利用して、日数の差を計算し、 Form2の label3に結果を表示させる 例: From2のTextbox1 = 2001/01/01 Form1の「DateTimePicker」 = 2002/01/01 RadioButton1を選択したら、 Label3内に " 誕生日から生まれて365日となりました" という結果が出れば、問題がないです。 ------------ Form 1 --------------------- Public Class Form1 Private Sub Label2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Label2.Click 'labelをクリックして、form2を開く Dim frmTmp As New Form2 frmTmp.ShowDialog() End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim intdate As Integer intdate = DateDiff(DateInterval.Day, DateTimePicker1.Value, Now) Label1.Text = "誕生日から生まれて" & intdate & "日となりました" End Sub End Class -------------------------------------------- -------------Form 2 ------------------------ Public Class Form2 Private Sub RadioButton1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioButton1.CheckedChanged If RadioButton1.Checked = True Then Label3.Text = "*******わからない部分*******" End If End Sub End Class ----------------------------------------------------- 以上

  • sub プロシージャを呼び出すにはどうればいいんですか?in vb 2005

    恐れ入ります。 vb2005にて、sub プロシージャをよびだしたいんですけどどうすればよろしいでしょうか?教えて下さい。 Public Class Form1 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click load ike 'vb6ではこれでいけたのに・・・ End Sub Public Sub ike() textbox1.text="イケメン" end sub End Class

  • form2がボタンを押すと消えてしまう

    vb2010で、作成しています。form1から、form2を呼び出し、okボタンまたは、cancelボタンを押すと、無条件でform2が消えてしまいます。私がしたいのは、form2(パスワード入力ウィンドウ)でテキストボックスにパスワードを入力してokボタンを押して、それが正しい(1234)ときのみform2を消去することです。現在のところ、入力したパスワードが間違っていてもokボタンを押すと、form2は消えてしまいます。 form1側のコードとform2側のコードは以下です。お手数ですが御教示いただけると幸いです。 /////////Form1 Public Class Form1 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim f As New Form2() f.TextBox1.PasswordChar = "*"c '//入力文字をマスクする If f.ShowDialog(Me) = DialogResult.OK Then If f.TextBox1.Text = "1234" Then f.Dispose() End If End If End Sub End Class /////////Form2 Public Class Form2 Private Sub btnOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOK.Click Dim f As Form1 f = Me.Owner Me.DialogResult = DialogResult.OK End Sub Private Sub btncancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btncancel.Click Dim f As Form1 f = Me.Owner Me.DialogResult = DialogResult.Cancel End Sub End Class

  • System.Timers.Timer について

    下記のようなコードで動いていますが、 TestFunc に独自の引数を渡したいと考えています。 どうすれば実現できるでしょうか? 引数以外(メンバ変数等)では対応できていますので、 引数の方法だけ教えてほしいです。 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load timer = New System.Timers.Timer() AddHandler timer.Elapsed, New ElapsedEventHandler(AddressOf TestFunc) timer.Interval = 1000 timer.Start() End Sub Public Sub TestFunc(ByVal sender As Object, ByVal e As ElapsedEventArgs) Console.WriteLine(DateTime.Now) End Sub

専門家に質問してみよう