CSVファイルの読み書き設定をC#スクリプトで記述するWPFアプリをDesktop App Converterで変換してストアに公開しました
デスクトップアプリをUWPに変換してWindowsストアに公開可能な状態にするDesktop App Converterを試してみたい!
ということで、ブログのネタで作成していたWPFアプリ(CsvEditSharp)をDesktop App Converterに掛けてストアに公開するまでをチャレンジしてみました。
ひとまず、公開まで漕ぎつけることができたので、アプリの宣伝をしておきます。
CsvEditSharp
CsvEditSharpは、CSVファイルの読み書き設定をC#スクリプトで記述するCSVエディタです。
スクリプトでは、C#でCSVファイルを扱うためのクラスライブラリCsvHelperのAPIを利用して各種設定を記述します。
Windows Storeから無料でダウンロードできます。(Windows10 Anniversary Update 以降のデスクトップPCのみで利用可能)
基本操作
設定スクリプトのひな型を生成してCSVファイルを読み込む
初めて扱うCSVファイル等、設定スクリプトが存在していない場合に、CSVファイルの読み込みと同時に設定スクリプトのひな型を生成することができます。
- ツールバーの「Configuration Script」コンボボックスで "(Auto Genarate)" を選択します
「Open」ボタンをクリックして読み込むCSVファイルを選択します
以下のダイアログで、自動生成される設定スクリプトの名前、CSVファイルのエンコーディングおよびヘッダレコードの有無を入力して[OK]をクリックします
次のように、選択したCSVファイルのヘッダ情報を基に設定スクリプトが自動生成されます。
レコード格納クラスがFieldData
という名前で生成されます。
- クラス内の各プロパティが1つのカラムを表します
- ヘッダレコードに定義されているカラム名が、そのままプロパティ名となります
- プロパティのデータ型は全て文字列(string)型となります
- カラム名にプロパティ名として使用できない文字が含まれる場合、またはヘッダレコードが存在しない場合のプロパティ名には
column_
+カラム番号
が割り当てられます
設定スクリプトのひな型をカスタマイズする
設定スクリプトの編集
設定スクリプトを、読み込んだCSVファイルの内容に応じて書き換えます。
Encoding = Encoding.GetEncoding("utf-8"); //Genderの選択肢を定義するenum enum Gender { Male, Female } //レコード格納クラスの名前を変更 class Person { //プロパティの型をデータの種類に応じて変更 public string Name { get; set; } public DateTime Birthday { get; set; } public Gender Gender { get; set; }public bool Married { get; set; } public double PocketMoney { get; set; } } //クラスマッピングの設定も、扱うデータの種類に応じたものに変更 RegisterClassMap<Person>(classMap => { classMap.Map(m => m.Name).Name("Name"); classMap.Map(m => m.Birthday).Name("Birthday") .TypeConverterOption("M/d/yyyy"); classMap.Map(m => m.Gender).Name("Gender"); classMap.Map(m => m.Married).Name("Married") .TypeConverterOption(true,"Y") .TypeConverterOption(false,"N"); var culture = System.Globalization.CultureInfo.GetCultureInfo("en-us"); classMap.Map(m => m.PocketMoney).Name("PocketMoney") .TypeConverterOption("C") .TypeConverterOption(NumberStyles.Currency) .TypeConverterOption(culture); });
編集が完了したら[Run]ボタンをクリックして、結果を確認します。
編集したコードに問題がなければ、編集後の設定でCSVファイルが再読み込みされ、内容がCSVエディタに表示されます
設定スクリプトの保存
編集した設定スクリプトは[Save] (上書き保存)ボタン、[SaveAs...] (名前を付けて保存)ボタンで保存できます。
[SaveAs...]ボタンをクリックすると、以下のダイアログが表示されます。
「Save as a new file」を選択
- 現在の設定スクリプトを入力した名前で保存します
「Save into the current directory as "Default.config.csx"」を選択
設定スクリプトを指定してCSVファイルを読み込む
対応する設定スクリプトが既に存在する場合、「Configuration Script」で対応するスクリプトの名前を選択後、CSVファイルを読み込みます。
設定スクリプトの管理
[Settings...]ボタンで表示される以下のダイアログで、作成済みの設定スクリプトの名前変更や削除が可能です。
値の編集
CSVエディタ(読み込んだCSVファイル名のタブ)内のセルを直接編集することができます。
クラスマッピングでマップしたプロパティのデータ型に応じて入力方法や入力可能な値が変わります。
- データ型がenumの場合、enumのメンバーを選択肢としたコンボボックスで値を選択します
- データ型がboolの場合、チェックボックスのON/OFFでTrue/Falseを切り替えます
- データ型が数値型やDateTime型の場合、セルに入力した文字列が目的の型に変換できない場合にエラーメッセージを表示します。
※ AddValidation()
メソッドを使用してより詳細な入力検証を設定することも可能です。
編集したCSVデータの保存
ツールバーの[SaveAs]ボタンをクリックして、編集後のCSVデータを別のCSVファイルとして保存することができます。 CSVエディタに表示されている状態がそのまま保存されます。(Queryメソッドでフィルタ・ソートを行った場合も、表示されている内容がそのまま保存されます。)
設定スクリプトAPI
Encoding プロパティ
Encoding Encoding { get; set; }
対象CSVファイルのエンコーディングを指定します。
省略した場合は Encoding.Default
が割り当てられます。
Encoding = Encoding.GetEncoding("utf-8");
RegisterClassMap メソッド
void RegisterClassMap<T>(); void RegisterClassMap<T>(Action<CsvClassMap<T>> propertyMapSetter); void RegisterClassMap<T>(Action<CsvClassMap<T>> propertyMapSetter, RegisterClassMapTarget target);
CsvHelperを利用したクラスマッピングの設定を記述します。
- 登録するクラスマッピングオブジェクトを引数に取るデリゲート
propertyMapSetter
内に設定内容を記述します。 - 第2引数で、登録したクラスマッピングを使用するタイミングを指定できます。
- RegisterClassMapTarget.Reader : 読み込み時のみ
- RegisterClassMapTarget.Writer : 書き込み時のみ
- RegisterClassMapTarget.Both : 読み書き両用
クラスマッピング設定の記述方法については、CsvHelper 公式ドキュメントのMappingのセクションを参照ください。
//既定のクラスマッピング設定を使用 RegisterClassMap<Person>(); //読み書き両用 RegisterClassMap<Person>(classMap => { classMap.Map(m => m.Name); classMap.Map(m => m.Birthday); classMap.Map(m => m.Gender); classMap.Map(m => m.Married) .TypeConverterOption(true,"Y") .TypeConverterOption(false,"N"); classMap.Map(m => m.PocketMoney) .TypeConverterOption("C") .TypeConverterOption(NumberStyles.Currency); }); //読み込み時のみ RegisterClassMap<Person>(classMap => { classMap.Map(m => m.Name); classMap.Map(m => m.Birthday); classMap.Map(m => m.Gender); classMap.Map(m => m.Married) .TypeConverterOption(true,"Y") .TypeConverterOption(false,"N"); classMap.Map(m => m.PocketMoney) .TypeConverterOption("C") .TypeConverterOption(NumberStyles.Currency); }, RegisterClassMapTarget.Reader);
SetConfiguration メソッド
void SetConfiguration(Action<CsvConfiguration> configurationSetter);
引数configurationSetter
デリゲートに渡されるCsvConfiguration
オブジェクトの値を書き換えることで、CSVファイル読み書き時の詳細な設定を記述することができます。
ここで設定可能な項目の詳細は CsvHelper 公式ドキュメントのConfigurationのセクションを参照ください。
SetConfiguration(config => { config.HasHeaderRecord = false; config.AllowComments = true; config.Comment = '#'; config.Delimiter = ';'; //etc... });
AddValidation メソッド
void AddValidation<TType, TMember>(Expression<Func<TType, TMember>> memberSelector, Func<TMember, bool> validation, string errorMessage);
値変更時の入力検証機能を追加することができます。
memberSelector
デリゲート(式木)で対象となるカラムのプロパティを指定します。validation
デリゲートで検証を通過する条件を指定します。errorMessage
に検証NG時に表示する文字列を指定します。
AddValidation<Person,DateTime>( m => m.Birthday , dt => dt <= DateTime.Now.Date, "Cannot enter a future date."); AddValidation<Person, double>( m => m.PocketMoney , n => (n > 0) && (n < 10000.0), "PocketMoney must be in the range $0 to $10000.");
Query メソッド
void Query<T>(Func<IEnumerable<T>, IEnumerable<T>> query); void Query<T>(Action<IEnumerable<T>> query);
データのフィルタ、ソート
LINQの拡張メソッドを利用して、表示するデータのフィルタ、ソートを行うことができます。
Query<Person>(source => source .Where(m => m.Gender == Gender.Female ) .Where(m => m.Married ) .OrderBy(m => m.PocketMoney) );
データの一括更新
ForEach()
拡張メソッドを使用して、データを書き換えることも可能です。
Query<Person>( record => record .Where( m => m.Gender == Gender.Male ) .Where( m => m.Married ) .ForEach( m => { m.Name += " *"; m.PocketMoney = 0; }) );
(Queryメソッドは、設定スクリプトのタブではなく、CSVデータ表示タブの下部にあるテキストエディタ内に記述します。下記のようなコードを記述後、[Execute]ボタンをクリックすることで、コードが実行され、表示に反映されます。)