質問編集履歴
2
タイトルの変更と、分かったことを追記しました
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
大幅に修正しました。
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
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
D
|
31
|
-
|
32
|
-
<
|
33
|
-
<
|
34
|
-
<
|
35
|
-
|
36
|
-
<
|
37
|
-
<
|
38
|
-
|
39
|
-
<
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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
|
83
|
+
public ViewModel(string folder)
|
106
|
-
{
|
84
|
+
{
|
107
|
-
|
85
|
+
this.folder = folder;
|
86
|
+
Directory.CreateDirectory(folder);
|
108
|
-
pri
|
87
|
+
ImportFiles(Directory.EnumerateFiles(folder, "*.jpg", SearchOption.TopDirectoryOnly));
|
109
|
-
|
88
|
+
}
|
89
|
+
|
90
|
+
[RelayCommand]
|
110
|
-
|
91
|
+
private void Apply(Item? item) => SelectPic = item;
|
111
|
-
|
92
|
+
|
112
|
-
|
93
|
+
public void ImportFiles(IEnumerable<string> paths)
|
113
|
-
|
94
|
+
{
|
114
|
-
InitializeComponent();
|
115
|
-
|
95
|
+
foreach (var path in paths) PicItems.Add(new(path));
|
116
|
-
|
96
|
+
}
|
117
|
-
|
97
|
+
|
118
|
-
|
98
|
+
public void AddItem(string path, Func<bool> isOverwrite)
|
119
|
-
|
99
|
+
{
|
100
|
+
var fileName = System.IO.Path.GetFileNameWithoutExtension(path);
|
120
|
-
|
101
|
+
var outPath = System.IO.Path.Combine(folder, $"{fileName}.jpg");
|
102
|
+
|
103
|
+
if (File.Exists(outPath))
|
104
|
+
{
|
121
|
-
|
105
|
+
if (!isOverwrite()) return;
|
122
|
-
e.
|
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
|
-
|
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
|
-
|
112
|
+
var f = BitmapFrame.Create(fsin, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnDemand);
|
113
|
+
var meta = f.Metadata.Clone() as BitmapMetadata ?? new BitmapMetadata("jpg");
|
139
|
-
|
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
|
-
|
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
|
-
|
125
|
+
- Rectangleが表示されない(SelectRectもRe
|
230
|
-
新しくPicModelとして作成して参照させようとしてます。
|
231
|
-
|
232
|
-
SubWindowのxamlに以下のように記載してみました。
|
233
|
-
xmlns:localtest="clr-namespace:wpfRectangleBindingTest.ViewModels"
|
234
|
-
|
126
|
+
- Canvasの裏に画像を表示させようとImageを追加したが、それも表示されない(SelectPicのデータはあり)
|
235
|
-
|
236
|
-
|
127
|
+
|
237
|
-
"PicModel" は名前空間 "clr-namespace:wpfRectangleBindingTest.ViewModels" に存在しません。とエラーになります。
|
238
|
-
|
239
|
-
何が悪いのでしょうか…?
|
240
|
-
|
241
|
-
```
|
128
|
+
```MyCanvas.cs
|
242
|
-
private readonly ViewModel PicModel;
|
243
|
-
|
244
|
-
|
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#
|