質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

Q&A

解決済

3回答

13463閲覧

登録されているイベントを実行したい

tec

総合スコア9

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

0グッド

0クリップ

投稿2019/06/13 08:36

編集2019/06/14 01:17

前提・実現したいこと

TextBox の Validating イベントを直接呼び出したいのですが、
VBでのRaiseEventのようなことは出来ないでしょうか?

Invoke(textbox1.KeyDown) のように、登録されているだろうイベントを直接呼び出す方法を探しているのですが、
検索してもDelegateに登録して実行する等の結果ばかりでした。

該当のソースコード

c#

1public class CustomTextBox : TextBox { 2 protected override void OnValidating(CancelEventArgs e) { 3 // チェック処理 4 if (チェックエラー) { 5 MessageBox.Show("チェックエラーです"); 6 this.Focus(); // <- ここでチェック中以外のCustomTextBoxに元々フォーカスがあった場合、 7 // Validating 処理が走って、またチェックエラーメッセージを表示してしまうので、これを回避したい 8 e.Cancel = true; 9 } 10 } 11} 12 13// 14// CustomTextBox を沢山配置したフォーム 15// 16public class Form1 { 17 18 // 19 // このボタンクリックはForm上のどのコントロールにフォーカスが当たっていても 20 // ショートカットキーで呼び出すことが可能 21 // 22 private void button1_Click(object sender, EventArgs e) 23 { 24 ※現在フォーカスのあるCustomTextBox.Validateを実行; // これを実行して、ActiveControlのチェックを行いたい 25 if (上記※の結果、e.Cancel == true) { 26 処理終了; 27 } 28 29 if (フォーム上のCustomTextBoxのチェック処理 == 失敗) { 30 処理終了; 31 } 32 } 33} 34

試したこと

リフレクションで OnValidating を呼んでみましたが、実行された気配がありませんでした。

c#

1object[] args = { new CancelEventArgs() }; 2// OnValidating内でブレークポイントを張っていたが、止まらなかった。(呼ばれていない?) 3ActiveControl.GetType().InvokeMember("OnValidating", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, ActiveControl, args); 4 5var cea = args[0] as CancelEventArgs; 6if (cea.Cancel) // Cancel の中身は falseだった。 7{ 8 return; 9}

補足情報(FW/ツールのバージョンなど)

VisualStudio 2015
Windowsフォーム アプリケーション
.NET Framework 4.6.2


追記

button1_click() は、フォーム上のどのコントロールにフォーカスが当たっていても、
ショートカットキーで直接呼び出すことが可能です。
そのため以下の順で処理が走ります。
0. CustomTextBox上でショートカットキーを押す(KeyDown)
0. button1_click() の処理が走る
0. フォーム上のCustomTextBoxのチェック処理が走る
0. CustomTextBoxのチェックが走って、「チェックエラーです」の後にフォーカスがCustomTextBoxに移動する。
0. 4の時にCustomTextBoxのLeaveイベントが起動し、OnValidatingが呼ばれる

5.のLeaveイベントを呼ばれる前に、CustomTextBoxのOnValidatingを呼んで、
フォーム上のCustomTextBoxのチェック処理まで到達できないようにしたいのです。

追記2

Zuishinさんの指摘を受けて最終的にチェック処理が実装されていたら呼ぶようにしました。

c#

1public interface IValidator { 2 // 不正値かどうかの判定 3 // 不正値だった場合はメッセージを表示させて、コントロールにフォーカスを強制的に移動させる 4 bool ValidateInvalidValue(); 5} 6 7public class CustomTextBox : TextBox, IValidator { 8 protected override void OnValidating(CancelEventArgs e) { 9 if (ValidateInvalidValue()) return; 10 11 e.Cancel = true; 12 } 13 14 public bool ValidateInvalidValue() { 15 // チェック処理 16 if (チェックエラー) { 17 MessageBox.Show("チェックエラーです"); 18 this.Focus(); 19 return false; 20 } 21 return true; 22 } 23} 24 25// 26// CustomTextBox を沢山配置したフォーム 27// 28public class Form1 { 29 30 // 31 // このボタンクリックはForm上のどのコントロールにフォーカスが当たっていても 32 // ショートカットキーで呼び出すことが可能 33 // 34 private void button1_Click(object sender, EventArgs e) 35 { 36 var controls = 画面上のチェック対象コントロール全て; 37 if (CheckAllControls(controls)) { 38 return; 39 } 40 } 41 42 private bool CheckAllControls(List<Control> controls) { 43 // フォーカスの当たっているコントロールに不正な値が入っていないか確認 44 var validator = ActiveControl as IValidator; 45 if (validator != null) { 46 if(! validator.ValidateInvalidValue()) { 47 return false; 48 } 49 } 50 51 // 全体のチェック 52 } 53} 54

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

papinianus

2019/06/13 10:29

this.Focus()ってなんの意味でやってるのか、どなたか教えて下さい
guest

回答3

0

ベストアンサー

イベントは能動的に呼び出すものではありません。イベントから呼び出して実際の仕事を行うメソッドを作り、それを複数箇所から呼び出してください。

投稿2019/06/13 08:58

Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tec

2019/06/14 00:31

javascript の trigger('イベント名')みたいなのが欲しかったのですが、 c#では出来ないものなんですね。 ActiveControlが何か判断がつかないので、 OnValidating() を呼ぶための CallValidating() を持ったインターフェースを実装して、 間接的に呼ぶようにしてみます。
Zuishin

2019/06/14 00:39

そうではなく、OnValidating の中身を丸々別の public なメソッドに移し、OnValidating からそれを呼んでください。処理は正しい文脈で呼ばなければ保守が大変になります。
tec

2019/06/14 00:55

「登録されているイベントを個別に実行するインターフェース」よりも、 「入力チェックするインターフェース」の方が良いのでしょうか? たしかに「イベント」を呼びたいわけではなく「イベント内の処理」を呼びたいので、 教えて頂いたやり方の方が良い気がしてきます
Zuishin

2019/06/14 01:00

そうです。イベントを起こすのは UI の役目なので、コードで発生させるのは他にどうしようもない時の最後の手段です。またその方がテストも作りやすくなります。
guest

0

イベントの概念についての理解がおかしい気がします。

イベントというのは何らかの事象が発生したことをそのコンポーネント(クラス)の「外部」に通知するためのものですので、今回の例で言えばCustomTextBoxのイベントをForm上から発火しようとしているのがまずイベントの使い方として間違っています。

Form上で実装するのはそのイベントの通知を受けて実行する処理(イベントハンドラ)です。

実際のチェックはそのイベントハンドラ内で「チェック処理」というメソッドを呼び出すようにしてやればいいので、今回のケースだとCustomTextBoxでOnValidatingをオーバーライドしているのもちょっと意図がよくわかりません。

VBのRaiseEventを例として挙げられていますが、それもイベントを発火するクラス(今回の例で言えばCustomTextBox)の「内部」で使うものであり、「外部」から使うものではありません。(つまりC#だからできない、というわけではありません)

リフレクションを使う方法も、仮にそれで上手くいったとしても論外です。

入力値検証をValidatingイベントを使ってやる場合、そのタイミングのコントロールはForm.AutoValidateプロパティやControl.CausesValidationでタイミングを制御するものですので、そこら辺の使い方を調べられると良いと思います。

投稿2019/06/14 01:41

編集2019/06/14 01:42
gentaro

総合スコア8949

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tec

2019/06/14 02:55

「イベント」は「呼ばれるもの」であり「呼ぶもの」ではないということですよね。 その辺りの感覚がまだ理解できていないと思います。 >今回のケースだとCustomTextBoxでOnValidatingをオーバーライドしているのもちょっと意図がよくわかりません。 CustomTextBoxはどの画面でも共通で利用するコントロールとして使っています。 その際に決まった入力値エラー(例えばありえない日付を入力した等)の場合の処理をOnValidating内で実装しています。 その他のチェック処理(必須だとか、大小だとか、画面によるもの)に関しては、全体のチェック処理の中で行っており、 そこにOnValidatingで行っているチェック処理を入れるというのは不要だと思っていました。 全体チェック時に不正値を検出すれば良いという方針も有りですし、 不正値の場合は入力が無かったことにするというのも有りだとは思いますが、 システムの方針上その場でユーザに再入力させるものとして、今回のような実装にしてます。 >Form.AutoValidateプロパティやControl.CausesValidationでタイミングを制御するものですので、そこら辺の使い方を調べられると良いと思います。 全体チェックの直前に「Form.AutoValidate = AutoValidate.Disable」とした場合、 不正な入力値が残ったまま、その他のコントロールにフォーカスが当たってしまうため、 採用できませんでした。
guest

0

上記のコードであるなら、CustomTextBox から button1 にフォーカスが移動した時点で CustomTextBox.Validating が呼ばれます。また、「現在フォーカスのあるCustomTextBox.Validateを実行」と書かれていますが、Button.Click が呼ばれた時点でフォーカスは移動しています。どうやって「現在(というか、直前に)フォーカスのある CustomTextBox」を取得しますか。
いろいろなイベントをとりあえ全てハンドリングして、デバッグでイベントの名前を出力することで、どのようなときに、どのような順序でイベントが発生するか、調べるといいと思います。

投稿2019/06/13 13:15

Q71

総合スコア995

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tec

2019/06/14 00:18

申し訳ありません、前提条件が抜けていましたので追記しました。 button1_click()はForm上のどこからでも直接呼び出せる実装なので、 実際にはOnValidatingより先にbutton1_click()が呼ばれることになります。
Q71

2019/06/14 02:13

C#は object oriented language です。objectは「目的」、orientedは「深く考える」です。 それぞれのメソッドの目的は何ですか。その目的に合致した内容になっていますか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問