質問編集履歴

2

タイトルの変更と、分かったことを追記しました

2023/07/06 05:31

投稿

nodoita
nodoita

スコア7

test CHANGED
File without changes
test CHANGED
@@ -272,6 +272,15 @@
272
272
  Canvas.SetTop(r, info.Y);
273
273
  }
274
274
  ```
275
+
276
+ ###分かったこと
277
+ 画面上にボタンを置き
278
+ 「vm.RectInfoCollection.Add(new RectInfo("3", 10, 10, 100, 100, "Red", ""));」としてみたところ、四角形が描画されました。
279
+ 起動時に作成したデータでは四角形が出来ず、DataGridのみに表示されますが、ボタンで実行すると四角形描画とDataGridへの追加もどちらもできるようです。
280
+
281
+ 画面上に置いたボタンで追加できるのであれば、
282
+ Binding自体は問題ない気がします。
283
+
275
284
  ### 補足情報(FW/ツールのバージョンなど)
276
285
  Visualstudio2022 V17.6.3
277
286
  .NET 6.0 C#

1

大幅に修正しました。

2023/07/06 02:40

投稿

nodoita
nodoita

スコア7

test CHANGED
File without changes
test CHANGED
@@ -12,243 +12,266 @@
12
12
  【1】
13
13
  WPF 動的生成したRectangleがドラッグで移動できない、Bindingが難しい…
14
14
  https://teratail.com/questions/j700zzpncph60k
15
+ →ソースが変わる前のものを利用しています。
15
16
 
16
17
  【2】
17
18
  WPF C# ImageSourceを利用しているからか、画像がロックされてしまう
18
19
  https://teratail.com/questions/t6uox4f1iujybm
19
-
20
20
  ### 試したこと
21
- ![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2023-07-04/802f09e2-a65f-46f4-8683-f7d07036dd38.jpeg)
22
-
23
- ```SubWindow.xaml
24
- xmlns:local="clr-namespace:wpfRectangleBindingTest.Views"
25
- xmlns:localtest="clr-namespace:wpfRectangleBindingTest.ViewModels"
26
- mc:Ignorable="d"
27
- Title="SubWindow" Height="450" Width="800"
28
- d:DataContext="{d:DesignInstance Type=localtest:PicModel}"
29
- AllowDrop="True"
30
- DragOver="File_DragOver"
31
- Drop="File_Drop">
32
- <DockPanel>
33
- <StatusBar DockPanel.Dock="Bottom">
34
- <StatusBarItem>
35
- <TextBlock Text="{Binding PicItems/FilePath}" />
36
- </StatusBarItem>
37
- </StatusBar>
38
-
39
- <Grid>
40
- <Grid.ColumnDefinitions>
41
- <ColumnDefinition />
42
- <ColumnDefinition Width="5" />
43
- <ColumnDefinition Width="2*" />
44
- </Grid.ColumnDefinitions>
45
- <Grid.RowDefinitions>
46
- <RowDefinition Height="*"/>
47
- <RowDefinition Height="50"/>
48
- </Grid.RowDefinitions>
49
-
50
- <ListView IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Items}">
51
- <ListView.View>
52
- <GridView>
53
- <GridViewColumn Width="200" Header="タイトル">
54
- <GridViewColumn.CellTemplate>
55
- <DataTemplate>
56
- <TextBox Width="200" Padding="1" Text="{Binding FileTitle}" TextWrapping="Wrap" />
57
- </DataTemplate>
58
- </GridViewColumn.CellTemplate>
59
- </GridViewColumn>
60
- <GridViewColumn DisplayMemberBinding="{Binding FileName}" Header="ファイル名" />
61
- <GridViewColumn>
62
- <GridViewColumn.CellTemplate>
63
- <DataTemplate>
64
- <Button Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}" CommandParameter="{Binding}" Content="削除" />
65
- </DataTemplate>
66
- </GridViewColumn.CellTemplate>
67
- </GridViewColumn>
68
- </GridView>
69
- </ListView.View>
70
- </ListView>
71
-
72
- <GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
73
-
74
- <ListView Grid.Column="2" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Items}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
75
- <ListView.ItemsPanel>
76
- <ItemsPanelTemplate>
77
- <WrapPanel />
78
- </ItemsPanelTemplate>
79
- </ListView.ItemsPanel>
80
- <ListView.ItemTemplate>
81
- <DataTemplate>
82
- <Grid Width="150" Height="150">
83
- <TextBlock Text="{Binding FileTitle}" />
84
- <Image Source="{Binding FilePath, Converter={StaticResource ImageConverter}}" />
85
- </Grid>
86
- </DataTemplate>
87
- </ListView.ItemTemplate>
88
- </ListView>
89
- <StackPanel Grid.Row="1" Grid.Column="2" Orientation="Horizontal">
90
- <Button x:Name="MainPicShow" Margin="5" Padding="10" Content="メインウィンドウに表示"
91
- Click="Ok_Button_Click" Command="{Binding ApplyCommand}" CommandParameter="{Binding PicItems/}"/>
92
- <Button Margin="5" Padding="10" Content="次のリンク画像決定" />
93
- <Button Margin="5" Padding="10" Content="Button" />
94
- </StackPanel>
95
- </Grid>
96
- </DockPanel>
97
- </Window>
98
-
99
- ```
100
- ```SubWindow.xaml.cs
101
- using wpfRectangleBindingTest.ViewModels;
102
-
103
- namespace wpfRectangleBindingTest.Views
21
+
22
+ ViewModelを1つにまとめました。
23
+ Itemsという同じ名称のものは、「RectItems」「PicItems」としました。
24
+
25
+ ```MainWindow.xaml
26
+ <Grid>
27
+ <Grid.RowDefinitions>
28
+ <RowDefinition Height="30" />
29
+ <RowDefinition Height="600"/>
30
+ <RowDefinition Height="*"/>
31
+ </Grid.RowDefinitions>
32
+ <ToolBar Grid.Row="0" VerticalAlignment="Top" Height="30">
33
+ <Button Content="画像選択" Width="128" Height="32" Click="Button_Click"/>
34
+ <RadioButton x:Name="DefaultButton" Width="32" Height="32"
35
+ Content="?" IsChecked="True" />
36
+ <RadioButton x:Name="RectButton" Width="32" Height="32">
37
+ <Rectangle Width="24" Height="16" Stroke="Black"/>
38
+ </RadioButton>
39
+ </ToolBar>
40
+
41
+ <!-- <Image Grid.Row="1" MinWidth="600" MinHeight="600" Height="600" MaxWidth="800" MaxHeight="600" Width="800" Source="{Binding SelectedPic.FilePath, Converter={StaticResource ImageConverter}}" StretchDirection="DownOnly" HorizontalAlignment="Left" VerticalAlignment="Top" />-->
42
+ <local:MyCanvas MinHeight="600" MaxHeight="600" Height="600" MinWidth="800" Width="800" MaxWidth="800" Grid.Row="1" RectItems="{Binding RectInfoCollection}" SelectRect="{Binding SelectRect, Mode=TwoWay}" >
43
+ </local:MyCanvas>
44
+ <local:MyDataGrid Grid.Row="2" DataContext="{Binding }"/>
45
+
46
+ </Grid>
47
+ ```
48
+ ```MainWindow.cs
49
+ public partial class MainWindow : Window
50
+ {
51
+ public ViewModel vm ;
52
+ public MainWindow()
53
+ {
54
+ InitializeComponent();
55
+ var imageFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "image");
56
+ vm = new ViewModel(imageFolder);
57
+ this.DataContext = vm;
58
+ }
59
+ private void Button_Click(object sender, RoutedEventArgs e)
60
+ => new SubWindow((ViewModel)DataContext).ShowDialog();
61
+
62
+ private void Window_Loaded(object sender, RoutedEventArgs e)
63
+ {
64
+ vm.RectInfoCollection.Add(new RectInfo("1", 10, 10, 100, 100, "Red", ""));
65
+ vm.RectInfoCollection.Add(new RectInfo("2", 100, 100, 200, 200, "Blue", ""));
66
+
67
+ }
68
+ }
69
+
70
+ ```
71
+ ```ViewModel.cs
72
+ public partial class ViewModel : BindableBase
104
73
  {
74
+ private RectInfo? _SelectedRect;
75
+ public RectInfo? SelectedRect { get => _SelectedRect; set => SetProperty(ref _SelectedRect, value); }
76
+
77
+ public ObservableCollection<Item> PicItems { get; } = new();
78
+
79
+ private Item? _SelectPic;
80
+ public Item? SelectPic { get => _SelectPic; set => SetProperty(ref _SelectPic, value); }
81
+
82
+ private readonly string folder;
105
- public partial class SubWindow : Window
83
+ public ViewModel(string folder)
106
- {
84
+ {
107
-
85
+ this.folder = folder;
86
+ Directory.CreateDirectory(folder);
108
- private static readonly string[] SupportedFormats = { ".jpg", ".jpeg", ".bmp", ".png" };
87
+ ImportFiles(Directory.EnumerateFiles(folder, "*.jpg", SearchOption.TopDirectoryOnly));
109
-
88
+ }
89
+
90
+ [RelayCommand]
110
- private readonly ViewModel PicModel;
91
+ private void Apply(Item? item) => SelectPic = item;
111
-
92
+
112
- public SubWindow(ViewModel PicModel)
93
+ public void ImportFiles(IEnumerable<string> paths)
113
- {
94
+ {
114
- InitializeComponent();
115
- DataContext = this.PicModel = PicModel;
95
+ foreach (var path in paths) PicItems.Add(new(path));
116
- }
96
+ }
117
-
97
+
118
- private void File_DragOver(object sender, DragEventArgs e)
98
+ public void AddItem(string path, Func<bool> isOverwrite)
119
- {
99
+ {
100
+ var fileName = System.IO.Path.GetFileNameWithoutExtension(path);
120
- e.Effects = e.Data.GetDataPresent(DataFormats.FileDrop, true) ? DragDropEffects.Copy
101
+ var outPath = System.IO.Path.Combine(folder, $"{fileName}.jpg");
102
+
103
+ if (File.Exists(outPath))
104
+ {
121
- : DragDropEffects.None;
105
+ if (!isOverwrite()) return;
122
- e.Handled = true;
106
+ PicItems.Remove(PicItems.FirstOrDefault(x => x.FilePath == outPath)!);
123
- }
107
+ }
108
+
124
-
109
+ using (var fsin = new FileStream(path, FileMode.Open, FileAccess.ReadWrite))
125
- private void File_Drop(object sender, DragEventArgs e)
110
+ using (var fsout = new FileStream(outPath, FileMode.Create, FileAccess.Write))
126
- {
111
+ {
127
- if (!e.Data.GetDataPresent(DataFormats.FileDrop)) return;
128
-
129
- var files = (string[])e.Data.GetData(DataFormats.FileDrop);
130
-
131
- var ok = files.Where(x => SupportedFormats.Contains(System.IO.Path.GetExtension(x).ToLower()));
132
- foreach (var path in ok)
133
- {
134
- PicModel.AddItem(path, IsOverwrite);
135
- bool IsOverwrite()
136
- {
137
- var msg = $"同名のファイルが既にあります。\n上書きしますか?\n\n{path}";
138
- var r = MessageBox.Show(this, msg, "", MessageBoxButton.YesNo, MessageBoxImage.Warning);
112
+ var f = BitmapFrame.Create(fsin, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnDemand);
113
+ var meta = f.Metadata.Clone() as BitmapMetadata ?? new BitmapMetadata("jpg");
139
- return r == MessageBoxResult.Yes;
114
+ var enc = new JpegBitmapEncoder();
115
+ enc.Frames.Add(BitmapFrame.Create(f, f.Thumbnail, meta, f.ColorContexts));
116
+ enc.Save(fsout);
140
- }
117
+ }
141
- }
118
+
142
-
143
- var ng = files.Where(x => !SupportedFormats.Contains(System.IO.Path.GetExtension(x).ToLower()));
144
- if (ng.Any()) MessageBox.Show(this, $"{string.Join("\n", ng)}\nのファイルは読めませんでした");
145
- }
146
- private void Ok_Button_Click(object sender, RoutedEventArgs e) => DialogResult = true;
119
+ PicItems.Add(new(outPath));
147
120
  }
148
121
  }
149
-
150
- ```
151
- ```PicModels.cs
152
- using CommunityToolkit.Mvvm.ComponentModel;
153
- using CommunityToolkit.Mvvm.Input;
154
- using System;
155
- using System.Collections.Generic;
156
- using System.Collections.ObjectModel;
157
- using System.IO;
158
- using System.Linq;
159
- using System.Text;
160
- using System.Threading.Tasks;
161
- using System.Windows.Media.Imaging;
162
- using System.Windows;
163
-
164
- namespace wpfRectangleBindingTest.ViewModels
165
- {
166
-
167
- public partial class PicModel : ObservableObject
168
- {
169
- public ObservableCollection<Item> PicItems { get; } = new();
170
- [ObservableProperty] private bool isSubWindowShown;
171
- [ObservableProperty] private Item? selectPic;
172
- private readonly string folder;
173
-
174
- public PicModel(string folder)
175
- {
176
- this.folder = folder;
177
- Directory.CreateDirectory(folder);
178
- ImportFiles(Directory.EnumerateFiles(folder, "*.jpg", SearchOption.TopDirectoryOnly));
179
- }
180
-
181
- [RelayCommand]
182
- private void Delete(Item item)
183
- {
184
- if (MessageBox.Show(item.FileTitle + "を削除しても良いですか?",
185
- "ファイル削除", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.No)
186
- { return; }
187
-
188
- PicItems.Remove(item);
189
- File.Delete(item.FilePath);
190
- }
191
-
192
- [RelayCommand]
193
- private void Apply(Item? item) => SelectPic = item;
194
-
195
- public void ImportFiles(IEnumerable<string> paths)
196
- {
197
- foreach (var path in paths) PicItems.Add(new(path));
198
- }
199
-
200
- public void AddItem(string path, Func<bool> isOverwrite)
201
- {
202
- var fileName = System.IO.Path.GetFileNameWithoutExtension(path);
203
- var outPath = System.IO.Path.Combine(folder, $"{fileName}.jpg");
204
-
205
- if (File.Exists(outPath))
206
- {
207
- if (!isOverwrite()) return;
208
- PicItems.Remove(PicItems.FirstOrDefault(x => x.FilePath == outPath)!);
209
- }
210
-
211
- using (var fsin = new FileStream(path, FileMode.Open, FileAccess.ReadWrite))
212
- using (var fsout = new FileStream(outPath, FileMode.Create, FileAccess.Write))
213
- {
214
- var f = BitmapFrame.Create(fsin, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnDemand);
215
- var meta = f.Metadata.Clone() as BitmapMetadata ?? new BitmapMetadata("jpg");
216
- var enc = new JpegBitmapEncoder();
217
- enc.Frames.Add(BitmapFrame.Create(f, f.Thumbnail, meta, f.ColorContexts));
218
- enc.Save(fsout);
219
- }
220
-
221
- PicItems.Add(new(outPath));
222
- }
223
- }
224
- }
225
122
  ```
226
123
 
227
124
  ### 発生している問題・エラーメッセージ
228
- このPicModelは、MainWindowでもSubWindowでも利用します。
229
- 元々はItemsだったのですが、Rectangleのと被るために
125
+ - Rectangleが表示されない(SelectRectRe
230
- 新しくPicModelとして作成して参照させようとしてます。
231
-
232
- SubWindowのxamlに以下のように記載してみました。
233
- xmlns:localtest="clr-namespace:wpfRectangleBindingTest.ViewModels"
234
- d:DataContext="{d:DesignInstance Type=localtest:PicModel}"
126
+ - Canvasの裏に画像を表示させようとImageを追加したが、それも表示されない(SelectPicのデータはあり)
235
-
236
- 上記のようにしたら参照できるかと思ったらNGでした。
127
+
237
- "PicModel" は名前空間 "clr-namespace:wpfRectangleBindingTest.ViewModels" に存在しません。とエラーになります。
238
-
239
- 何が悪いのでしょうか…?
240
-
241
- ```SubWindow.xaml.cs
128
+ ```MyCanvas.cs
242
- private readonly ViewModel PicModel;
243
-
244
- public SubWindow(ViewModel PicModel)
129
+ public MyCanvas()
245
130
  {
246
131
  InitializeComponent();
247
- DataContext = this.PicModel = PicModel;
248
- }
132
+ }
133
+
134
+ private System.Windows.Point _dragOffset;
135
+ private System.Windows.Shapes.Rectangle? _dragRectangle;
136
+ public RectInfo SelectRect
137
+ {
138
+ get { return (RectInfo)GetValue(SelectRectProperty); }
139
+ set { SetValue(SelectRectProperty, value); }
140
+ }
141
+
142
+ public static readonly DependencyProperty SelectRectProperty =
143
+ DependencyProperty.Register("SelectRect", typeof(RectInfo), typeof(MyCanvas), new PropertyMetadata(null, SelectRect_Changed));
144
+
145
+ private static void SelectRect_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
146
+ {
147
+ (d as MyCanvas)?.SelectRectChanged(e.OldValue, e.NewValue);
148
+ }
149
+
150
+ private void SelectRectChanged(object oldValue, object newValue)
151
+ {
152
+ if (oldValue is RectInfo o)
153
+ {
154
+ var target = FindRectangle(o);
155
+ if (target != null)
156
+ {
157
+ target.StrokeDashArray = null;
158
+ }
159
+ }
160
+ if (newValue is RectInfo n)
161
+ {
162
+ var target = FindRectangle(n);
163
+ if (target != null)
164
+ {
165
+ target.StrokeDashArray = new DoubleCollection() { 2 };
166
+ }
167
+ }
168
+ }
169
+
170
+ public ObservableCollection<RectInfo> RectItems
171
+ {
172
+ get { return (ObservableCollection<RectInfo>)GetValue(RectItemsProperty); }
173
+ set { SetValue(RectItemsProperty, value); }
174
+ }
175
+
176
+ public static readonly DependencyProperty RectItemsProperty =
177
+ DependencyProperty.Register("RectItems", typeof(ObservableCollection<RectInfo>), typeof(MyCanvas), new PropertyMetadata(null, RectItemsChangedCallback));
178
+
179
+ private static void RectItemsChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
180
+ {
181
+ (d as MyCanvas)?.RegisterCollectionChanged();
182
+ }
183
+
184
+ private void RegisterCollectionChanged()
185
+ {
186
+ RectItems.CollectionChanged += RectItems_CollectionChanged;
187
+ }
188
+
189
+ private void RectItems_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
190
+ {
191
+ switch (e.Action)
192
+ {
193
+ case NotifyCollectionChangedAction.Add:
194
+ if (e.NewItems != null)
195
+ {
196
+ foreach (RectInfo mp in e.NewItems)
197
+ {
198
+ AddRectangle(mp);
199
+ mp.PropertyChanged += RectInfo_PropertyChanged;
200
+ }
201
+ }
202
+ break;
203
+
204
+ case NotifyCollectionChangedAction.Remove:
205
+ if (e.OldItems != null)
206
+ {
207
+ foreach (RectInfo info in e.OldItems)
208
+ {
209
+ var target = FindRectangle(info);
210
+ if (target != null)
211
+ {
212
+ canvas2.Children.Remove(target);
213
+ info.PropertyChanged -= RectInfo_PropertyChanged;
214
+ }
215
+ }
216
+ }
217
+ break;
218
+
219
+ default:
220
+ break;
221
+ }
222
+ }
223
+
224
+ private System.Windows.Shapes.Rectangle? FindRectangle(RectInfo info)
225
+ {
226
+ if (info == null) return null;
227
+ return canvas2.Children.OfType<System.Windows.Shapes.Rectangle>().FirstOrDefault(i => info == (RectInfo)i.Tag);
228
+ }
229
+
230
+ internal void AddRectangle(RectInfo info)
231
+ {
232
+ var r = new System.Windows.Shapes.Rectangle
233
+ {
234
+ Width = 20,
235
+ Height = 20,
236
+ Stroke=Brushes.Black,
237
+ StrokeThickness=5,
238
+ ToolTip = info.Name,
239
+ Tag = info
240
+ };
241
+
242
+ r.Width = info.Width;
243
+ r.Height = info.Height;
244
+
245
+ try
246
+ {
247
+ var brush = (SolidColorBrush)new BrushConverter().ConvertFromString(info.BorderColor);
248
+ r.Stroke = brush;
249
+ }
250
+ catch
251
+ {
252
+ r.Stroke = Brushes.Transparent;
253
+ }
254
+
255
+ try {
256
+ var brush = (SolidColorBrush)new BrushConverter().ConvertFromString(info.FillColor);
257
+ r.Fill = brush;
258
+ }
259
+ catch
260
+ {
261
+ r.Fill = Brushes.Transparent;
262
+ }
263
+
264
+ //イベント追加
265
+ r.MouseDown += DragStart;
266
+ r.MouseUp += (o, e) => { _dragRectangle = null; r.ReleaseMouseCapture(); };
267
+ r.MouseMove += MoveRectangle;
268
+
269
+ //パネルに追加
270
+ canvas2.Children.Add(r);
271
+ Canvas.SetLeft(r, info.X);
272
+ Canvas.SetTop(r, info.Y);
273
+ }
249
- ```
274
+ ```
250
-
251
-
252
275
  ### 補足情報(FW/ツールのバージョンなど)
253
276
  Visualstudio2022 V17.6.3
254
277
  .NET 6.0 C#