atelier:mitsuba

i love UI/UX, Blend, XAML, Behavior, P5, oF, Web, Tangible Bits and Physical computing. なにかあればお気軽にご連絡ください。atelier@c-mitsuba.com

WPFで表示したListを、CSV化するコードを書かずにExcelで表示する。

世は大Excel時代。
あれもこれもなんでもExcelで。これExcelで見れへんの???CSVとかにならんの????
みたいなのは日常茶飯事で、毎回毎回CSVを出力するコード書くのはダルいめんどい飽きた。


色々調べてみると、最近のExcelJSON読めるらしいってことにたどり着いた。
なので今回は、WPFなりUWPなり、.NETで作られたListをJSONに出力して、Excelで表示までやってみる。


作ったアプリと書いたコードはこんなかんじ。

なんてことはない、どっかで見た名前がListで表示されてて、ボタン押すとファイルダイアログが出てきて、JSONで保存するだけ。
f:id:c-mitsuba:20201203062725p:plain

サンプルだからMVVMとかしてないし、エラー処理もしてない。


MainWindow.xaml

<Window x:Class="WpfApp1.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"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid Margin="16,8,16,8">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="FirstName" Grid.Column="0"
                       Background="#FFB4B4B4" Padding="4,4,4,4"/>
            <TextBlock Text="LastName" Grid.Column="1" 
                       Background="#FF6E6E6E" Padding="4,4,4,4" Foreground="White"/>
            <TextBlock Text="Age" Grid.Column="2"
                       Background="#FFB4B4B4" Padding="4,4,4,4"/>
            <TextBlock Text="IdolType" Grid.Column="3"
                       Background="#FF6E6E6E" Padding="4,4,4,4" Foreground="White"/>
        </Grid>
        <ListView Grid.Row="1" Margin="8" x:Name="IdolList">
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="{Binding FirstName}" Grid.Column="0"
                                   Background="#FFB4B4B4" Padding="4,4,4,4"/>
                        <TextBlock Text="{Binding LastName}" Grid.Column="1"
                                   Background="#FF6E6E6E" Padding="4,4,4,4" Foreground="White"/>
                        <TextBlock Text="{Binding Age}" Grid.Column="2"
                                   Background="#FFB4B4B4" Padding="4,4,4,4"/>
                        <TextBlock Text="{Binding IdolType}" Grid.Column="3"
                                   Background="#FF6E6E6E" Padding="4,4,4,4" Foreground="White"/>
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <Button Margin="8" Content="output" Grid.Row="2" Click="OutputButton_Click"/>
    </Grid>
</Window>


JSONの出力は、Newtonsoft.jsonシリアライズして出力してる。

MainWindow.xaml.cs

using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows;
using Microsoft.Win32;
using Newtonsoft.Json;
using Formatting = Newtonsoft.Json.Formatting;

namespace WpfApp1
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += MainWindow_Loaded;
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            IdolList.ItemsSource = new List<Idol>
            {
                new Idol { FirstName = "Mayu", LastName = "Sakuma", Age = 16, IdolType = "Cute" },
                new Idol { FirstName = "Kaede", LastName = "Takagaki", Age = 25, IdolType = "Cool" },
                new Idol { FirstName = "Sae", LastName = "Kobayakawa", Age = 15, IdolType = "Cute" },
                new Idol { FirstName = "Syuko", LastName = "Shiomi", Age = 18, IdolType = "Cute" },
                new Idol { FirstName = "Kako", LastName = "Takafuji", Age = 20, IdolType = "Cool" },
                new Idol { FirstName = "Nagi", LastName = "Hisakawa", Age = 14, IdolType = "Passion" },
                new Idol { FirstName = "Hayate", LastName = "Hisakawa", Age = 14, IdolType = "Cool" },
                new Idol { FirstName = "Riamu", LastName = "Yumemi", Age = 19, IdolType = "Passion" },
            };
        }

        private async void OutputButton_Click(object sender, RoutedEventArgs e)
        {
            var list = IdolList.ItemsSource;

            var dialog = new SaveFileDialog
            {
                Title = "保存先のファイルを選択してください",
                Filter = "JSONファイル(*.json)|*.json"
            };
            var serializeObject = JsonConvert.SerializeObject(list, Formatting.Indented);
            if (dialog.ShowDialog() == true)
            {
                await using var w = new StreamWriter(dialog.FileName, false, Encoding.UTF8);
                await w.WriteAsync(serializeObject);
            }
        }
    }

    public class Idol
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Age { get; set; }
        public string IdolType { get; set; }
    }

}


ここからはExcelのターン。

まずはエクスプローラーで出力したjsonのパスをコピーする。
shift押しながら右クリックすると、メニューにパスコピーが表示される。
f:id:c-mitsuba:20201203063557p:plain

Excelのリボンから、「データ、新しいクエリ、その他のデータソースから、Webから」を選択。
f:id:c-mitsuba:20201203063807p:plain

ダイアログが表示されるから、コピーしたパスを貼っ付ける。
f:id:c-mitsuba:20201203063924p:plain

すると、怒られるから、両端のダブルコーテーションを外してOK。
f:id:c-mitsuba:20201203064020p:plain

Power Queryエディターが表示される。
リストのRecordがJsonの1アイテムになってる。

左上の「テーブルへの変換」をクリックする。
f:id:c-mitsuba:20201203064104p:plain

テーブルに変換すると、リストがCloumn1に変わったから、Column1の右にあるボタンをクリックして展開する。
f:id:c-mitsuba:20201203064239p:plain

展開すると項目が表示されるから、扱いたいものにチェックを入れてOK。
f:id:c-mitsuba:20201203064318p:plain

全部チェックを入れるとこんなかんじに展開される。
f:id:c-mitsuba:20201203064415p:plain

欲しい表になったら、左上の「閉じて読み込む」をクリックする。
そしたら、JSONがちゃんと表になってインポートされる。
f:id:c-mitsuba:20201203064517p:plain

もちろん表になってるからソートもできる。
f:id:c-mitsuba:20201203064618p:plain


ちなみにjsonの中身を貼っておくとこんなかんじ。

idol.json

[
  {
    "FirstName": "Mayu",
    "LastName": "Sakuma",
    "Age": 16,
    "IdolType": "Cute"
  },
  {
    "FirstName": "Kaede",
    "LastName": "Takagaki",
    "Age": 25,
    "IdolType": "Cool"
  },
  {
    "FirstName": "Sae",
    "LastName": "Kobayakawa",
    "Age": 15,
    "IdolType": "Cute"
  },
  {
    "FirstName": "Syuko",
    "LastName": "Shiomi",
    "Age": 18,
    "IdolType": "Cute"
  },
  {
    "FirstName": "Kako",
    "LastName": "Takafuji",
    "Age": 20,
    "IdolType": "Cool"
  },
  {
    "FirstName": "Nagi",
    "LastName": "Hisakawa",
    "Age": 14,
    "IdolType": "Passion"
  },
  {
    "FirstName": "Hayate",
    "LastName": "Hisakawa",
    "Age": 14,
    "IdolType": "Cool"
  },
  {
    "FirstName": "Riamu",
    "LastName": "Yumemi",
    "Age": 19,
    "IdolType": "Passion"
  }
]

これでExcel大好きマンでもJSONが扱えるようになったから、いちいちCSV化するコードなんて書かなくていいね!
CSV出力コードなんてもう無駄な工数だね!!!やったね!!!