質問するログイン新規登録

回答編集履歴

2

一部訂正

2016/11/08 05:24

投稿

KSwordOfHaste
KSwordOfHaste

スコア18406

answer CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  多重にハンドラーを登録してしまうことを防ぐ管理コードの一例。
8
8
 
9
- あくまで実装のイメージを示すだけのものです。本来は登録解除の機能やDisposeしたコントローラーに対して(WeakReferenceを使って)自動的に登録解除したりする仕組みを実装しないと使い物にならないと思います。下記の例では簡単のためTargetEventをstructにしてますがvalur type/classのどちらが適切かは最終実装によってかわるかもしれません。また当然ながらxamlで登録されたハンドラーについては対処のしようがないため、この仕組みを使うコントローラーイベントはxamlで登録しないことが前提になります。
9
+ あくまで実装のイメージを示すだけのものです。本来は登録解除の機能やDisposeしたコントローラーに対して(WeakReferenceを使って)自動的に登録解除したりする仕組みを実装しないと使い物にならないと思います。下記の例では簡単のためTargetEventをstructにしてますがvalur type/classのどちらが適切かは最終実装によってかわるかもしれません。また当然ながらxamlで登録されたハンドラーについては対処のしようがないため、この仕組みを使うコントローラー(ンスタンス)のイベントはxamlで定義しないことが前提になります(xamlで静的に記述したインスタンスのイベントは動的にハンドラーを追加することはないと思えるのでおそらく質問者さんが取り組んでおられるプログラムでは問題にならないと推測します)
10
10
 
11
11
  先にも書いたようにeventは+=/-=の左辺にしか使えず(他のメソッドの引数に渡すことさえできない)のでどうしてもこのような迂遠な実装になると思います。(リフレクションとunsafeコードを使うともう少しましにできるのかも知れませんが自分には可能かどうかわかりません)
12
12
 

1

追記

2016/11/08 05:23

投稿

KSwordOfHaste
KSwordOfHaste

スコア18406

answer CHANGED
@@ -1,3 +1,53 @@
1
1
  eventに対して可能な操作は+=/-=のみですが、自分はそれを「その操作だけあればeventへの操作は十分であると言語仕様策定者が想定している」と解釈します。つまりeventへハンドラーを登録する契機はそのイベントを持つオブジェクトが活動を開始する以前のタイミングで一度だけ登録すれば十分であり、登録されていなければ登録するという操作は典型的な使い方では必要ないという判断なのだと思います。
2
2
 
3
- ハンドラーが登録済みかどうかの判断機能は提供されてないので、必要ならば自分自身で管理するためのコードを書くことになろうかと思います。
3
+ ハンドラーが登録済みかどうかの判断機能は提供されてないので、必要ならば自分自身で管理するためのコードを書くことになろうかと思います。
4
+
5
+ ---
6
+
7
+ 多重にハンドラーを登録してしまうことを防ぐ管理コードの一例。
8
+
9
+ あくまで実装のイメージを示すだけのものです。本来は登録解除の機能やDisposeしたコントローラーに対して(WeakReferenceを使って)自動的に登録解除したりする仕組みを実装しないと使い物にならないと思います。下記の例では簡単のためTargetEventをstructにしてますがvalur type/classのどちらが適切かは最終実装によってかわるかもしれません。また当然ながらxamlで登録されたハンドラーについては対処のしようがないため、この仕組みを使うコントローラーとイベントはxamlで登録しないことが前提になります。
10
+
11
+ 先にも書いたようにeventは+=/-=の左辺にしか使えず(他のメソッドの引数に渡すことさえできない)のでどうしてもこのような迂遠な実装になると思います。(リフレクションとunsafeコードを使うともう少しましにできるのかも知れませんが自分には可能かどうかわかりません)
12
+
13
+ ```c#
14
+ public enum EventCode {
15
+ CLICKED,
16
+ ...
17
+ }
18
+ public static class HandlerManager {
19
+ private struct TargetEvent {
20
+ public Control TargetControl;
21
+ public EventCode EventCode;
22
+ }
23
+
24
+ private static Dictionary<TargetEvent, EventHandler> registory
25
+ = new Dictionary<TargetEvent, EventHandler>();
26
+
27
+ public static bool RegisterIfAny(Control c, EventCode ec, EventHandler handler) {
28
+ TargetEvent te = new TargetEvent { TargetControl = c, EventCode = ec };
29
+ EventHandler h;
30
+ if (registory.TryGetValue(te, out h)) {
31
+ return false;
32
+ } else {
33
+ registory.Add(te, handler);
34
+ return true;
35
+ }
36
+ }
37
+ }
38
+
39
+ // 上記を使ったハンドラー登録の例
40
+
41
+ public partial class Form1 : Form {
42
+ public Form1() {
43
+ InitializeComponent();
44
+ // 以下のように2回登録しても最初しか登録されない
45
+ if (HandlerManager.RegisterIfAny(button1, EventCode.CLICKED, button1_Click))
46
+ button1.Click += button1_Click;
47
+ if (HandlerManager.RegisterIfAny(button1, EventCode.CLICKED, button1_Click))
48
+ button1.Click += button1_Click;
49
+ }
50
+ }
51
+ ...
52
+ }
53
+ ```