teratail header banner
teratail header banner
質問するログイン新規登録

質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.30%
.NET

.NETとは、主に.NET Frameworkと呼ばれるアプリケーションまたは開発環境を指します。CLR(共通言語ランタイム)を搭載し、入力された言語をCIL(共通中間言語)に変換・実行することが可能です。そのため、C#やPythonなど複数の言語を用いることができます。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

1回答

1309閲覧

WPF ViewModelに値があるのに画像が表示されない

nodoita

総合スコア7

.NET

.NETとは、主に.NET Frameworkと呼ばれるアプリケーションまたは開発環境を指します。CLR(共通言語ランタイム)を搭載し、入力された言語をCIL(共通中間言語)に変換・実行することが可能です。そのため、C#やPythonなど複数の言語を用いることができます。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

1グッド

0クリップ

投稿2023/07/10 05:50

編集2023/07/10 07:46

1

0

お世話になります。
色々と試しているのですが、分からないため教えてください。

実現したいこと

【1】WPF 動的生成したRectangleがドラッグで移動できない、Bindingが難しい…
https://teratail.com/questions/j700zzpncph60k

【2】WPF C# ImageSourceを利用しているからか、画像がロックされてしまう
https://teratail.com/questions/t6uox4f1iujybm

上記2つのものを組み合わせて作成途中です。

・プロパティ 'SelectedRect' が型 'DataGrid' に見つかりませんでした。
というエラーが気になる

途中の入力ミスだったので削除します

<local:MyCanvas MinHeight="600" MaxHeight="600" Height="600" MinWidth="800" Width="800" MaxWidth="800" Grid.Row="1" Items="{Binding RectInfoCollection}" SelectedRect="{Binding ElementName=datagrid,Path=**SelectedItem**, Mode=TwoWay}" />

・ObservableCollection<PicInfo> PicInfoCollection
で、ListViewで今選択している値を抽出してSelectPicに入れたり
今選択している値を削除したりしたい

前提

MainWindowでRectangleを生成したり操作したりします。
SubWindowでは、SubWindowで選択した画像を最背面に表示します。
選択した画像とRectangleを組み合わせ、ファイルを作成する予定です。
そのため、Rectangleの値(X,Y,Width,Height,色、位置など)
選択した画像の値(画像メタデータのタイトル、画像タイトル、画像ファイルパス、その他紐づくいろんな値)が必要になってきます。
再利用するために、取り回し良く?する必要があります。

とりあえず今はシンプルに
RectangleのX,Y画像のファイルパス、画像ファイル名、タイトル…など必要最低限のデータに絞って作成してます。

発生している問題・エラーメッセージ

SelectPicに値が入っているのにMainWindowに画像が表示されません。

該当のソースコード

イメージ説明

MainWindow

1 <Window.Resources> 2 <x:Array x:Key="Colors" Type="sys:String"> 3 <sys:String>transparent</sys:String> 4 <sys:String>red</sys:String> 5 <sys:String>blue</sys:String> 6 </x:Array> 7 </Window.Resources> 8 <Grid> 9 <Grid.RowDefinitions> 10 <RowDefinition Height="30" /> 11 <RowDefinition Height="600"/> 12 <RowDefinition Height="*"/> 13 </Grid.RowDefinitions> 14 <ToolBar Grid.Row="0" VerticalAlignment="Top" Height="30"> 15 <Button Content="画像選択" Width="128" Height="32" Click="Button_Click"/> 16 <RadioButton x:Name="DefaultButton" Width="32" Height="32" 17 Content="↖" IsChecked="True" /> 18 <RadioButton x:Name="RectButton" Width="32" Height="32"> 19 <Rectangle Width="24" Height="16" Stroke="Black"/> 20 </RadioButton> 21 </ToolBar> 22 23 <Image Source="{Binding SelectedPic.PicFilePath}" StretchDirection="DownOnly" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="1" ></Image> 24 <local:MyCanvas MinHeight="600" MaxHeight="600" Height="600" MinWidth="800" Width="800" MaxWidth="800" Grid.Row="1" 25 Items="{Binding RectInfoCollection}" 26 SelectedRect="{Binding ElementName=datagrid,Path=SelectedRect, Mode=TwoWay}" /> 27 28 <DataGrid Name="datagrid" 29 Grid.Row="2" 30 ItemsSource="{Binding RectInfoCollection}" SelectionMode="Single"> 31 <DataGrid.Columns> 32 <DataGridTextColumn Header="Name" MinWidth="50" Binding="{Binding Name}" /> 33 <DataGridTextColumn Header="X" Binding="{Binding X}" /> 34 <DataGridTextColumn Header="Y" Binding="{Binding Y}" /> 35 </DataGrid.Columns> 36 </DataGrid> 37 </Grid>

SubWindow

1 <DockPanel> 2 <StatusBar DockPanel.Dock="Bottom"> 3 <StatusBarItem> 4 <TextBlock Text="{Binding PicInfoCollection/PicFilePath}" /> 5 </StatusBarItem> 6 </StatusBar> 7 8 <Grid> 9 <Grid.ColumnDefinitions> 10 <ColumnDefinition /> 11 <ColumnDefinition Width="5" /> 12 <ColumnDefinition Width="2*" /> 13 </Grid.ColumnDefinitions> 14 <Grid.RowDefinitions> 15 <RowDefinition Height="*"/> 16 <RowDefinition Height="50"/> 17 </Grid.RowDefinitions> 18 19 <ListView IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding PicInfoCollection}"> 20 <ListView.View> 21 <GridView> 22 <GridViewColumn Width="200" Header="タイトル"> 23 <GridViewColumn.CellTemplate> 24 <DataTemplate> 25 <TextBox Width="200" Padding="1" Text="{Binding PicTitle}" TextWrapping="Wrap" /> 26 </DataTemplate> 27 </GridViewColumn.CellTemplate> 28 </GridViewColumn> 29 <GridViewColumn DisplayMemberBinding="{Binding PicName}" Header="ファイル名" /> 30 <GridViewColumn> 31 <GridViewColumn.CellTemplate> 32 <DataTemplate> 33 <Button Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}" CommandParameter="{Binding}" Content="削除" /> 34 </DataTemplate> 35 </GridViewColumn.CellTemplate> 36 </GridViewColumn> 37 </GridView> 38 </ListView.View> 39 </ListView> 40 41 <GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" /> 42 43 <ListView Grid.Column="2" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding PicInfoCollection}" ScrollViewer.HorizontalScrollBarVisibility="Disabled"> 44 <ListView.ItemsPanel> 45 <ItemsPanelTemplate> 46 <WrapPanel /> 47 </ItemsPanelTemplate> 48 </ListView.ItemsPanel> 49 <ListView.ItemTemplate> 50 <DataTemplate> 51 <Grid Width="150" Height="150"> 52 <TextBlock Text="{Binding PicTitle}" /> 53 <Image Source="{Binding PicFilePath, Converter={StaticResource ImageConverter}}" /> 54 </Grid> 55 </DataTemplate> 56 </ListView.ItemTemplate> 57 </ListView> 58 <StackPanel Grid.Row="1" Grid.Column="2" Orientation="Horizontal"> 59 <Button x:Name="MainPicShow" Margin="5" Padding="10" Content="メインウィンドウに表示" 60 Click="Ok_Button_Click" Command="{Binding ApplyCommand}" CommandParameter="{Binding PicInfoCollection/}"/> 61 <Button x:Name="DeleteButton" Margin="5" Padding="10" Content="削除"/> 62 </StackPanel> 63 </Grid> 64 </DockPanel>

ViewModel

1public class ViewModel : BindableBase 2{ 3 private ObservableCollection<RectInfo> _rectInfoCollection = null!; 4 public ObservableCollection<RectInfo> RectInfoCollection { get => _rectInfoCollection; set => SetProperty(ref _rectInfoCollection, value); } 5 6 private ObservableCollection<PicInfo> _picInfoCollection = null!; 7 public ObservableCollection<PicInfo> PicInfoCollection { get => _picInfoCollection; set => SetProperty(ref _picInfoCollection, value); } 8 public PicInfo? SelectedPic { get; set; } 9 private readonly string ImageFolder; 10 private readonly string HtmlFolder; 11 12 public ViewModel() 13 { 14 RectInfoCollection = MyData.RectInfos; 15 PicInfoCollection = MyData.PicInfos; 16 ImageFolder = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "image"); 17 if (!Directory.Exists(ImageFolder)){ 18 Directory.CreateDirectory(ImageFolder); 19 } 20 HtmlFolder = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "html"); 21 if (!Directory.Exists(HtmlFolder)) 22 { 23 Directory.CreateDirectory(HtmlFolder); 24 } 25 ImportFiles(Directory.EnumerateFiles(ImageFolder, "*.jpg", SearchOption.TopDirectoryOnly)); 26 } 27 28 public void ImportFiles(IEnumerable<string> paths) 29 { 30 foreach (var path in paths) PicInfoCollection.Add(new(path)); 31 } 32 33 public void AddItem(string path, Func<bool> isOverwrite) 34 { 35 var fileName = System.IO.Path.GetFileNameWithoutExtension(path); 36 var outPath = System.IO.Path.Combine(ImageFolder, $"{fileName}.jpg"); 37 38 if (File.Exists(outPath)) 39 { 40 if (!isOverwrite()) return; 41 PicInfoCollection.Remove(PicInfoCollection.FirstOrDefault(x => x.PicFilePath == outPath)!); 42 } 43 44 using (var fsin = new FileStream(path, FileMode.Open, FileAccess.ReadWrite)) 45 using (var fsout = new FileStream(outPath, FileMode.Create, FileAccess.Write)) 46 { 47 var f = BitmapFrame.Create(fsin, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnDemand); 48 var meta = f.Metadata.Clone() as BitmapMetadata ?? new BitmapMetadata("jpg"); 49 var enc = new JpegBitmapEncoder(); 50 enc.Frames.Add(BitmapFrame.Create(f, f.Thumbnail, meta, f.ColorContexts)); 51 enc.Save(fsout); 52 } 53 54 PicInfoCollection.Add(new(outPath)); 55 }

試したこと

PicInfoCollectionを作りました。
SubWindowを開き、無事画像が表示されるようになりましたが
MainWindowに表示されません。
また、画像の削除等も出来ないです。

PicInfoCollectionから、今操作しているものの逆探知?みたいなのが出来て
それをSelectPicに入れたり、PicInfoCollectionから削除できたりしたら
分かりやすくて良いのですが、

DelegateCommand.csと同じ(Class名とかのみ変更)のClassファイルを
作成し、ボタンクリック時に動作させようともしましたが、
それも上手くいきませんでした。

SubWindow.xaml.cs

1 private void Ok_Button_Click(object sender, RoutedEventArgs e) 2 { 3 if (MyList.SelectedItem == null) 4 { 5 DialogResult = true; // ListViewで何も選択されていない場合は何もしない 6 } 7 else 8 { 9 PicInfo item = (PicInfo)MyList.SelectedItem; // ListViewで選択されている項目を取り出す 10 viewModel.SelectedPic = item; 11 DialogResult = true; 12 } 13 }

MainWindow.xaml

1 <Image Source="{Binding SelectedPic.PicFilePath}" StretchDirection="DownOnly" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="1" ></Image>

上記のようにしても、画像はMainWindowに表示されません。
SelectedPicに値は入ったようなのですが…。

補足情報(FW/ツールのバージョンなど)

Visualstudio2022 V17.6.3
.NET 6.0 C#

TN8001👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

SelectPicには値が入っているのにMainWindowに画像が表示されません。

cs

1public PicInfo? SelectedPic { get; set; }

SelectPicの変更通知が、いつのまにかなくなってしまっています。
C#コード側から変更する値は、変更通知を出さないとViewは知りようがありません。

hqf00342さん風に書くならこうです。

cs

1private PicInfo? _selectedPic; 2public PicInfo? SelectedPic { get => _selectedPic; set => SetProperty(ref _selectedPic, value); }

↑が長ったらしくて面倒なので、わたしはCommunityToolkitを使ってこうしていました(意味は全く同じです)

cs

1[ObservableProperty] private PicInfo? selectedPic;

ObservableProperty属性を使うなら、public class ViewModel : BindableBasepublic partial class ViewModel : ObservableObjectに変更する必要があります。

PicInfoCollectionから、今操作しているものの逆探知?みたいなのが出来て
それをSelectPicに入れたり、PicInfoCollectionから削除できたりしたら
分かりやすくて良いのですが、

xml

1<Button 2 x:Name="MainPicShow" 3 Click="Ok_Button_Click" 4 Command="{Binding ApplyCommand}" 5 CommandParameter="{Binding PicInfoCollection/}" 6 Content="メインウィンドウに表示" />

ApplyCommandが残ってるなら、そこで既にSelectPicに代入しているはずです(Ok_Button_Clickでやる意味がない)

DeleteCommandも残ってると思うのですが、ListViewの中とは別にボタンを作りたいということですか?(ListViewの中のボタンに気が付いていない?)

DelegateCommand.csと同じ(Class名とかのみ変更)のClassファイルを
作成し、ボタンクリック時に動作させようともしましたが、
それも上手くいきませんでした。

DelegateCommand(委譲コマンド)というのは、ICommandを簡単に作れるようにしたものです(意味が分からないでしょうが、分からなくても大丈夫です)
似たクラスを作る必要はありません。与えるラムダ(あるいはメソッド)を変更します。
コマンドが呼ばれると中のラムダが実行されます。引数はCommandParameterです。

cs

1private DelegateCommand? _picDeleteCommand; 2public DelegateCommand PicDeleteCommand => _picDeleteCommand ??= new(pic => PicInfoCollection.Remove(pic));

CommunityToolkitで↑と同じことを書くならこうです(メソッド名にCommandを付けたコマンドを自動生成します)

cs

1[RelayCommand] 2private void PicDelete(PicInfo? pic) 3{ 4 PicInfoCollection.Remove(pic); 5}

コマンドができたらボタンにバインドします。

xml

1<Button 2 x:Name="DeleteButton" 3 Command="{Binding PicDeleteCommand}" 4 CommandParameter="{Binding PicInfoCollection/}" 5 Content="削除" />

選択した画像とRectangleを組み合わせ、ファイルを作成する予定です。

HtmlFolderという新しいワードが出てきましたが、最終的にHTMLを出力するんですか?(ホームページ・ビルダーのようなもの??)

再利用するために、取り回し良く?する必要があります。

「再利用」というのはどこのだれがいつするんでしょう?
今のところViewModelは全部把握できていると思われますが...

とりあえず今はシンプルに

「本当はドラッグ移動とかしたいけど、DataGridで編集できるので(とりあえずは)いいや」という意味ですよね?

「本当は文字とか表とかいろいろなものを入れる予定ですっ!」って意味じゃないですよね?(いやそういう意味でもいいですが、だとすると先が長すぎてわたしはこのペースでは付き合いきれないですね^^;

投稿2023/07/10 09:01

編集2023/07/10 09:06
TN8001

総合スコア10104

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TN8001

2023/07/10 09:01

CommunityToolkitとオレオレ実装のちゃんぽんが混乱を助長しているのかなぁ? 個人的には折角.NET6使ってるなら、ソースジェネレーターしない手はないと思うのだけど。 基本(自前実装)が分かったうえで応用?ということなんだろうけど、もうこの辺はすっ飛ばしたいところ(文字数的にも辛いし^^; [MVVM ソース ジェネレーター - .NET Community Toolkit | Microsoft Learn](https://learn.microsoft.com/ja-jp/dotnet/communitytoolkit/mvvm/generators/overview)
hqf00342

2023/07/10 14:11 編集

Toolkit,mvvmはQiitaでお薦め記事書いているぐらいなので https://qiita.com/hqf00342/items/40a753edd8e37286f996 https://qiita.com/hqf00342/items/d12bb669d1ac6fed6ab6 個人的には使ってほしいです。 サンプルなのでtoolkit使わなかったのですがこのまま下敷きにされるとは思ってなかったのです・・・ 前の質問時には使ってそうな気配があったのでぜひご自身で直してほしいです。
TN8001

2023/07/10 14:44 編集

@hqf00342さん あ、イヤhqf00342さんに向けて愚痴ってるわけではないです^^; INotifyPropertyChangedの仕組み自体は極単純なんですが、MVVMという文脈で出てくるとなぜかやけに難しいもののように受け取られている感じがします。 もうその辺の説明をすっ飛ばして「とにかくこうします」で済ませてもいいのかな?とw というか【2】の回答を練り直してるんですが1万字がほんとにきついw 「再利用するために、取り回し良く?する必要があります。」 というのはclass MyDataのようなことを言ってるんだと思うんですが、これってシングルトンではないですよね? 通常シングルトンパターンというと↓のようなものだと思います。 class Singleton {   public static Singleton Instance { get; } = new Singleton();   private Singleton() { } } でもこれをヒントに何とか1万字に収まりそうな目途がつきました。ありがとうございます^^ これで移動リサイズ時に邪魔だった無関係コードをきれいに省略できそうです。 こんなVM in VMみたいな風でw(ModelがCommand持ってもいいっすよね?^^; public class ViewModel {   public PictModel? Pict { get; init; }   public RectModel? Rect { get; init; } } そうすれば命名が被る心配もないし省略も簡単でいいなーと。
hqf00342

2023/07/11 04:03 編集

サンプルにToolKit(v8)を使わなかった理由は「自分が定義していない名前のプロパティ/コマンドがいつの間にかあってそれを使う」ことが逆に混乱を招くのでは、と思ったことも理由の1つではあります。 シングルトンの定義は置いておきましょうw。 最初はMVVMにこだわりすぎると(MessangerやDIまで話が及ぶと面倒なので)よくないと思います。 ViewにBindingしてもいいと思いますし、ModelとViewModelを合体させてもありだと思います。
hqf00342

2023/07/11 04:51 編集

PicInfoクラスのコードがないので実装されているかわからないですが <Image Source="{Binding SelectedPic.PicFilePath}" ならば PicFilePath プロパティにも変更通知が必要かもしれません。
TN8001

2023/07/11 08:33

> 自分が定義していない名前のプロパティ/コマンドがいつの間にかあって 「それなー」案件ですね^^; > PicInfoクラスのコードがないので実装されているかわからないですが nodoitaさんもいろいろ試行錯誤されているようで、その際に命名が変わったり内容が変わったりはありそうですね。 > PicFilePath プロパティにも変更通知が必要 SelectedPicが変われば通知は飛ぶはずです。
nodoita

2023/07/12 01:11

TN8001様 回答ありがとうございます!お忙しいのに色々と本当にありがとうございます。 >SelectPicの変更通知が、いつのまにかなくなってしまっています。 あぁあ!本当ですね!! 変更通知を入れたら出るようになりました!ありがとうございます!! >ApplyCommandが残ってるなら、そこで既にSelectPicに代入しているはずです(Ok_Button_Clickでやる意味がない) >DeleteCommandも残ってると思うのですが、ListViewの中とは別にボタンを作りたいということですか?(ListViewの中のボタンに気が付いていない?) ListView内の削除ボタンは動作しません。 ViewModelをMVVM形式?にしていないからか [RelayCommand]のところが反映せず移行が上手くいっていなかったため形(xaml)だけそのまま移行した形になってました。 ListViewの中とは別にボタンがあっても分かりやすいと思い、 ListView外にボタンを作ろうしているのですが色々かkンが得てうまくできました! 良い物かどうかは分かりませんが、とりあえず動けば問題ないです! ◆SbuWindow.xaml.cs private void DeleteButton_Click(object sender, RoutedEventArgs e) { PicInfo item = (PicInfo)MyList.SelectedItem; // ListViewで選択されている項目を取り出す viewModel.DeletePic(item); } ◆ViewModel public void DeletePic(PicInfo item) { if (MessageBox.Show(item.PicName + "を削除しても良いですか?", "ファイル削除", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.No) { return; } PicInfoCollection.Remove(item); File.Delete(item.PicFilePath); } >「本当はドラッグ移動とかしたいけど、DataGridで編集できるので(とりあえずは)いいや」という意味ですよね? 画像と紐づけをしたHTMLを出力したいだけです!表とかその他追加は考えておりません、ありがとうございます。 ドラッグ移動や拡大なども出来たら良いなと思いましたが、 DataGridで変更したら反映するので、できたら作るで良いなと思ってます。 hqf00342様も、ありがとうございます!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問