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

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

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

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

WPF

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

Q&A

解決済

2回答

5110閲覧

C# WPF 自作クラスをXMLに保存する方法について

退会済みユーザー

退会済みユーザー

総合スコア0

C#

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

WPF

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

0グッド

0クリップ

投稿2019/02/03 16:23

1行で表せるタイトルが考えつかなかったので、抽象的ですみません。
WPFで作っていますが、WPF要素はあまりないと思います。
ソースコードを丸々載せて聞くのは他力本願で申し訳ないので、できるだけ要約して書いてみました。
わかりにくいものに関してはコードを読んでいただくか、追記依頼していただけると助かります。
たぶんVisualStudioにコピペすれば動くので、そちらで確認していただけるとわかりやすい…かもです。

~要約~

Fileクラスでは、string型のFileNameプロパティ、int型のValueプロパティを定義。
FileListクラスでは、File型のコレクション"Files"を持つ。Filesは初期から(FileName)file1~file4、(Value)1~4の4つのインスタンスを持つ
Personクラスでは、string型のNameプロパティ、File型のFile1プロパティ、File型のFile2プロパティを定義
PersonListクラスでは、Person型のコレクション"People"を持つ
ViewModelクラスでは、FileList型のプロパティ、PersonList型のプロパティを持ち、ViewのDataContextに設定
(それぞれ必要なものはNotifyPropertyChangedを実装している。)

DataGrid
→ItemsSourceにはPeopleをバインド
1つ目のComboBox
→ItemsSourceにはFilesをバインド(file1~file4から選択)
→SelectedValueには、DataGridのSelectedValue(Personクラス)のFile1プロパティをバインド
2つ目のComboBox
→ItemsSourceにはFilesをバインド(file1~file4から選択)
→SelectedValueには、DataGridのSelectedValue(Personクラス)のFile2プロパティをバインド
Button「Set」
→PeopleにPerson型のインスタンスを4人分(佐藤、鈴木、高橋、田中)追加。File1、File2はどちらも空
Button「Export」
→ViewModelのインスタンスをXML形式(export.xml)にシリアライズ
Button「Import」
→XML形式(export.xml)をViewModelにデシリアライズし、DataContextを更新

1.Setボタンを押すと佐藤、鈴木、高橋、田中がDataGridに追加される
2.DataGridで誰か(佐藤など)を選択し、ComboBoxでその人が持つFileをfile1~file4から設定
3.2を人数分設定する
4.ExportボタンでXML形式で保存
5.ImportボタンでXML形式で読み込み

~したいこと~

XML形式で保存すると、

XML

1 <PersonList> 2 <People> 3 <Person> 4 <Name>Sato</Name> 5 <File1> 6 <FileName>file1</FileName> 7 <Value>1</Value> 8 </File1> 9 <File2> 10 <FileName>file2</FileName> 11 <Value>2</Value> 12 </File2> 13 </Person> 14 <Person> 15 <Name>Suzuki</Name> 16 <File1> 17 <FileName>file2</FileName> 18 <Value>2</Value> 19 </File1> 20 <File2> 21 <FileName>file3</FileName> 22 <Value>3</Value> 23 </File2> 24 </Person> 25  (略) 26 </People> 27 </PersonList> 28<FileList> 29 <Files> 30 <File> 31 <FileName>file1</FileName> 32 <Value>1</Value> 33 </File> 34 <File> 35 <FileName>file2</FileName> 36 <Value>2</Value> 37 </File> 38 <File> 39 <FileName>file3</FileName> 40 <Value>3</Value> 41 </File> 42 <File> 43 <FileName>file4</FileName> 44 <Value>4</Value> 45 </File> 46 </Files> 47 </FileList>

といったように、せっかくFileListにFileの内容(FileName,Value)を持っているのに、SatoはSatoでFileの内容、SuzukiはSuzukiでFileの内容を持っていて行数が無駄に増えてしまいます。
またImportすると、FileListが持つFileのインスタンスと各個人が持つFileのインスタンスが異なってしまうので、FileListのFileを編集しても各個人の持つFileには反映されなくなってしまいます。
ですので、PersonのFile1、File2にはFileListの持つFileへの参照のようなものを持たせる必要があると思うのですが、どう実現すればよいのかわかりません。

ソースコード

c#

1using System; 2using System.Collections.ObjectModel; 3using System.ComponentModel; 4using System.IO; 5using System.Runtime.CompilerServices; 6using System.Text; 7using System.Windows; 8using System.Xml.Serialization; 9 10namespace test2 11{ 12 /// <summary> 13 /// MainWindow.xaml の相互作用ロジック 14 /// </summary> 15 public partial class MainWindow : Window 16 { 17 public ViewModel ViewModel { get; set; } = new ViewModel(); 18 public MainWindow() 19 { 20 InitializeComponent(); 21 DataContext = ViewModel; 22 } 23 private void Set_Click(object sender, RoutedEventArgs e) 24 { 25 ViewModel.PersonList.People.Add(new Person 26 { 27 Name = "Sato" 28 }); 29 ViewModel.PersonList.People.Add(new Person 30 { 31 Name = "Suzuki" 32 }); 33 ViewModel.PersonList.People.Add(new Person 34 { 35 Name = "Takahashi" 36 }); 37 ViewModel.PersonList.People.Add(new Person 38 { 39 Name = "Tanaka" 40 }); 41 } 42 private void Export_Click(object sender, RoutedEventArgs e) 43 { 44 XmlSerializer xmlSerializer = new XmlSerializer(typeof(ViewModel)); 45 using (StreamWriter streamWriter = new StreamWriter(@"export.xml", false, new UTF8Encoding(false))) 46 { 47 xmlSerializer.Serialize(streamWriter, ViewModel); 48 } 49 } 50 private void Import_Click(object sender, RoutedEventArgs e) 51 { 52 XmlSerializer xmlSerializer = new XmlSerializer(typeof(ViewModel)); 53 using (StreamReader streamWriter = new StreamReader(@"export.xml", new UTF8Encoding(false))) 54 { 55 ViewModel viewModel = (ViewModel)xmlSerializer.Deserialize(streamWriter); 56 ViewModel = viewModel; 57 DataContext = ViewModel; 58 } 59 } 60 } 61 public class ViewModel 62 { 63 public PersonList PersonList { get; set; } = new PersonList(); 64 public FileList FileList { get; set; } = new FileList 65 { 66 Files = new ObservableCollection<File> 67 { 68 new File 69 { 70 FileName = "file1",Value = 1 71 }, 72 new File 73 { 74 FileName = "file2",Value = 2 75 }, 76 new File 77 { 78 FileName = "file3",Value = 3 79 }, 80 new File 81 { 82 FileName = "file4",Value = 4 83 } 84 } 85 }; 86 } 87 public class Person 88 { 89 private string name; 90 public string Name 91 { 92 get { return name; } 93 set 94 { 95 name = value; 96 NotifyPropertyChanged(); 97 } 98 } 99 private File file1; 100 public File File1 101 { 102 get { return file1; } 103 set 104 { 105 file1 = value; 106 NotifyPropertyChanged(); 107 } 108 } 109 private File file2; 110 public File File2 111 { 112 get { return file2; } 113 set 114 { 115 file2 = value; 116 NotifyPropertyChanged(); 117 } 118 } 119 120 public event PropertyChangedEventHandler PropertyChanged; 121 public void NotifyPropertyChanged([CallerMemberName] String propertyName = "") 122 { 123 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 124 } 125 } 126 public class PersonList 127 { 128 public ObservableCollection<Person> People { get; set; } = new ObservableCollection<Person>(); 129 } 130 public class File 131 { 132 private string fileName; 133 public string FileName 134 { 135 get { return fileName; } 136 set 137 { 138 fileName = value; 139 NotifyPropertyChanged(); 140 } 141 } 142 private int val; 143 public int Value 144 { 145 get { return val; } 146 set 147 { 148 val = value; 149 NotifyPropertyChanged(); 150 } 151 } 152 public override string ToString() 153 { 154 return FileName; 155 } 156 public event PropertyChangedEventHandler PropertyChanged; 157 public void NotifyPropertyChanged([CallerMemberName] String propertyName = "") 158 { 159 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 160 } 161 } 162 public class FileList 163 { 164 public ObservableCollection<File> Files { get; set; } = new ObservableCollection<File>(); 165 } 166} 167

XAML

1<Window x:Class="test2.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:test2" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="450" Width="800"> 9 <Grid> 10 <Grid.ColumnDefinitions> 11 <ColumnDefinition/> 12 <ColumnDefinition/> 13 </Grid.ColumnDefinitions> 14 <DataGrid x:Name="People" ItemsSource="{Binding PersonList.People}"/> 15 <StackPanel Grid.Column="1"> 16 <ComboBox ItemsSource="{Binding FileList.Files}" SelectedValue="{Binding SelectedValue.File1, ElementName=People}"/> 17 <ComboBox ItemsSource="{Binding FileList.Files}" SelectedValue="{Binding SelectedValue.File2, ElementName=People}"/> 18 <Button Content="Set" Click="Set_Click"/> 19 <Button Content="Export" Click="Export_Click"/> 20 <Button Content="Import" Click="Import_Click"/> 21 </StackPanel> 22 </Grid> 23</Window> 24

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

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

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

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

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

guest

回答2

0

ベストアンサー

このアプリケーション内でのデータ保存、復元を目的としているのなら簡単にできますよ。
こんな感じに書くと、

C#

1private void Export_Click(object sender, RoutedEventArgs e) { 2 XamlServices.Save(@"export.xml", this.ViewModel); 3} 4private void Import_Click(object sender, RoutedEventArgs e) { 5 this.ViewModel = XamlServices.Load(@"export.xml") as ViewModel; 6 this.DataContext = this.ViewModel; 7}

出力結果はこんな感じになります。

XML

1<ViewModel xmlns="clr-namespace:test2;assembly=TestWpfNetFramework" xmlns:sco="clr-namespace:System.Collections.ObjectModel;assembly=System" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 2 <ViewModel.FileList> 3 <FileList> 4 <FileList.Files> 5 <sco:ObservableCollection x:TypeArguments="File"> 6 <x:Reference>__ReferenceID0</x:Reference> 7 <x:Reference>__ReferenceID3</x:Reference> 8 <x:Reference>__ReferenceID2</x:Reference> 9 <x:Reference>__ReferenceID1</x:Reference> 10 </sco:ObservableCollection> 11 </FileList.Files> 12 </FileList> 13 </ViewModel.FileList> 14 <ViewModel.PersonList> 15 <PersonList> 16 <PersonList.People> 17 <Person Name="Sato"> 18 <Person.File1> 19 <File x:Name="__ReferenceID0" FileName="file1" Value="1" /> 20 </Person.File1> 21 <Person.File2> 22 <File x:Name="__ReferenceID3" FileName="file2" Value="2" /> 23 </Person.File2> 24 </Person> 25 <Person Name="Suzuki"> 26 <Person.File1> 27 <File x:Name="__ReferenceID1" FileName="file4" Value="4" /> 28 </Person.File1> 29 <Person.File2> 30 <File x:Name="__ReferenceID2" FileName="file3" Value="3" /> 31 </Person.File2> 32 </Person> 33 <Person File1="{x:Reference __ReferenceID0}" File2="{x:Reference __ReferenceID1}" Name="Takahashi" /> 34 <Person File1="{x:Reference __ReferenceID2}" File2="{x:Reference __ReferenceID3}" Name="Tanaka" /> 35 </PersonList.People> 36 </PersonList> 37 </ViewModel.PersonList> 38</ViewModel>

要件にあってます?

投稿2019/02/04 10:16

nanase

総合スコア123

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

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

退会済みユーザー

退会済みユーザー

2019/02/04 12:19

実装したい機能はこれで可能となったので、ベストアンサーにさせていただきます。ありがとうございました。
guest

0

PersonのFile1、File2をFileクラスではなくFileListのインデックスを持つようにすればいいのではないでしょうか。

投稿2019/02/03 22:12

YAmaGNZ

総合スコア10258

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

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

退会済みユーザー

退会済みユーザー

2019/02/04 10:53

ComboBoxで選んだ(アイテムの)インデックスをint型で保持するという事でしょうか。 書き忘れていて申し訳ないのですが、Fileは編集だけでなく、追加・削除も想定しているので、Fileを追加・削除した場合に順序が狂ってしまうかと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問