回答編集履歴

1

コレクションのアイテムの変更通知について追記

2016/08/06 08:42

投稿

flied_onion
flied_onion

スコア2604

test CHANGED
@@ -251,3 +251,247 @@
251
251
  }
252
252
 
253
253
  ```
254
+
255
+ ---
256
+
257
+ ## 追記
258
+
259
+
260
+
261
+ 上記のListName0 と ListName1 を別個のプロパティではなく、配列 ListName[] として持たせたいということですね。
262
+
263
+
264
+
265
+ この場合、ListNameのsetterの処理によってRaisePropertyChangedが呼ばれても、そもそも 配列ListNameをまるごと更新することはないので、そのsetterは使わることがなく、RaisePropertyChangedが発行されることはありません。
266
+
267
+
268
+
269
+ * MyModel のプロパティを配列にした場合
270
+
271
+ (MainWindowの変更は省略。Bindingに設定するnameは `"ListName[" + iKoumokuNo + "]";` にすれば良い)
272
+
273
+ ```cs
274
+
275
+ private string[] listName = {"Hello 0", "Hello 1"};
276
+
277
+ public string[] ListName {
278
+
279
+ get { return listName; }
280
+
281
+ set { SetProperty(ref listName, value, "ListName"); }
282
+
283
+ }
284
+
285
+ ```
286
+
287
+
288
+
289
+ このセッターは要素への代入では呼ばれない。
290
+
291
+ ```cs
292
+
293
+ private void Button_Click(object sender, RoutedEventArgs e) {
294
+
295
+ vm.ListName[0] = "a"; // これではListNameのセッターは呼ばれない
296
+
297
+ ```
298
+
299
+
300
+
301
+ 一番単純な解決策は、要素へのSetメソッドを用意してPropertyChangedを呼ぶことです。
302
+
303
+
304
+
305
+ MyModel
306
+
307
+ ```
308
+
309
+ public void SetListName(int index, string value) {
310
+
311
+ listName[index] = value;
312
+
313
+ var h = PropertyChanged;
314
+
315
+ if (h != null)
316
+
317
+ h(this, new PropertyChangedEventArgs("ListName"));
318
+
319
+ }
320
+
321
+ ```
322
+
323
+
324
+
325
+ MainWindow#Button_Click
326
+
327
+ ```
328
+
329
+ private void Button_Click(object sender, RoutedEventArgs e) {
330
+
331
+ vm.SetListName(0, "a");
332
+
333
+ vm.SetListName(1, "b");
334
+
335
+ }
336
+
337
+ ```
338
+
339
+
340
+
341
+ ただ使い方が変わるので扱いにくいですね。
342
+
343
+ WPFには `System.Collections.ObjectModel.ObservableCollection<T>` があるのでこれを利用することができます。
344
+
345
+
346
+
347
+ ```cs
348
+
349
+ // using System.Collections.ObjectModel; を追加する。
350
+
351
+ public partial class MainWindow : Window {
352
+
353
+ public MainWindow() {
354
+
355
+ InitializeComponent();
356
+
357
+ }
358
+
359
+
360
+
361
+ private MyModel vm = new MyModel();
362
+
363
+ private void Window_Loaded(object sender, RoutedEventArgs e) {
364
+
365
+
366
+
367
+ List<Label> labelns = new List<Label> { Label0, Label1 };
368
+
369
+ for (var i = 0; i < labelns.Count; i++) {
370
+
371
+ Binding textNamebinding = new Binding();
372
+
373
+ var iKoumokuNo = i; var iLabelNo = i;
374
+
375
+ string name = "ListName[" + iKoumokuNo + "]";
376
+
377
+ textNamebinding.Path = new PropertyPath(name);
378
+
379
+ textNamebinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
380
+
381
+ BindingOperations.SetBinding(labelns[iLabelNo], Label.ContentProperty, textNamebinding);
382
+
383
+ }
384
+
385
+
386
+
387
+ this.DataContext = vm;
388
+
389
+ }
390
+
391
+
392
+
393
+ private void Button_Click(object sender, RoutedEventArgs e) {
394
+
395
+ vm.ListName[0] = "a";
396
+
397
+ vm.ListName[1] = "b";
398
+
399
+ }
400
+
401
+
402
+
403
+
404
+
405
+ public class MyModel : INotifyPropertyChanged {
406
+
407
+ private ObservableCollection<string> listName = new ObservableCollection<string>();
408
+
409
+
410
+
411
+ public MyModel() {
412
+
413
+ listName.Add("Hello 0");
414
+
415
+ listName.Add("Hello 1");
416
+
417
+
418
+
419
+ listName.CollectionChanged += listName_CollectionChanged;
420
+
421
+ }
422
+
423
+
424
+
425
+
426
+
427
+ public ObservableCollection<string> ListName {
428
+
429
+ get {
430
+
431
+ return listName;
432
+
433
+ }
434
+
435
+ set {
436
+
437
+ SetProperty(ref listName, value, "ListName");
438
+
439
+ }
440
+
441
+ }
442
+
443
+
444
+
445
+ void listName_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
446
+
447
+ // 項目の変更やリスト全体の変更時に発生するイベント
448
+
449
+ var h = PropertyChanged;
450
+
451
+ if (h != null)
452
+
453
+ h(this, new PropertyChangedEventArgs("ListName"));
454
+
455
+
456
+
457
+ }
458
+
459
+
460
+
461
+ public virtual bool SetProperty(ref ObservableCollection<string> target, ObservableCollection<string> value, string name) {
462
+
463
+ // サンプルでは使ってないのでnullチェック省略省略
464
+
465
+ target = value;
466
+
467
+ RaisePropertyChanged(name);
468
+
469
+ return true;
470
+
471
+ }
472
+
473
+
474
+
475
+ protected virtual void RaisePropertyChanged(string name) {
476
+
477
+ var h = PropertyChanged;
478
+
479
+ if (h != null)
480
+
481
+ h(this, new PropertyChangedEventArgs(name));
482
+
483
+ }
484
+
485
+
486
+
487
+ public event PropertyChangedEventHandler PropertyChanged;
488
+
489
+ }
490
+
491
+ }
492
+
493
+ ```
494
+
495
+
496
+
497
+ もっと良いやり方もあるかもしれませんが、これで目的は達成できるかと思います。