回答編集履歴

1

追記

2018/01/09 04:14

投稿

Zuishin
Zuishin

スコア28673

test CHANGED
@@ -1,7 +1,167 @@
1
- await で一度イベントハンドラが終了します。その時 e.Cancel は true です。
1
+ `await` で一度イベントハンドラが終了します。その時 `e.Cancel``true` です。
2
2
 
3
3
  ですのでフォームは閉じません。
4
4
 
5
5
 
6
6
 
7
- しかし e.Cancel が評価される前にタスクが終了して e.Cancel が書き換えられるとフォームは閉じます。
7
+ しかし `e.Cancel` が評価される前にタスクが終了して `e.Cancel` が書き換えられるとフォームは閉じます。
8
+
9
+
10
+
11
+ 追記
12
+
13
+
14
+
15
+ わかりにくかったかもしれないので順を追って説明します。
16
+
17
+
18
+
19
+ これは `System.Windows.Forms.Form` のソースです。
20
+
21
+ [Form.cs](http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Form.cs,3519)
22
+
23
+ ```C#
24
+
25
+ OnFormClosing(e);
26
+
27
+ if (e.Cancel)
28
+
29
+ {
30
+
31
+ dialogResult = DialogResult.None;
32
+
33
+ }
34
+
35
+ else
36
+
37
+ {
38
+
39
+ // we have called closing here, and it wasn't cancelled, so we're expecting a close
40
+
41
+ // call again soon.
42
+
43
+ CalledClosing = true;
44
+
45
+ }
46
+
47
+ ```
48
+
49
+
50
+
51
+ 上記の `OnFormClosing(e);` で `FormClosing` イベントハンドラを(あれば)呼びます。
52
+
53
+ ユーザーはハンドラの中で `e.Cancel` を設定します。
54
+
55
+ イベントハンドラが次のようになっている場合
56
+
57
+
58
+
59
+ ```C#
60
+
61
+ private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
62
+
63
+ {
64
+
65
+ e.Cancel = true;
66
+
67
+ await Task.Run(() =>
68
+
69
+ {
70
+
71
+ return;
72
+
73
+ });
74
+
75
+ e.Cancel = false;
76
+
77
+ }
78
+
79
+ ```
80
+
81
+
82
+
83
+ `await` によって一度ハンドラが終了するので、次のようなハンドラを指定したのと同じことになります。
84
+
85
+
86
+
87
+ ```C#
88
+
89
+ private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
90
+
91
+ {
92
+
93
+ e.Cancel = true;
94
+
95
+ }
96
+
97
+ ```
98
+
99
+
100
+
101
+ そして同時に次の非同期処理が登録されます。
102
+
103
+ (実際に実行されるのは同時とは限りません)
104
+
105
+
106
+
107
+ ```C#
108
+
109
+ Task.Run(() =>
110
+
111
+ {
112
+
113
+ return;
114
+
115
+ });
116
+
117
+ e.Cancel = false;
118
+
119
+ ```
120
+
121
+
122
+
123
+ この非同期処理は `return` のみのタスクを実行し、それが終了すると `e.Cancel = false` というタスクを実行しますので、整理すると次の内容とほぼ同じです。
124
+
125
+
126
+
127
+ ```C#
128
+
129
+ Task.Run(() =>
130
+
131
+ {
132
+
133
+ e.Cancel = false;
134
+
135
+ });
136
+
137
+ ```
138
+
139
+
140
+
141
+ さてこの非同期処理がいつ行われるかですが、それは実行してみるまでわかりません。
142
+
143
+ この処理によって `e.Cancel` が書き換えられるわけですが、それが `Form.cs` 中の
144
+
145
+
146
+
147
+ ```C#
148
+
149
+ if (e.Cancel)
150
+
151
+ ```
152
+
153
+
154
+
155
+ この部分より前に行われると、`e.Cancel` は `false` となって `else` ブロックが実行されます。
156
+
157
+ また、後に行われたならば真のブロックが実行されます。
158
+
159
+
160
+
161
+ 重たい処理の場合はおそらく間に合わないので `e.Cancel` は `true` となります。
162
+
163
+ 二番目の例の場合は間に合うか間に合わないかは状況次第です。
164
+
165
+
166
+
167
+ 以上が処理の流れとなります。