独自にAPIを増やしてデスクトップアプリでプリザンターのエディタの設定を見てみた!

IISの石崎です。
以前に「プリザンターのAPI連携をデスクトップアプリで使ってみた!」「独自にAPIを増やしてデスクトップアプリでプリザンターのすべてを見てみた!」という記事を書きました。

今回は、独自にAPIを増やして「エディタの設定を見やすい一覧表示したい」という夢をかなえるデスクトップアプリのサンプルをC#で書いてみます。

デスクトップアプリ

今回作ってみたデスクトップアプリの見た目です。独自に増やしたAPIで取ってきたエディタの設定を一覧表示しています。内部データの名前をそのまま表示しているので当初の狙いと違い見やすくは成らなかったかもしれません。そこは今後の課題とさせてください。

f:id:imageinformationsystem:20181021191142j:plain

コード

コード全体はこのようになっています。jsonを扱うためにNuGetでJson.NETをインストールしています。

<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"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="SiteSettingsViewer" Height="1000" Width="1000" Icon="icon.png">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Label Content="エディタ設定を表示するデスクトップアプリ" Margin="5,0" Background="MediumBlue" Foreground="White" FontWeight="ExtraBold"/>
        <Button Content=" 設定を取得 " Margin="5,0" HorizontalAlignment="Right" Click="Button_Click"/>

        <ListBox ItemsSource="{Binding}" Grid.Row="1" Margin="10,5" x:Name="listBox">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Border BorderThickness="0,0,0,1" BorderBrush="LightBlue">
                        <Grid Margin="5">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="150"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>

                            <Label Content="{Binding Name}" Margin="5" VerticalAlignment="Center" HorizontalAlignment="Right"/>
                            <DataGrid Grid.Column="1" ItemsSource="{Binding Setting}" IsReadOnly="True"/>
                        </Grid>
                    </Border>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace WpfApp1
{
    /// <summary>
    /// View クラス
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// すべてを取得ボタンの処理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            // Apiキー、HttpClient の準備
            var apiKey = "取得したAPIキー";
            var httpClient = new HttpClient();

            // 取得条件のセット
            var requestData = new ApiRequest();

            // API 呼び出し テーブルの値を取得
            var apiClient = new ApiClient();
            var data = await apiClient.GetDataAsync(httpClient, apiKey, "MySites", requestData);

            // 設定の取得
            var settings =
                JsonConvert.DeserializeObject<SiteSetting>(
                    data.AsEnumerable()
                    .First(row =>
                         row["SiteId"].ToString() == "設定を表示するサイトのID")["SiteSettings"]
                        .ToString()
                );

            // カラム名
            var columnName = settings.EditorColumns;
            // カラム設定
            var columnSettings = settings.Columns;

            // カラム名とカラム設定
            var nameAndSetting = columnName.Select(name =>
            {
                var dt = columnSettings.Clone();
                dt.Rows.Add(columnSettings.AsEnumerable()
                    .FirstOrDefault(row => row["ColumnName"].ToString() == name)?.ItemArray
                    ?? new object[0]);
                return new { Name = name, Setting = dt };
            }).ToArray();

            // 画面にセット
            listBox.DataContext = nameAndSetting;
        }
    }

    /// <summary>
    /// API クライアントクラス
    /// </summary>
    public class ApiClient
    {
        public async Task<DataTable> GetDataAsync(HttpClient httpClient, string apiKey, string baseUrl, string apiName, string apiMethod, ApiRequest requestData)
        {
            requestData.ApiKey = apiKey;
            var json = JsonConvert.SerializeObject(requestData);
            var content = new StringContent(json, Encoding.UTF8, "application/x-www-form-urlencoded");

            var response = await httpClient.PostAsync($"{baseUrl}/{apiName}/{apiMethod}", content);
            var responseContentString = await response?.Content?.ReadAsStringAsync();
            var responseContent = JsonConvert.DeserializeObject<DataTable>(responseContentString);
            return responseContent;
        }

        public async Task<DataTable> GetDataAsync(HttpClient httpClient, string apiKey, string apiName, ApiRequest requestData)
            => await GetDataAsync(httpClient, apiKey, "http://localhost:1759/", apiName, "get", requestData);
    }

    /// <summary>
    /// API リクエストデータモデル
    /// </summary>
    public class ApiRequest
    {
        public string ApiKey { get; set; }
        public long Offset { get; set; }
        public View View { get; } = new View();
    }

    /// <summary>
    /// API リクエストデータモデルに保持されるデータモデル
    /// </summary>
    public class View
    {
        public Dictionary<string, string> ColumnFilterHash { get; } = new Dictionary<string, string>();
    }

    /// <summary>
    /// サイト設定データモデル
    /// </summary>
    public class SiteSetting
    {
        public string[] EditorColumns { get; set; }
        public DataTable Columns { get; set; }
    }
}

軽く解説

基本的な処理は以前の記事「独自にAPIを増やしてデスクトップアプリでプリザンターのすべてを見てみた!」を参照してください。

・メインの処理
APIから取得したデータから表示したいテーブルをSiteIdで絞って抽出し、データ構造を調整してListBoxへ表示しています。
ListBoxはItemTemplateを設定し、Itemそれぞれの中にDataGridを置いてカラムの設定を一覧表示しています。

// API 呼び出し テーブルの値を取得
var apiClient = new ApiClient();
var data = await apiClient.GetDataAsync(httpClient, apiKey, "MySites", requestData);

// 設定の取得
var settings =
    JsonConvert.DeserializeObject<SiteSetting>(
        data.AsEnumerable()
        .First(row =>
             row["SiteId"].ToString() == "設定を表示するサイトのID")["SiteSettings"]
            .ToString()
    );

// カラム名
var columnName = settings.EditorColumns;
// カラム設定
var columnSettings = settings.Columns;

// カラム名とカラム設定
var nameAndSetting = columnName.Select(name =>
{
    var dt = columnSettings.Clone();
    dt.Rows.Add(columnSettings.AsEnumerable()
        .FirstOrDefault(row => row["ColumnName"].ToString() == name)?.ItemArray
        ?? new object[0]);
    return new { Name = name, Setting = dt };
}).ToArray();

// 画面にセット
listBox.DataContext = nameAndSetting;

・POCO
前回はDataTableとしてデシリアライズしてそのまま使用しましたが、今回はSiteSettingsカラムの中身が複雑で少しデータモデルが必要になりました。

/// <summary>
/// サイト設定データモデル
/// </summary>
public class SiteSetting
{
    public string[] EditorColumns { get; set; }
    public DataTable Columns { get; set; }
}

APIは前回作成したIIS固有の技術で独自に増やしたものを使用しています。

今後の野望

今回も、ただデータを取得して手早く表示しただけですが、今後は

  • テーブルの設定をExcelのような見た目で一覧表示したい
  • エディタの設定をExcelのような見た目で一覧表示したい
  • アクセス制御の設定をExcelのような見た目で一覧表示したい
  • データの登録件数や状況のサマリーを一覧表示したい
  • プリザンターの使われ方を分析したい
  • データを一覧形式で登録・編集したい
  • テータを独自の画面で登録・編集したい
  • テーブルの設定を独自の画面で編集したい
  • 独自のフォーマットでデータのファイル出力・取込機能をしたい

といった夢をかなえるAPIを作って、皆様のお役に立てる製品を開発して行きます。個別のカスタマイズのご相談も歓迎です。

最後に

C#によるデスクトップアプリ開発IISが最も得意とする領域です。今後もプリザンターとデスクトップアプリの連携の研究を進めて行くつもりです。デスクトップアプリとの連携に関心のある方、よかったらブログ上部の「+読者になる」をクリックをお願いします!