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

回答編集履歴

4

追記

2018/10/14 09:47

投稿

Zuishin
Zuishin

スコア28675

answer CHANGED
@@ -68,4 +68,106 @@
68
68
  FromEvent はまず AddHandler を呼び出し、マウスイベントにイベントハンドラを登録します。
69
69
  そして必要な処理が終われば RemoveHandler を呼び出し、イベントハンドラを削除します。
70
70
  そして Mouse イベントが起こるたびに Conversion から返された action を呼び出します。
71
- h は FromEvent の登録したデリゲートで、これを呼び出すことにより、以降のオブザーバーに e を渡します。
71
+ h は FromEvent の登録したデリゲートで、これを呼び出すことにより、以降のオブザーバーに e を渡します。
72
+
73
+ #追記
74
+
75
+ Observable.FromEvent の中ではだいたいこんなことが行われていると思います。
76
+
77
+ ```C#
78
+ using System;
79
+ using System.Collections.Generic;
80
+ using System.Diagnostics;
81
+ using System.Reactive.Linq;
82
+ using System.Windows.Forms;
83
+
84
+ namespace WindowsFormsApp1
85
+ {
86
+ public partial class Form1 : Form
87
+ {
88
+ public Form1()
89
+ {
90
+ InitializeComponent();
91
+ }
92
+
93
+ private void button1_Click(object sender, EventArgs args)
94
+ {
95
+ MyObservable<MouseEventHandler, MouseEventArgs>
96
+ .FromEvent(
97
+ h => (s, e) => h(e),
98
+ h => MouseMove += h,
99
+ h => MouseMove -= h)
100
+ .Subscribe(e =>
101
+ {
102
+ Debug.WriteLine($"({e.X},{e.Y})");
103
+ });
104
+ }
105
+ }
106
+
107
+ class MyObservable<TEventHandler, TEventArgs> : IObservable<TEventArgs>
108
+ where TEventArgs : EventArgs
109
+ where TEventHandler : MulticastDelegate
110
+ {
111
+ protected IList<IObserver<TEventArgs>> Observers { get; } = new List<IObserver<TEventArgs>>();
112
+ protected Action<TEventHandler> AddHandler { get; private set; }
113
+ protected Action<TEventHandler> RemoveHandler { get; private set; }
114
+ protected TEventHandler EventHandler { get; private set; }
115
+
116
+ public static IObservable<TEventArgs> FromEvent(
117
+ Func<Action<TEventArgs>, TEventHandler> conversion,
118
+ Action<TEventHandler> addHandler,
119
+ Action<TEventHandler> removeHandler)
120
+ {
121
+ var result = new MyObservable<TEventHandler, TEventArgs>();
122
+ result.AddHandler = addHandler;
123
+ result.RemoveHandler = removeHandler;
124
+ result.EventHandler = conversion(result.Handler);
125
+ result.AddHandler?.Invoke(result.EventHandler);
126
+ return result;
127
+ }
128
+
129
+ private void Handler(TEventArgs e)
130
+ {
131
+ foreach (var observer in Observers)
132
+ {
133
+ observer.OnNext(e);
134
+ }
135
+ }
136
+
137
+ public IDisposable Subscribe(IObserver<TEventArgs> observer)
138
+ {
139
+ Observers.Add(observer);
140
+ return new Disposable(this, observer);
141
+ }
142
+
143
+ protected void RemoveObserver(IObserver<TEventArgs> observer)
144
+ {
145
+ if (Observers.Count == 0) return;
146
+ Observers.Remove(observer);
147
+ if (Observers.Count == 0)
148
+ {
149
+ RemoveHandler?.Invoke(EventHandler);
150
+ }
151
+ }
152
+
153
+ class Disposable : IDisposable
154
+ {
155
+ protected MyObservable<TEventHandler, TEventArgs> Owner { get; private set; }
156
+ protected IObserver<TEventArgs> Observer { get; private set; }
157
+
158
+ public Disposable(MyObservable<TEventHandler, TEventArgs> owner, IObserver<TEventArgs> observer)
159
+ {
160
+ Owner = owner;
161
+ Observer = observer;
162
+ }
163
+
164
+ public void Dispose()
165
+ {
166
+ if (Owner == null) return;
167
+ Owner.RemoveObserver(Observer);
168
+ Owner = null;
169
+ }
170
+ }
171
+ }
172
+ }
173
+ ```

3

修正

2018/10/14 09:47

投稿

Zuishin
Zuishin

スコア28675

answer CHANGED
@@ -67,5 +67,5 @@
67
67
  FromEvent の引数として、Conversion, AddHandler, RemoveHandler のデリゲートを渡しています。
68
68
  FromEvent はまず AddHandler を呼び出し、マウスイベントにイベントハンドラを登録します。
69
69
  そして必要な処理が終われば RemoveHandler を呼び出し、イベントハンドラを削除します。
70
- そして MouseMove イベントが起こるたびに Conversion から返された action を呼び出します。
70
+ そして Mouse イベントが起こるたびに Conversion から返された action を呼び出します。
71
71
  h は FromEvent の登録したデリゲートで、これを呼び出すことにより、以降のオブザーバーに e を渡します。

2

修正

2018/10/14 08:00

投稿

Zuishin
Zuishin

スコア28675

answer CHANGED
@@ -67,5 +67,5 @@
67
67
  FromEvent の引数として、Conversion, AddHandler, RemoveHandler のデリゲートを渡しています。
68
68
  FromEvent はまず AddHandler を呼び出し、マウスイベントにイベントハンドラを登録します。
69
69
  そして必要な処理が終われば RemoveHandler を呼び出し、イベントハンドラを削除します。
70
- そして MouseMove イベントが起こるたびに Conversion を呼び出します。
70
+ そして MouseMove イベントが起こるたびに Conversion から返された action を呼び出します。
71
71
  h は FromEvent の登録したデリゲートで、これを呼び出すことにより、以降のオブザーバーに e を渡します。

1

追記

2018/10/14 07:59

投稿

Zuishin
Zuishin

スコア28675

answer CHANGED
@@ -3,4 +3,69 @@
3
3
  わからなければ理解できません。
4
4
 
5
5
  ラムダ式については[ラムダ式っていうのが分かりません](https://teratail.com/questions/149408#reply-224905) で書いたので詳細は省略します。
6
- これでわからなければネット上に情報はたくさんありますので検索してみてください。
6
+ これでわからなければネット上に情報はたくさんありますので検索してみてください。
7
+
8
+ #追記
9
+
10
+ ラムダ式を使わず書いてみました。
11
+
12
+ ```C#
13
+ using System;
14
+ using System.Diagnostics;
15
+ using System.Reactive.Linq;
16
+ using System.Windows.Forms;
17
+
18
+ namespace WindowsFormsApp1
19
+ {
20
+ public partial class Form1 : Form
21
+ {
22
+ public Form1()
23
+ {
24
+ InitializeComponent();
25
+ }
26
+
27
+ private void button1_Click(object sender, EventArgs args)
28
+ {
29
+ Observable
30
+ .FromEvent<MouseEventHandler, MouseEventArgs>(
31
+ //h => (s, e) => h(e),
32
+ Conversion,
33
+
34
+ //h => this.MouseMove += h,
35
+ AddHandler,
36
+
37
+ //h => this.MouseMove -= h)
38
+ RemoveHandler)
39
+ .Subscribe(e =>
40
+ {
41
+ Debug.WriteLine($"({e.X},{e.Y})");
42
+ });
43
+ }
44
+
45
+ private MouseEventHandler Conversion(Action<MouseEventArgs> h)
46
+ {
47
+ void action(object s, MouseEventArgs e)
48
+ {
49
+ h(e);
50
+ }
51
+ return action;
52
+ }
53
+
54
+ private void AddHandler(MouseEventHandler h)
55
+ {
56
+ MouseMove += h;
57
+ }
58
+
59
+ private void RemoveHandler(MouseEventHandler h)
60
+ {
61
+ MouseMove -= h;
62
+ }
63
+ }
64
+ }
65
+ ```
66
+
67
+ FromEvent の引数として、Conversion, AddHandler, RemoveHandler のデリゲートを渡しています。
68
+ FromEvent はまず AddHandler を呼び出し、マウスイベントにイベントハンドラを登録します。
69
+ そして必要な処理が終われば RemoveHandler を呼び出し、イベントハンドラを削除します。
70
+ そして MouseMove イベントが起こるたびに Conversion を呼び出します。
71
+ h は FromEvent の登録したデリゲートで、これを呼び出すことにより、以降のオブザーバーに e を渡します。