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

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

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

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

Visual Studio 2013

Microsoft Visual Studio 2013は、Microsoftによる統合開発環境(IDE)であり、多種多様なプログラミング言語に対応しています。 Visual Studio 2012の次のバージョンです

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

Q&A

解決済

1回答

4006閲覧

TextBox.KeyPress イベントに指定するメソッド内部で、事前に作成したオブジェクトを利用したい

cha-ra

総合スコア40

C#

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

Visual Studio 2013

Microsoft Visual Studio 2013は、Microsoftによる統合開発環境(IDE)であり、多種多様なプログラミング言語に対応しています。 Visual Studio 2012の次のバージョンです

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

0グッド

1クリップ

投稿2016/07/12 07:28

###前提・実現したいこと
TextBox.KeyPress イベントに指定するメソッド内部で、
事前に作成したオブジェクトを利用したい。

###該当のソースコード

c#

1private void EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) { 2 3 TextBox tb = (DataGridViewTextBoxEditingControl)e.Control; 4 // 5 // 6 // ここで生成したオブジェクトを、MyKeyPress内で利用したい 7 // このオブジェクトは列毎・画面毎に設定する内容が変わります。 8 Foo foo = new Foo(); 9 foo.Length = 5; 10 foo.Scale = 3; 11 12 // イベントは削除できるが、Fooオブジェクトを利用する方法がわからない 13 tb.KeyPress -= new KeyPressEventHandler(MyKeyPress); 14 tb.KeyPress += new KeyPressEventHandler(MyKeyPress); 15 16 // これではイベントが消えないが、Fooオブジェクト自体は利用できた 17 tb.KeyPress -= createHandler(foo); 18 tb.KeyPress += createHandler(foo); 19} 20 21private void MyKeyPress(object sender, KeyPressEventArgs e) { 22 int len = foo.Length; 23 int scale = foo.Scale; 24} 25 26public KeyPressEventHandler createHandler(Foo foo) { 27 return (sender, e) => { 28 int len = foo.Length; 29 int scale = foo.Scale; 30 }; 31} 32

###試したこと
ユーティリティクラスに、引数Fooを取るKeyPressEventHandlerを返すメソッドを作成しましたが、
その方法では イベントの削除が出来ませんでした。

###補足情報
DataGridView内のセル編集時に、数値・小数の列を編集する場合に、
文字入力不可・指定桁数を超えた入力不可とする処理を作成しています。
小数列の場合は整数部Length桁、小数部Scale桁として定義し、
KeyPress時にその桁数を超える場合は入力を無視させます。

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

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

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

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

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

guest

回答1

0

ベストアンサー

foo のスコープが EditingControlShowing に限定されていますので、MyKeyPress では無効です。次のようにしてください。

C#

1private Foo foo = new Foo(); 2 3private void EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) { 4 5 TextBox tb = (DataGridViewTextBoxEditingControl)e.Control; 6 // 7 // 8 // ここで生成したオブジェクトを、MyKeyPress内で利用したい 9 // このオブジェクトは列毎・画面毎に設定する内容が変わります。 10 foo.Length = 5; 11 foo.Scale = 3; 12 13 // イベントは削除できるが、Fooオブジェクトを利用する方法がわからない 14 tb.KeyPress -= new KeyPressEventHandler(MyKeyPress); 15 tb.KeyPress += new KeyPressEventHandler(MyKeyPress); 16 17 // これではイベントが消えないが、Fooオブジェクト自体は利用できた 18 tb.KeyPress -= createHandler(foo); 19 tb.KeyPress += createHandler(foo); 20} 21 22private void MyKeyPress(object sender, KeyPressEventArgs e) { 23 int len = foo.Length; 24 int scale = foo.Scale; 25} 26 27public KeyPressEventHandler createHandler(Foo foo) { 28 return (sender, e) => { 29 int len = foo.Length; 30 int scale = foo.Scale; 31 }; 32}

###追記
このような方法もあります。

C#

1private KeyPressEventHandler keyPress; 2 3private void EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) 4{ 5 TextBox tb = (DataGridViewTextBoxEditingControl)e.Control; 6 // 7 // 8 // ここで生成したオブジェクトを、MyKeyPress内で利用したい 9 // このオブジェクトは列毎・画面毎に設定する内容が変わります。 10 Foo foo = new Foo(); 11 foo.Length = 5; 12 foo.Scale = 3; 13 14 if (keyPress == null) 15 { 16 keyPress = createHandler(foo); 17 } 18 tb.KeyPress -= keyPress; 19 tb.KeyPress += keyPress; 20} 21 22public KeyPressEventHandler createHandler(Foo foo) 23{ 24 return (sender, e) => 25 { 26 int len = foo.Length; 27 int scale = foo.Scale; 28 }; 29}

投稿2016/07/12 13:44

編集2016/07/13 02:32
Zuishin

総合スコア28660

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

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

cha-ra

2016/07/13 00:20

回答ありがとうございます。 私の記述があまり正確でなかった為、誤解させてしまったようです。 自画面のみの処理でしたら、提示して頂いた方法やその他の方法が使えるのですが、 MyKeyPress、またはcreateHandlerはユーティリティクラスに定義し、 各画面から利用したいので、ローカルのインスタンスには値を持たせられない次第です。 それとも、ユーティリティクラスに値の受け渡し用の静的なインスタンスを用意して、 各画面から利用したほうが良いのでしょうか? WindowsFormアプリケーションだと、同時に複数人がアクセスすることも無いのかもしれない為、そのような実装をしてよいものか悩んでいました。
Zuishin

2016/07/13 00:40

方法はたくさんありますが、こちらがその中から適切な方法を選ぶには情報が少なすぎます。 大まかに分けるなら、 (1)引数として渡す (2)ユーティリティークラスにインスタンスを渡すことのできるオブジェクトのプロパティとする (3)ユーティリティークラスの認識できるクラスの静的プロパティとする ですか。 もしくはアプローチを変えて (4)イベントは削除しない。ただし、イベントハンドラーから新たなイベントを発生させ、自クラスのメソッドをそこに登録する。それを削除することでイベントの削除とする。 という方法もとれます。 ユーティリティクラスで Foo を直接扱うなら、持たせてやって何の問題もないのではないかとこちらからは見えますが、何か理由がおありなのでしょう。 (1)に関しては、 (A)sender にイベントを発生させたインスタンスが入るはずなので、それを適切な型にキャストしてプロパティを取り出す (B)KeyEventArgs から継承した拡張 KeyEventArgs を渡す などの方法がとれます。 とにかく要点は一つです。 ローカル変数は他から参照できないので何らかの形で渡さなければならなりません。 またはユーティリティクラスで直接 Foo を扱わないよう仕様を変更しなければなりません。
cha-ra

2016/07/13 02:10

>(1)引数として渡す この方法を取れるのが一番良いのでしょうが、 TextBox.KeyPress イベントに、予めイベントを設定する場合には利用出来ませんでした(利用する方法がわかりませんでした)。 ※(A)は(DataGridViewTextBoxEditingControl : TextBox) が固定で入り、  (B)はKeyPressEventArgsのみ指定可で、継承したクラスではビルドエラーとなりました。 >ユーティリティクラスで Foo を直接扱うなら、持たせてやって何の問題もないのではないかとこちらからは見えますが、何か理由がおありなのでしょう。 ユーティリティクラスに状態を持つオブジェクトを用意すること自体今まで無かったので、戸惑っていたという次第です。 WindowsFormアプリケーションでは一般的というならば、特に問題ありません。
Zuishin

2016/07/13 02:23

(A)に関しては、DataGridViewTextBoxEditingControl を継承したクラスを使います。または簡単に FindForm() を使うことで、それの属するフォームを取得できます。 (B)に関しては、KeyPressEventArgs から継承したクラスを使うことでビルドエラーを防ぐことができます。EventArgs から継承しませんでしたか? ユーティリティクラスの設計としては、そのメソッドをイベントハンドラーにするというものこそ私には驚きですが、もともとそのように Windows.Forms と Foo に依存するよう設計されたクラスならば再利用性は低いので、特定の用途に合わせて使いやすいように作っていいのではないかと思います。
cha-ra

2016/07/13 02:54

そもそも私がやろうとしていた、共通利用するイベントハンドラー用メソッドという考え方自体がおかしかった様で申し訳ありませんでした。 KeyPressにハンドルするメソッドはForm側で定義することにし、 入力可否の処理をユーティリティクラスに持っていくことにします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問