回答編集履歴

1

見直しキャンペーン中

2023/07/27 14:34

投稿

TN8001
TN8001

スコア9884

test CHANGED
@@ -1,493 +1,248 @@
1
1
  > クリックされたセルの修正(プログラム側で)⇒ObservableCollectionの修正方法
2
2
 
3
-
4
-
5
3
  `ObservableCollection`はアイテムの増減を通知しますが、中のアイテムの状態は関知しません。
6
-
7
4
  [ObservableCollection<T> クラス (System.Collections.ObjectModel) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.objectmodel.observablecollection-1)
8
5
 
9
-
10
-
11
6
  [INotifyCollectionChanged インターフェイス (System.Collections.Specialized) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.specialized.inotifycollectionchanged)
12
7
 
13
-
14
-
15
8
  中のアイテムのプロパティの変更は、`INotifyPropertyChanged`を実装する必要があります。
16
-
17
9
  [INotifyPropertyChanged インターフェイス (System.ComponentModel) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.componentmodel.inotifypropertychanged)
18
10
 
19
-
20
-
21
11
  実例や詳細はいっぱい記事がありますので検索してください。
22
12
 
23
-
24
-
25
13
  > myData[row][col]="A"みたいに編集したりしたいです。
26
14
 
27
-
28
-
29
15
  インデクサを作ればそのようなアクセスはできますがうれしいですかね?
30
16
 
31
-
32
-
33
17
  ---
34
18
 
35
-
36
-
37
19
  CSVの編集ツールという感じなのでしょうか。
38
-
39
20
  「存在しないフォルダやファイルは入力させたくない&手入力はだるい」のでダイアログで選択するような仕様と。
40
21
 
41
22
  ソートやカラム移動を禁止しているので今の実装でも問題なさそうですが、`DataGridCell`にイベントを付けたほうがはるかに簡単だと思います。
42
-
43
23
  そうすれば禁止にする必要もなくなります(`Column.Header`で`switch`するのは微妙な気もしますが^^;
44
24
 
45
25
 
46
-
47
-
48
-
49
26
  注)カレントフォルダの扱いが違っていると思います(完動コードとして作りにくいので^^;
50
-
51
27
  注)新規行を追加するにはタイトルを先に入れる必要があります(先にカレントフォルダ等をダブルクリックしても無視する)
52
-
53
28
  [NuGet Gallery | Ookii.Dialogs.Wpf 3.1.0](https://www.nuget.org/packages/Ookii.Dialogs.Wpf/3.1.0)を使用
54
-
55
- ```xaml
29
+ ```xml
56
-
57
30
  <Window
58
-
59
31
  x:Class="Questions341357.MainWindow"
60
-
61
32
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
62
-
63
33
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
64
-
65
34
  Width="1000"
66
-
67
35
  Height="300"
68
-
69
36
  HorizontalAlignment="Center">
70
-
71
37
  <DockPanel>
72
-
73
38
  <StackPanel DockPanel.Dock="Bottom">
74
-
75
39
  <Button Click="ResetButton_Click" Content="リセット" />
76
-
77
40
  <Button Click="PrintButton_Click" Content="確認" />
78
-
79
41
  </StackPanel>
80
42
 
81
-
82
-
83
43
  <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Items}">
84
-
85
44
  <DataGrid.CellStyle>
86
-
87
45
  <Style TargetType="DataGridCell">
88
-
89
46
  <EventSetter Event="MouseDoubleClick" Handler="DataGridCell_MouseDoubleClick" />
90
-
91
47
  </Style>
92
-
93
48
  </DataGrid.CellStyle>
94
-
95
49
  <DataGrid.Columns>
96
-
97
50
  <DataGridTextColumn Binding="{Binding Title}" Header="タイトル" />
98
-
99
51
  <DataGridTextColumn
100
-
101
52
  Width="*"
102
-
103
53
  Binding="{Binding CurrentFolder}"
104
-
105
54
  Header="カレントフォルダ"
106
-
107
55
  IsReadOnly="True" />
108
-
109
56
  <DataGridTextColumn
110
-
111
57
  Width="300"
112
-
113
58
  Binding="{Binding PictureFileName}"
114
-
115
59
  Header="画像"
116
-
117
60
  IsReadOnly="True" />
118
-
119
61
  <DataGridTemplateColumn Width="32" IsReadOnly="True">
120
-
121
62
  <DataGridTemplateColumn.CellTemplate>
122
-
123
63
  <DataTemplate>
124
-
125
64
  <Image Source="{Binding PicturePath}" />
126
-
127
65
  </DataTemplate>
128
-
129
66
  </DataGridTemplateColumn.CellTemplate>
130
-
131
67
  </DataGridTemplateColumn>
132
-
133
68
  </DataGrid.Columns>
134
-
135
69
  </DataGrid>
136
-
137
70
  </DockPanel>
138
-
139
71
  </Window>
140
-
141
72
  ```
142
73
 
143
-
144
-
145
- ```C#
74
+ ```cs
146
-
147
75
  using Microsoft.Win32;
148
-
149
76
  using Ookii.Dialogs.Wpf;
150
-
151
77
  using System;
152
-
153
78
  using System.Collections.ObjectModel;
154
-
155
79
  using System.ComponentModel;
156
-
157
80
  using System.Diagnostics;
158
-
159
81
  using System.IO;
160
-
161
82
  using System.Runtime.CompilerServices;
162
-
163
83
  using System.Windows;
164
-
165
84
  using System.Windows.Controls;
166
-
167
85
  using System.Windows.Input;
168
86
 
169
-
170
-
171
87
  namespace Questions341357
172
-
173
88
  {
174
-
175
89
  public partial class MainWindow : Window
176
-
177
90
  {
178
-
179
91
  public ObservableCollection<Item> Items { get; } = new ObservableCollection<Item>();
180
92
 
181
-
182
-
183
93
  public MainWindow()
184
-
185
- {
94
+ {
186
-
187
95
  InitializeComponent();
188
-
189
96
  DataContext = this;
190
-
191
97
  Reset();
192
-
193
- }
98
+ }
194
-
195
-
196
99
 
197
100
  private void Reset()
198
-
199
- {
101
+ {
200
-
201
102
  Items.Clear();
202
-
203
103
  Items.Add(new Item
204
-
205
- {
104
+ {
206
-
207
105
  //Title = "taroko",
208
-
209
106
  CurrentFolder = "https://teratail-v2.storage.googleapis.com/uploads/avatars/u7/72728/",
210
-
211
107
  PictureFileName = "FBvOAPUf_thumbnail_32x32.jpg",
212
-
213
108
  });
214
-
215
109
  // インデクサを作れば↓のようなアクセスはできますがうれしいかどうか。。。
216
-
217
110
  Items[0][0] = "taroko";
218
111
 
219
-
220
-
221
112
  Items.Add(new Item
222
-
223
- {
113
+ {
224
-
225
114
  Title = "TN8001",
226
-
227
115
  CurrentFolder = "https://teratail-v2.storage.googleapis.com/uploads/avatars/u13/132786/",
228
-
229
116
  PictureFileName = "KnkDDC5A_thumbnail_32x32.jpg",
230
-
231
117
  });
232
-
233
- }
118
+ }
234
-
235
-
236
119
 
237
120
  private void ResetButton_Click(object sender, RoutedEventArgs e) => Reset();
238
121
 
239
-
240
-
241
122
  private void PrintButton_Click(object sender, RoutedEventArgs e)
242
-
243
- {
123
+ {
244
-
245
124
  foreach (var item in Items)
246
-
247
- {
125
+ {
248
-
249
126
  Debug.WriteLine($"Title:{item.Title}");
250
-
251
127
  Debug.WriteLine($"CurrentFolder:{item.CurrentFolder}");
252
-
253
128
  Debug.WriteLine($"PictureFileName:{item.PictureFileName}");
254
-
255
129
  Debug.WriteLine("");
256
-
257
- }
130
+ }
258
-
259
- }
131
+ }
260
-
261
-
262
132
 
263
133
  private void DataGridCell_MouseDoubleClick(object sender, MouseButtonEventArgs e)
264
-
265
- {
134
+ {
266
-
267
135
  if (!(sender is DataGridCell cell)) return;
268
-
269
136
  if (!(cell.DataContext is Item item)) return;
270
137
 
271
-
272
-
273
138
  var header = cell.Column.Header as string;
274
-
275
139
  var exeFolder = AppDomain.CurrentDomain.BaseDirectory;
276
-
277
140
  switch (header)
278
-
279
- {
141
+ {
280
-
281
142
  case "カレントフォルダ":
282
-
283
143
  var folderDlg = new VistaFolderBrowserDialog { SelectedPath = exeFolder, };
284
-
285
144
  if (folderDlg.ShowDialog() == true)
286
-
287
145
  {
288
-
289
146
  item.CurrentFolder = folderDlg.SelectedPath;
290
-
291
147
  }
292
-
293
148
  break;
294
-
295
149
  case "画像":
296
-
297
150
  var fileDlg = new OpenFileDialog
298
-
299
151
  {
300
-
301
152
  InitialDirectory = exeFolder,
302
-
303
153
  Filter = "画像ファイル(*.bmp,*.jpg,*.jpeg,*.png)|*.bmp;*.jpg;*.jpeg;*.png",
304
-
305
154
  };
306
-
307
155
  if (fileDlg.ShowDialog() == true)
308
-
309
156
  {
310
-
311
157
  item.CurrentFolder = Path.GetDirectoryName(fileDlg.FileName);
312
-
313
158
  item.PictureFileName = Path.GetFileName(fileDlg.FileName);
314
-
315
159
  }
316
-
317
160
  break;
318
-
319
161
  default: return;
320
-
321
- }
162
+ }
322
-
323
- }
163
+ }
324
-
325
164
  }
326
165
 
327
-
328
-
329
166
  public class Item : Observable
330
-
331
167
  {
332
-
333
168
  // View側(ユーザー操作)からしか変更されないのであれば、PropertyChangedを呼ぶ必要はない
334
-
335
169
  public string Title { get; set; }
336
-
337
170
  //private string _Title;
338
-
339
171
  //public string Title { get => _Title; set => Set(ref _Title, value); }
340
172
 
341
-
342
-
343
173
  // ViewModel側(コード)でも変更がある場合は、PropertyChangedを呼びViewに変更を伝えなければならない
344
-
345
174
  // 関連したプロパティ(PicturePath)があるので冗長だが、
346
-
347
175
  // 通常の独立したプロパティなら↑のコメント化したTitleのような書き方
348
-
349
176
  private string _CurrentFolder = ""; // Path.CombineでArgumentNullExceptionがでるので^^;
350
-
351
177
  public string CurrentFolder
352
-
353
- {
178
+ {
354
-
355
179
  get => _CurrentFolder;
356
-
357
180
  set
358
-
359
- {
181
+ {
360
-
361
182
  if (Set(ref _CurrentFolder, value))
362
-
363
- {
183
+ {
364
-
365
184
  // PicturePathも変わるわけなので、同じくPropertyChangedを呼ぶ
366
-
367
185
  OnPropertyChanged(nameof(PicturePath));
368
-
369
- }
186
+ }
370
-
371
- }
187
+ }
372
-
373
- }
188
+ }
374
-
375
-
376
189
 
377
190
  private string _PictureFileName = "";
378
-
379
191
  public string PictureFileName
380
-
381
- {
192
+ {
382
-
383
193
  get => _PictureFileName;
384
-
385
194
  set
386
-
387
- {
195
+ {
388
-
389
196
  if (Set(ref _PictureFileName, value))
390
-
391
- {
197
+ {
392
-
393
198
  OnPropertyChanged(nameof(PicturePath));
394
-
395
- }
199
+ }
396
-
397
- }
200
+ }
398
-
399
- }
201
+ }
400
-
401
-
402
202
 
403
203
  // PicturePathのPropertyChangedを呼べばViewが再取得するので、最新の値に常になる
404
-
405
204
  public string PicturePath => Path.Combine(CurrentFolder, PictureFileName);
406
205
 
407
206
 
408
-
409
-
410
-
411
207
  // インデクサ
412
-
413
208
  public string this[int index]
414
-
415
- {
209
+ {
416
-
417
210
  get
418
-
419
- {
211
+ {
420
-
421
212
  switch (index)
422
-
423
- {
213
+ {
424
-
425
214
  case 0: return Title;
426
-
427
215
  case 1: return CurrentFolder;
428
-
429
216
  case 2: return PictureFileName;
430
-
431
217
  default: throw new ArgumentOutOfRangeException();
432
-
433
- }
218
+ }
434
-
435
- }
219
+ }
436
-
437
220
  set
438
-
439
- {
221
+ {
440
-
441
222
  switch (index)
442
-
443
- {
223
+ {
444
-
445
224
  case 0: Title = value; break;
446
-
447
225
  case 1: CurrentFolder = value; break;
448
-
449
226
  case 2: PictureFileName = value; break;
450
-
451
227
  default: throw new ArgumentOutOfRangeException();
452
-
453
- }
228
+ }
454
-
455
- }
229
+ }
456
-
457
- }
230
+ }
458
-
459
231
  }
460
232
 
461
-
462
-
463
233
  // INotifyPropertyChangedのよくある実装 ViewModelBase等の場合も
464
-
465
234
  public class Observable : INotifyPropertyChanged
466
-
467
235
  {
468
-
469
236
  public event PropertyChangedEventHandler PropertyChanged;
470
-
471
237
  protected bool Set<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
472
-
473
- {
238
+ {
474
-
475
239
  if (Equals(storage, value)) return false;
476
-
477
240
  storage = value;
478
-
479
241
  OnPropertyChanged(propertyName);
480
-
481
242
  return true;
482
-
483
- }
243
+ }
484
-
485
244
  protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
486
-
487
245
  }
488
-
489
246
  }
490
-
491
247
  ```
492
-
493
248
  ![アプリ画像](8fdc53d1c61112de73459c1f0839cd67.png)