C#でTOML読み書き

# ■概要

 C#でTOMLファイル読み書き

# ■環境

* Windows 10
* Visual Studio Community 2019 Version 16.6.4
* .NET Framework 4.5.2/.NET Core 3.1

# ■準備

NuGetで`Nett`をインストール

# ■画面イメージ

実行ファイルと同じ場所にTOML形式の設定ファイル作成
![screenshot1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142879/6e7e0758-ec52-ec0c-6e6f-6436a663ef23.png)

```toml:TomlTestCore.toml（設定ファイル）
Width = 650.0

[InputItems]
Item1 = "あいうえお"
Item2 = "＠＠＠＠＠＠＠＠＠"
Item3 = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
Item4 = 12
```

# ■コード

.NET Coreで`TomlTestCore`というプロジェクト名で作成。

```xml:MainWindow.xaml
<Window
    x:Class="TomlTestCore.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:local="clr-namespace:TomlTestCore"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="650"
    Height="250"
    ResizeMode="CanResizeWithGrip"
    mc:Ignorable="d">
    <Window.Resources>
        <!--  項目ラベルスタイル  -->
        <Style x:Key="ItemLabelStyle" TargetType="Label">
            <Setter Property="Width" Value="80" />
            <Setter Property="Margin" Value="5" />
        </Style>
        <!--  入力項目スタイル  -->
        <Style x:Key="ItemInputStyle" TargetType="TextBox">
            <Setter Property="Width" Value="300" />
            <Setter Property="Margin" Value="5" />
            <Setter Property="VerticalContentAlignment" Value="Center" />

            <EventSetter Event="GotFocus" Handler="ItemInput_GotFocus" />
        </Style>
        <!--  ボタン既定スタイル  -->
        <Style TargetType="Button">
            <Setter Property="Width" Value="100" />
            <Setter Property="Height" Value="35" />
            <Setter Property="Margin" Value="5,15,5,5" />
        </Style>
    </Window.Resources>

    <StackPanel Background="LavenderBlush" FocusManager.FocusedElement="{Binding ElementName=Item1}">
        <StackPanel Orientation="Horizontal">
            <Label
                Content="項目1(_1)"
                Style="{StaticResource ItemLabelStyle}"
                Target="{Binding ElementName=Item1}" />
            <TextBox x:Name="Item1" Style="{StaticResource ItemInputStyle}" />
        </StackPanel>

        <StackPanel Orientation="Horizontal">
            <Label
                Content="項目2(_2)"
                Style="{StaticResource ItemLabelStyle}"
                Target="{Binding ElementName=Item2}" />
            <TextBox x:Name="Item2" Style="{StaticResource ItemInputStyle}" />
        </StackPanel>

        <DockPanel LastChildFill="True">
            <Label
                Content="項目3(_3)"
                DockPanel.Dock="Left"
                Style="{StaticResource ItemLabelStyle}"
                Target="{Binding ElementName=Item3}" />
            <TextBox
                x:Name="Item3"
                Width="Auto"
                Style="{StaticResource ItemInputStyle}" />
        </DockPanel>

        <StackPanel Orientation="Horizontal">
            <Label
                Content="項目4(_4)"
                Style="{StaticResource ItemLabelStyle}"
                Target="{Binding ElementName=Item4}" />
            <TextBox
                x:Name="Item4"
                Width="40"
                MaxLength="3"
                Style="{StaticResource ItemInputStyle}" />
        </StackPanel>

        <StackPanel Orientation="Horizontal">
            <Button
                x:Name="SaveButton"
                Click="SaveButton_Click"
                Content="保存(_S)" />
            <Button
                x:Name="LoadButton"
                Click="LoadButton_Click"
                Content="読み込み(_L)" />
            <Button
                x:Name="ClearButton"
                Click="ClearButton_Click"
                Content="クリア(_C)" />
        </StackPanel>
    </StackPanel>
</Window>
```

```CSharp:MainWindow.xaml.cs
using Nett;
using System;
using System.Windows;
using System.Windows.Controls;

namespace TomlTestCore
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 画面の値を設定ファイルに保存
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SaveButton_Click(object sender, RoutedEventArgs e)
        {
            var toml = Toml.Create();

            toml.Add("Width", Width);

            var inputItems = Toml.Create();
            inputItems.Add("Item1", Item1.Text);
            inputItems.Add("Item2", Item2.Text);
            inputItems.Add("Item3", Item3.Text);
            inputItems.Add("Item4", int.TryParse(Item4.Text, out int i) ? i : 99);

            toml.Add("InputItems", inputItems);

            Toml.WriteFile(toml, GetConfigFilePath());
        }

        /// <summary>
        /// 設定ファイルの値を画面に読み込み
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void LoadButton_Click(object sender, RoutedEventArgs e)
        {
            var toml = Toml.ReadFile(GetConfigFilePath());

            Width = toml.Get<double>("Width");

            var inputItems = toml.Get<TomlTable>("InputItems");
            Item1.Text = inputItems.Get<string>("Item1");
            Item2.Text = inputItems.Get<string>("Item2");
            Item3.Text = inputItems.Get<string>("Item3");
            Item4.Text = inputItems.Get<int>("Item4").ToString();
        }

        /// <summary>
        /// 画面クリア
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClearButton_Click(object sender, RoutedEventArgs e)
        {
            Item1.Clear();
            Item2.Clear();
            Item3.Clear();
            Item4.Clear();
            Item1.Focus();
        }

        /// <summary>
        /// テキストボックスフォーカス取得時
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ItemInput_GotFocus(object sender, RoutedEventArgs e)
        {
            // 全選択
            (sender as TextBox).SelectAll();
        }

        /// <summary>
        /// 設定ファイルのフルパスを取得
        /// </summary>
        /// <returns>設定ファイルのフルパス</returns>
        private string GetConfigFilePath()
        {
            // 実行ファイルのフルパスを取得
            string appFilePath = System.Reflection.Assembly.GetEntryAssembly().Location;

            // 実行ファイルのフルパス末尾（拡張子）を変えて返す
            return System.Text.RegularExpressions.Regex.Replace(
                appFilePath,
                "\\.exe|dll$",
                "toml",
                System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        }

    }
}
```