アプリのウィンドウの位置とListboxに表示する文字列を、ファイルに保存と読み込みをWPF(.NET Core 3.1、C#)で試してみた
アプリのウィンドウの位置は左で
この状態をファイルに保存
リストに文字列(山芋)を追加して
ウィンドウを右側に移動してから
さっき保存した設定を読み込むと
ウィンドウの位置が戻って
リスト内容も山芋が消えて、保存時の状態になった
条件というか決め打ち
- ファイルの保存場所はアプリの実行ファイルと同じ
- ファイル名はAppConfig.xml
MainWindow.xaml
<Window x:Class="_20201104_アプリの設定保存_文字列リスト.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:_20201104_アプリの設定保存_文字列リスト" mc:Ignorable="d" Title="MainWindow" Height="250" Width="300" Top="{Binding Path=WindowTop, Mode=TwoWay}" Left="{Binding Path=WindowLeft, Mode=TwoWay}"> <Window.Resources> <Style TargetType="Button"> <Setter Property="Margin" Value="8,2"/> </Style> </Window.Resources> <Grid Margin="0,10"> <StackPanel> <Button x:Name="ButtonSave" Content="設定保存" Click="ButtonSave_Click"/> <Button x:Name="ButtonLoad" Content="設定読み込み" Click="ButtonLoad_Click"/> <Grid Margin="0,10"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition Width="100"/> </Grid.ColumnDefinitions> <TextBox x:Name="MyTextBox" Grid.Column="0" Margin="8,2" DockPanel.Dock="Left"/> <Button x:Name="ButtonAdd" Grid.Column="1" Content="リストに追加" Click="ButtonAdd_Click"/> </Grid> <ListBox x:Name="MyList" ItemsSource="{Binding Path=StringList}" Margin="8,0"/> </StackPanel> </Grid> </Window>
MainWindow.xaml.cs
using System; using System.Collections.Generic; using System.Text; using System.Windows; namespace _20201104_アプリの設定保存_文字列リスト { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { private AppData MyAppData = new AppData();//設定データ用 private string AppConfigFilePath;//設定ファイルのパス用 public MainWindow() { InitializeComponent(); MyAppData = new AppData(); this.DataContext = MyAppData; //設定ファイルのパスを設定 //アプリの実行ファイルがあるフォルダのパスを取得してファイル名を追加 AppConfigFilePath = System.IO.Path.GetDirectoryName( System.Reflection.Assembly.GetExecutingAssembly().Location); AppConfigFilePath += "\\" + "AppConfig.xml"; } private void ButtonSave_Click(object sender, RoutedEventArgs e) { SaveAppConfig(); } //シリアライズして保存 private void SaveAppConfig() { var serializer = new System.Xml.Serialization.XmlSerializer(typeof(AppData)); try { using (var stream = new System.IO.StreamWriter(AppConfigFilePath, false, new UTF8Encoding(false))) { serializer.Serialize(stream, MyAppData); } } catch (Exception ex) { MessageBox.Show($"保存できなかった\n{ex.Message}"); } } private void ButtonLoad_Click(object sender, RoutedEventArgs e) { LoadAppConfig(); } private void LoadAppConfig() { var serializer = new System.Xml.Serialization.XmlSerializer(typeof(AppData)); try { using (var stream = new System.IO.StreamReader(AppConfigFilePath, new UTF8Encoding(false))) { MyAppData = (AppData)serializer.Deserialize(stream); } //読み込んだデータをアプリのDataContextに指定 this.DataContext = MyAppData; } catch (Exception ex) { MessageBox.Show($"読み込みできなかった\n{ex.Message}"); } } //リストにテキストボックスの文字列追加 private void ButtonAdd_Click(object sender, RoutedEventArgs e) { MyAppData.StringList.Add(MyTextBox.Text); MyList.Items.Refresh();//リストの表示更新が必要 } } /// <summary> /// アプリの設定のデータ用 /// </summary> [Serializable]//これは付けなくても動いた public class AppData { public List<string> StringList { get; set; } public double WindowTop { get; set; }//ウィンドウのY座標用 public double WindowLeft { get; set; }//X座標用 public AppData() { StringList = new List<string>(); } } }
保存するデータ用のクラス、AppData
ウィンドウのx,y座標はdouble型
リストボックスの文字列群はList
86行目のSerializable属性は付けなくても問題なさそうだったけど、気分的に付けた
アプリ起動時
AppDataクラスをアプリのDataContextに指定している、こうしておいてxamlのほうでバインディングしている
そのバインディングは
ウィンドウの位置のバインディングは9と10行目でしている、ModeはTwoWayを指定で期待通りの動きになった
リストボックスのバインディングは30行目でしている、Modeは指定しなくても期待通りの動きだった
リストボックスに文字列を追加するときはバインディング元データに文字列を追加する
リストボックスに直接追加することもできるかもしれないけど、元データに追加するほうがラク
追加したあとはRefresh()すると表示が更新された
設定の保存
System.Xml.Serialization.XmlSerializerクラスでシリアライズして保存してるけど、このへんはよくわかっていない
保存したファイルを見てみる
さっきのこの状態保存したファイルは
アプリの実行ファイルと同じフォルダにあるAppConfig.xml
これをテキストエディタとかで開いてみる
それっぽいのが書いてある
読み込み
読み込んだあとは、改めてDataContextに指定する必要があった、65行目
感想
意外にラクだった、特にList
もっとラク?な方法は
このアプリのプロパティの設定画面で既定値を指定して、Properties.Settings.Defaultとか使う方法があるけど、
[C#/WPF]Setting.settingを使用して、簡易的にアプリの設定値を保存/読出しする - Qiita https://qiita.com/tera1707/items/2ebc0e5c48dc5226f60c
こちらを見ると、アプリのバージョンに変更があった場合は、設定ファイルの保存場所が変化してしまって、設定を引き継げないとか不便かなあと、なので今回の方法に落ち着きそう
関連記事?
Pixtack紫陽花2nd、編集状態をファイルに保存できるようにした - 午後わてんのブログ
https://gogowaten.hatenablog.com/entry/14103815
4.5年前、全然覚えていない