回答編集履歴

1

コード追記

2023/10/01 03:59

投稿

hqf00342
hqf00342

スコア394

test CHANGED
@@ -1,16 +1,18 @@
1
1
 
2
- 質問ポイントが複数にわたるようなので分けて書きますが、
2
+ 質問ポイントが複数にわたるので分けて記載しますが、
3
- コードは書ききれないのでサンプルをアップします。
3
+ コードは書ききれないので質問コードをベースにしたサンプルを置きます。
4
4
 
5
5
  https://github.com/hqf00342/Wpf_teratail_29545c8iv6n7wd
6
6
 
7
- (可能な限り質問元コードにしてます。TN8001さんのビヘイビアにしたいところですが・・。また、質問内の他サイト様コードをわざと丸ごと引用していますしばらくしたら削除します。)
7
+ (質問内の他サイト様コードを丸ごと引用のため、しばらくしたら削除します。)
8
8
 
9
9
  ----
10
10
 
11
11
  ##### データの見通しをよくしたい
12
- 全データを管理するデータセット(以降、モデルと言います)を1つ用意し、各UI部品はそのモデルデータを参照します。UIを更新したら必ずそのモデルのデータも更新することで整合性を保ちます。
12
+ 全データを管理するデータセット(以降、モデルと言います)を1つ用意し、各UI部品はそのモデルデータを参照します。
13
-
13
+ UIを更新したら必ずそのモデルのデータも更新することで整合性を保ちます。各UIコントロールはモデルデータの変更を検知して自分に反映するようにします。
14
+ UI同士でデータ連携しようとせず、必ずモデルを介することで見通し良くします。(その分パフォーマンスは悪くなります)
15
+ モデルデータ変更時のUI更新はWPFの場合はBindingを使うのが一般的です。
14
16
  ```csharp
15
17
  //モデルデータ
16
18
  internal class OriginData
@@ -26,12 +28,63 @@
26
28
  }
27
29
  ```
28
30
  ##### DataGridの複数データをCanvas側でどう管理、連携するか
31
+
32
+ DataGrid同様にCanvas側にもコレクションを管理する機能が必要です。
29
- DataGrid同様にCanvas側にもコレクションを管理する機能が必要です。簡単なケースならItemsControl、複雑なら自分で実装することになると思います(https://teratail.com/questions/j700zzpncph60k は両方書いてあります)。2つのコントロールが同じモデルを参照することで連携します(コードはサンプル)
33
+ 簡単なケースなら`ItemsControl`をCanvas化して利用凝ったことをしたければ自分で実装ます。2つのコントロールが同じモデル(コレクション)を参照することで連携します
34
+ `ItemsControl`を使うとXAMLは長いですが、C#コードはすっきりします。
35
+
36
+ ```xml
37
+ <ItemsControl Width="800" Height="600" ItemsSource="{Binding Items}">
38
+
39
+ <ItemsControl.ItemsPanel>
40
+ <ItemsPanelTemplate>
41
+ <Canvas />
42
+ </ItemsPanelTemplate>
43
+ </ItemsControl.ItemsPanel>
44
+
45
+ <ItemsControl.ItemTemplate>
46
+ <DataTemplate>
47
+ <Button Content="{Binding HintText}"
48
+ Width="{Binding Width}" Height="{Binding Height}">
49
+ <Button.Style>
50
+ <Style TargetType="Button">
51
+ <Style.Triggers>
52
+ <Trigger Property="IsFocused" Value="True">
53
+ <Setter Property="local:AdornedBy.Template"
54
+ Value="{StaticResource AdornerTemplate}" />
55
+ </Trigger>
56
+ </Style.Triggers>
57
+ </Style>
58
+ </Button.Style>
59
+ </Button>
60
+ </DataTemplate>
61
+ </ItemsControl.ItemTemplate>
62
+
63
+ <ItemsControl.ItemContainerStyle>
64
+ <Style TargetType="ContentPresenter">
65
+ <Setter Property="Canvas.Left" Value="{Binding X,Mode=TwoWay}" />
66
+ <Setter Property="Canvas.Top" Value="{Binding Y,Mode=TwoWay}" />
67
+ </Style>
68
+ </ItemsControl.ItemContainerStyle>
69
+ </ItemsControl>
70
+ ```
30
71
 
31
72
  ##### AdornerからDataGridまで反映させる方法
32
73
 
33
- ResizeThumb_DragDelta()で`adored`に対象のButtonは抽出できていると思います。このButtonとモデルのデータを何らかの方法で結び付け、データ更新することで別コントロール(DataGrid)に反映させます。MVVMなら`Button.DataContext`プロパティ、MVVMを使わないのならば`Button.Tag`プロパティ等を使って自分の好きな識別データを入れるのが早いです。(コードはサンプル)
34
-
74
+ ResizeThumb_DragDelta()で`adored`変数に対象のButtonは抽出できてます。
75
+ このButtonとモデルのデータを何らかの方法で結び付け、データ更新することで別コントロール(DataGrid)に反映させます。
76
+ MVVM利用なら`Button.DataContext`プロパティに自動で入ってます。MVVM未利用ならば`Button.Tag`プロパティ等に対象データを入れたり、実際の位置から計算して特定する手もあります。
77
+ ```csharp
78
+ private void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
79
+ {
80
+ var thumb = sender as Thumb;
81
+ if (thumb == null) return;
82
+ var button = AdornedBy.GetAdornedElementFromTemplateChild(thumb) as Button;
83
+ if (button == null) return;
84
+ //バインディングされているアイテムを取得
85
+ Item item = button.DataContext as Item;
86
+ ```
87
+ 対象のモデルデータが手に入れば、それを更新すれば全UIコントロールに反映されます。
35
88
  ##### 選択状態の連携
36
89
 
37
90
  別のWindow間であればモデルやViewModelに選択アイテム用プロパティを1つ用意します。
@@ -39,11 +92,10 @@
39
92
  ```csharp
40
93
  public partial class ViewModel : ObservableObject
41
94
  {
42
- /// <summary>データ</summary>
95
+ ...略
43
- public ObservableCollection<Item> Items => OriginData.OriginItems;
44
-
45
96
  /// <summary>選択アイテム</summary>
46
97
  [ObservableProperty] private Item selectedItem;
47
98
  ```
99
+
48
100
  MVVMの思想的には1つのViewModelを複数のViewで共有しないのですが、一人開発ならMVVMをあまり気にせず、プログラムを完成させることを目指しましょう。
49
101