回答編集履歴

5

SetValue をこっそり追加

2018/09/17 15:08

投稿

Zuishin
Zuishin

スコア28660

test CHANGED
@@ -190,6 +190,20 @@
190
190
 
191
191
 
192
192
 
193
+ protected void SetValue<T>(ref T field, T value, [CallerMemberName]string propertyName = null)
194
+
195
+ {
196
+
197
+ if (Equals(field, value)) return;
198
+
199
+ field = value;
200
+
201
+ OnPropertyChanged(propertyName);
202
+
203
+ }
204
+
205
+
206
+
193
207
  private bool unlocked = false;
194
208
 
195
209
  public bool Unlocked
@@ -198,17 +212,7 @@
198
212
 
199
213
  get => unlocked;
200
214
 
201
- set
202
-
203
- {
204
-
205
- if (unlocked == value) return;
215
+ set => SetValue(ref unlocked, value);
206
-
207
- unlocked = value;
208
-
209
- OnPropertyChanged();
210
-
211
- }
212
216
 
213
217
  }
214
218
 

4

ローカル変数を使わないようこっそり修正

2018/09/17 15:08

投稿

Zuishin
Zuishin

スコア28660

test CHANGED
@@ -158,8 +158,6 @@
158
158
 
159
159
  .ToArray();
160
160
 
161
- var list = Enumerable.Empty<Button>();
162
-
163
161
  keys
164
162
 
165
163
  .Select(key => key.button)
@@ -176,19 +174,15 @@
176
174
 
177
175
  .Aggregate((a, b) => a.Merge(b))
178
176
 
177
+ .Scan(Enumerable.Empty<Button>(),
178
+
179
+ (list, button) => new[] { button }.Concat(list).Take(orders.Length))
180
+
179
- .Subscribe(button =>
181
+ .Subscribe(buttons =>
180
182
 
181
183
  {
182
184
 
183
- list = new[] { button }
184
-
185
- .Concat(list)
186
-
187
- .Take(orders.Length)
188
-
189
- .ToList();
190
-
191
- Unlocked = list.SequenceEqual(orders);
185
+ Unlocked = buttons.SequenceEqual(orders);
192
186
 
193
187
  });
194
188
 

3

追記

2018/09/17 14:57

投稿

Zuishin
Zuishin

スコア28660

test CHANGED
@@ -104,6 +104,8 @@
104
104
 
105
105
  プロジェクトに新しいクラスを追加し、次のように書き換えてください。
106
106
 
107
+ そしてここで一度ビルドしてください。
108
+
107
109
 
108
110
 
109
111
  ```C#

2

追記

2018/09/17 13:55

投稿

Zuishin
Zuishin

スコア28660

test CHANGED
@@ -244,7 +244,7 @@
244
244
 
245
245
 
246
246
 
247
- Form1 のソース開き、次のように書き換えてください。
247
+ デザイナーで button3ダブルクリックし、次のように書き換えてください。
248
248
 
249
249
 
250
250
 

1

追記

2018/09/17 11:54

投稿

Zuishin
Zuishin

スコア28660

test CHANGED
@@ -67,3 +67,265 @@
67
67
 
68
68
 
69
69
  ただ、Windows Forms は圧倒的に学習コストは低く、現役で十分使えるパワーも持っていますから、無理にモダンを目指さずそこから入るのが楽しいと思います。
70
+
71
+
72
+
73
+ #追記(余談)
74
+
75
+
76
+
77
+ データバインディングと Reactive Extensions を使ったモダンっぽい書き方の例です。
78
+
79
+
80
+
81
+ ###ソリューションの作成
82
+
83
+
84
+
85
+ Windows Forms プロジェクトを作成し、ボタンを 3 つ貼り付け、必ず名前を付けて保存してください。
86
+
87
+ ここでは WindowsFormsApp1 としました。
88
+
89
+
90
+
91
+ ###Reactive Extensions のインストール
92
+
93
+
94
+
95
+ パッケージマネージャーコンソールを開き、`Install-Package System.Reactive` とコマンドを実行してください。
96
+
97
+ これはソリューション毎にインストールされますので、別のソリューションでも使いたい場合にはその都度インストールする必要があります。
98
+
99
+
100
+
101
+ ###Unlock クラスの作成
102
+
103
+
104
+
105
+ プロジェクトに新しいクラスを追加し、次のように書き換えてください。
106
+
107
+
108
+
109
+ ```C#
110
+
111
+ using System;
112
+
113
+ using System.ComponentModel;
114
+
115
+ using System.Linq;
116
+
117
+ using System.Reactive.Linq;
118
+
119
+ using System.Runtime.CompilerServices;
120
+
121
+ using System.Windows.Forms;
122
+
123
+
124
+
125
+ namespace WindowsFormsApp1
126
+
127
+ {
128
+
129
+ public class Unlock : INotifyPropertyChanged
130
+
131
+ {
132
+
133
+ public event PropertyChangedEventHandler PropertyChanged;
134
+
135
+
136
+
137
+ protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
138
+
139
+ {
140
+
141
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
142
+
143
+ }
144
+
145
+
146
+
147
+ public Unlock(params (Button button, int count)[] keys)
148
+
149
+ {
150
+
151
+ var orders = keys
152
+
153
+ .SelectMany(key => Enumerable.Repeat(key.button, key.count))
154
+
155
+ .Reverse()
156
+
157
+ .ToArray();
158
+
159
+ var list = Enumerable.Empty<Button>();
160
+
161
+ keys
162
+
163
+ .Select(key => key.button)
164
+
165
+ .Distinct()
166
+
167
+ .Select(button => Observable
168
+
169
+ .FromEventPattern<EventArgs>(button, nameof(button.Click))
170
+
171
+ .Select(eventArgs => eventArgs.Sender)
172
+
173
+ .OfType<Button>())
174
+
175
+ .Aggregate((a, b) => a.Merge(b))
176
+
177
+ .Subscribe(button =>
178
+
179
+ {
180
+
181
+ list = new[] { button }
182
+
183
+ .Concat(list)
184
+
185
+ .Take(orders.Length)
186
+
187
+ .ToList();
188
+
189
+ Unlocked = list.SequenceEqual(orders);
190
+
191
+ });
192
+
193
+ }
194
+
195
+
196
+
197
+ private bool unlocked = false;
198
+
199
+ public bool Unlocked
200
+
201
+ {
202
+
203
+ get => unlocked;
204
+
205
+ set
206
+
207
+ {
208
+
209
+ if (unlocked == value) return;
210
+
211
+ unlocked = value;
212
+
213
+ OnPropertyChanged();
214
+
215
+ }
216
+
217
+ }
218
+
219
+ }
220
+
221
+ }
222
+
223
+ ```
224
+
225
+
226
+
227
+ ###ボタンと Unlock をバインド
228
+
229
+
230
+
231
+ デザイナーを開き、button3 のプロパティを開き、(DataBindings) を展開し、「詳細」の「…」をクリックしてください。
232
+
233
+ プロパティペインから Enabled を選択し、バインドコンボボックスをドロップダウンし、「プロジェクトデータソースの追加…」をクリックしてください。
234
+
235
+ 「オブジェクト」を選択して「次へ」
236
+
237
+ 「Unlock」にチェックをつけて「完了」
238
+
239
+ 「OK」で閉じると、「unlockBindingSource」がフォームに追加され、button3.Enabled がそれとバインドされます。
240
+
241
+
242
+
243
+ ###Form1
244
+
245
+
246
+
247
+ Form1 のソースを開き、次のように書き換えてください。
248
+
249
+
250
+
251
+ ```C#
252
+
253
+ using System;
254
+
255
+ using System.Windows.Forms;
256
+
257
+
258
+
259
+ namespace WindowsFormsApp1
260
+
261
+ {
262
+
263
+ public partial class Form1 : Form
264
+
265
+ {
266
+
267
+ public Form1()
268
+
269
+ {
270
+
271
+ InitializeComponent();
272
+
273
+ Unlock = new Unlock((button1, 1), (button2, 2), (button1, 1));
274
+
275
+ }
276
+
277
+
278
+
279
+ public Unlock Unlock
280
+
281
+ {
282
+
283
+ get => (Unlock)unlockBindingSource.DataSource;
284
+
285
+ set => unlockBindingSource.DataSource = value;
286
+
287
+ }
288
+
289
+
290
+
291
+ private void button3_Click(object sender, EventArgs e)
292
+
293
+ {
294
+
295
+ if (!Unlock.Unlocked) return;
296
+
297
+ MessageBox.Show("ガチャッ");
298
+
299
+ }
300
+
301
+ }
302
+
303
+ }
304
+
305
+ ```
306
+
307
+
308
+
309
+ ###実行
310
+
311
+
312
+
313
+ 実行し、button1 を 1 回、button2 を 2 回、button1 を 1 回、この順に押してください。
314
+
315
+ button3 が押せるようになるので、それをクリックすると「ガチャッ」と表示されます。
316
+
317
+ この回数は Form1 のコンストラクタの以下の部分で指定しています。
318
+
319
+
320
+
321
+ ```C#
322
+
323
+ Unlock = new Unlock((button1, 1), (button2, 2), (button1, 1));
324
+
325
+ ```
326
+
327
+
328
+
329
+ これと同じことを真正直にしようと思えば、button1 button2 をクリックされた時に複雑なフラグ管理をしなければいけませんが、Reactive Extensions と LINQ を使うとこんなにすっきりと書くことができます。
330
+
331
+ 最初は読みにくいと思いますが、読み慣れたらなんということはありません。