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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

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

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

WPF

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

Q&A

1回答

1305閲覧

WPF「ObservableCollection」「INotifyCollectionChanged」「Class」が良く分からない

pineapple3

総合スコア0

C#

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

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

WPF

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

0グッド

1クリップ

投稿2022/03/09 04:40

初めまして、よろしくお願いいたします。

前提・実現したいこと

WPFで表を作る場合、「ObservableCollection」でまとめたほうが良いとみかけます。
「INotifyCollectionChanged」を利用すれば、更新したという事が分かるとも見かけました。
物凄く初歩的な話を分かっていないのだと思います。

以下内容を一行したいと思っています。
①データをファイルから読み込む(Button1)
②WPFアプリ上でテキストボックスなど入力後ボタンを押してデータを追加する(Button3)
③データをファイルに書き出す(①と③は同じデータ形式)(Button2?)

例えるなら、CSVをWPF上で開き、変更して保存したいという感じです。
列の項目は決まっており、途中コンボボックスでしか選択できない項目もあります。

別のフォームでも値を利用したいことから、
Publicにすればいいと思いました。

とりあえず、XMLファイルへの書き出し、読み込みをしようと思っています。

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

 1.xmlファイルの読み込みの、どこがおかしいのかが分からない。
https://memo.abridge-lab.com/?p=145」のサイトを参考にしましたが、
Class?のつくり方が違うので良くわかりませんでした。
xmlファイルを読込み、itemsの中にデータを入れてDataGridにデータを表示させたいです。

 2.IDは連番(カウントアップ方式で重ならない)にしたいのですが、番号の保持方法が良く分からない
※ 行の削除、追加も検討中のため、IDを変更することがあります

該当のソースコード

xaml

1<Window x:Class="ClickCap.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:ClickCap" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="450" Width="800"> 9 <Grid> 10 <DataGrid ItemsSource="{Binding}" AutoGenerateColumns="False" Margin="0,0,0,67"> 11 <DataGrid.Columns> 12 13 <DataGridTextColumn Header="ID" Binding="{Binding Myid}" /> 14 <DataGridTextColumn Header="タイトル" Binding="{Binding Title}" /> 15 <DataGridTextColumn Header="詳細" Binding="{Binding Detail}" /> 16 </DataGrid.Columns> 17 </DataGrid> 18 <Button Content="Button" HorizontalAlignment="Left" Margin="182,391,0,0" VerticalAlignment="Top" Click="Button_Click"/> 19 <Button Content="Button" HorizontalAlignment="Left" Margin="446,392,0,0" VerticalAlignment="Top" Click="Button_Click_1"/> 20 <Button Content="Button" HorizontalAlignment="Left" Margin="680,392,0,0" VerticalAlignment="Top" Click="Button_Click_2"/> 21 </Grid> 22</Window>

c#

1using System; 2using System.Collections.Generic; 3using System.Collections.ObjectModel; 4using System.IO; 5using System.Linq; 6using System.Text; 7using System.Threading.Tasks; 8using System.Windows; 9using System.Windows.Controls; 10using System.Windows.Data; 11using System.Windows.Documents; 12using System.Windows.Input; 13using System.Windows.Media; 14using System.Windows.Media.Imaging; 15using System.Windows.Navigation; 16using System.Windows.Shapes; 17using System.Xml.Serialization; 18 19namespace ClickCap 20{ 21 /// <summary> 22 /// MainWindow.xaml の相互作用ロジック 23 /// </summary> 24 public partial class MainWindow : Window 25 { 26 public ObservableCollection<Item> items { get; } = new ObservableCollection<Item>(); 27 public class Item 28 { 29 public int Myid { get; set; } 30 public string Title { get; set; } 31 public string Detail { get; set; } 32 public bool Isedit { get; set; } 33 } 34 35 public MainWindow() 36 { 37 InitializeComponent(); 38 items.Add(new Item { Myid = 1, Title = "タイトル1", Detail = "詳細1", Isedit = true }); 39 items.Add(new Item { Myid = 2, Title = "タイトル2", Detail = "詳細2", Isedit = true }); 40 items.Add(new Item { Myid = 3, Title = "タイトル3", Detail = "詳細3", Isedit = false }); 41 this.DataContext = items; 42 } 43 44 private void Button_Click(object sender, RoutedEventArgs e) 45 { 46 47 XmlSerializer serializer = new XmlSerializer(items.GetType()); 48 using (FileStream fs = new FileStream(Directory.GetCurrentDirectory() + "\\" + "mydata.xml", FileMode.Create)) 49 serializer.Serialize(fs, items); 50 } 51 52 private void Button_Click_1(object sender, RoutedEventArgs e) 53 { 54 XmlSerializer serializer = new XmlSerializer(items.GetType()); 55 using (FileStream fs = new FileStream(Directory.GetCurrentDirectory() + "\\" + "mydata.xml", FileMode.Open)) ; 56 //test = (Item)serializer.Deserialize(fs); 57 } 58 59 private void Button_Click_2(object sender, RoutedEventArgs e) 60 { 61 items.Add(new Item { Myid = 7, Title = "追加", Detail = "追加1", Isedit = true }); 62 } 63 } 64} 65

試したこと

 エラーになったところをコメントアウトしてみましたが、何も変わりませんでした。

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

.Net Framework 4.7.2

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

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

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

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

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

guest

回答1

0

WPF「ObservableCollection」「INotifyCollectionChanged」「Class」が良く分からない

というよりわからないのは、XmlSerializerのほうですよね?

1.xmlファイルの読み込みの、どこがおかしいのかが分からない。
(Item)serializer.Deserialize(fs);

itemsをシリアライズしたのですから、デシリアライズされた型はitemsの型です。

(ObservableCollection<Item>)serializer.Deserialize(fs);

 2.IDは連番(カウントアップ方式で重ならない)にしたいのですが、番号の保持方法が良く分からない

データベース等使わずにテキスト(xmlやcsv)で保存するなら、自分で管理する必要があります。
「読み込んだ時に最大値を覚えておく」でいいんじゃないですか?

※ 行の削除、追加も検討中のため、IDを変更することがあります

空いた番号を詰めるということですか?(データベースでは普通しない操作です)
ユニークなIDが必要なのはそれに紐づく別のデータがあるからで、Itemがそれ単体で完結しているならそもそもIDを保存する意味ありますか?

xml

1<Window 2 x:Class="Q1ypxtzrjzwnam0.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 Width="800" 6 Height="450"> 7 <Grid> 8 <Grid.RowDefinitions> 9 <RowDefinition /> 10 <RowDefinition Height="Auto" /> 11 </Grid.RowDefinitions> 12 13 <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding}"> 14 <DataGrid.Columns> 15 <DataGridTextColumn Binding="{Binding Id}" Header="ID" IsReadOnly="True" /> 16 <DataGridTextColumn Binding="{Binding Myid}" Header="Myid" /> 17 <DataGridTextColumn Binding="{Binding Title}" Header="タイトル" /> 18 <DataGridTextColumn Binding="{Binding Detail}" Header="詳細" /> 19 </DataGrid.Columns> 20 </DataGrid> 21 22 <UniformGrid Grid.Row="1" HorizontalAlignment="Center" Rows="1"> 23 <Button Margin="10" Click="SaveButton_Click" Content="Save" /> 24 <Button Margin="10" Click="LoadButton_Click" Content="Load" /> 25 <Button Margin="10" Click="AddButton_Click" Content="Add" /> 26 </UniformGrid> 27 </Grid> 28</Window>

cs

1using System.Collections.ObjectModel; 2using System.IO; 3using System.Linq; 4using System.Windows; 5using System.Xml.Serialization; 6 7namespace Q1ypxtzrjzwnam0 8{ 9 public class Item 10 { 11 public static int MaxId; // 雑いw 12 13 public int Id { get; } 14 [XmlAttribute] public int Myid { get; set; } 15 [XmlAttribute] public string Title { get; set; } 16 [XmlAttribute] public string Detail { get; set; } 17 [XmlAttribute] public bool Isedit { get; set; } 18 19 public Item() => Id = ++MaxId; 20 } 21 22 public partial class MainWindow : Window 23 { 24 public ObservableCollection<Item> Items { get; private set; } = new ObservableCollection<Item>(); 25 26 private int maxMyid; 27 28 public MainWindow() 29 { 30 InitializeComponent(); 31 32 Items.Add(new Item { Myid = 1, Title = "タイトル1", Detail = "詳細1", Isedit = true, }); 33 Items.Add(new Item { Myid = 2, Title = "タイトル2", Detail = "詳細2", Isedit = true, }); 34 Items.Add(new Item { Myid = 3, Title = "タイトル3", Detail = "詳細3", Isedit = false, }); 35 maxMyid = Items.Max(x => x.Myid); 36 37 DataContext = Items; 38 } 39 40 private void SaveButton_Click(object sender, RoutedEventArgs e) 41 { 42 var serializer = new XmlSerializer(Items.GetType()); 43 using (var fs = new FileStream("mydata.xml", FileMode.Create)) 44 serializer.Serialize(fs, Items); 45 } 46 47 private void LoadButton_Click(object sender, RoutedEventArgs e) 48 { 49 Item.MaxId = 0; // 数字が増えちゃうのでリセット^^; 50 51 var serializer = new XmlSerializer(Items.GetType()); 52 using (var fs = new FileStream("mydata.xml", FileMode.Open)) 53 { 54 Items = (ObservableCollection<Item>)serializer.Deserialize(fs); 55 maxMyid = Items.Max(x => x.Myid); 56 57 // Items自体の変更は通知されないので明示的に入れ替え 58 // INotifyPropertyChangedを実装するか、Clear・Addするか 59 DataContext = null; 60 DataContext = Items; 61 } 62 } 63 64 private void AddButton_Click(object sender, RoutedEventArgs e) 65 { 66 var i = ++maxMyid; 67 Items.Add(new Item { Myid = i, Title = $"タイトル{i}", Detail = $"詳細{i}", Isedit = true, }); 68 } 69 } 70 71}

DataGridの最下行(空行)をクリックするとアイテムが追加されます(禁止にすることもできますが)
注意が必要です(現状Myidが0で追加される)

ぐちゃぐちゃマージン(Margin="182,391,0,0"のようなもの)はやめましょう。
ウィンドウをリサイズすると大変残念なことになります。

投稿2022/03/09 09:38

編集2023/07/30 05:09
TN8001

総合スコア9317

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問