【手抜きUI】C#でCUIな人が楽するためのGUIフレームワーク（萌えあり？）　その２ (2版）


[【手抜きUI】C#でCUIな人が楽するためのGUIフレームワーク（萌えあり？）　その１  (2版）](http://qiita.com/GDaigo/items/5b7d7cbf3429b271ccf5)からの続きです。その１でも書きましたが、普段VisualStudioやらない人が作った、生まれたてのソフトなんで生暖かい目で見守って下さると。。

こちらではアプリケーションを組むにあたり、必要となる情報をまとめます。

# 2版で何したか

諸々事情がありまして、DLL化しました。つか、初めからしろって話で・・申し訳ございません。。
それに合わせて、設定ファイルの場所などを変更しています。

# システム概要

CuiHelperはHTML系とCuiHelperLibプロジェクトで生成されるDLLから構成されます。んでもって、アプリケーションを開発する際は、そのDLLを用いてソフトを書き、CuiHelperContentsにあるHTML系のリソースを使って目的の機能を実現させます。

## CuiHelperContents(HTML関連）

CuiHelperは出力としてHTML5ベースのWebページを使っています。その関連ファイルをまとめました。以下構成です。

```
root
│  index.html 初期画面のhtml
│  
├─css
│      bootstrap.min.css    bootstrap関連のスタイルシート
│      index.css            index.htmlが使うスタイルシート 
│      report.css           CuiHelperが作成するHTMLのスタイルシート
│      
├─img
│      ここにアイコンとか、CuiHelperが使う画像を集めます。
│      
├─js
│      bootstrap.min.js     bootstarp
│      jquery-2.2.3.min.js  jQuery
│      
└─others
        report_after.txt       CuiHelperが作成するHTMLのテンプレ
        report_before.txt      CuiHelperが作成するHTMLのテンプレ
```

* CuiHelperはプログラムの結果からHTMLファイルを作成、それをWebBrowserクラスで表示させています。
* 具体的には「report_before.txt」 ＋「 CuiHelper（の中のアプリ）が指定したHTML」 +「 report_after.txt」 でHTMLを作成します。
* それをアプリが指定した名前のhtmlファイルにします。
* 基本スタイルを変更したい人は、以下のファイルおよびスタイルシートなどを変更する必要があります。
 *   index.html
 *   report_before.txt
 *    report_after.txt

デザインとかデフォルトの絵を変更とかが必要なければ、アプリケーションを書く人は特に修正をする必要はありません。必要に応じて画像を追加する事があるぐらいを想定しています。

## CuiHelperLib

クラス構成は以下の通りです。

|クラス名|カテゴリ|説明|
|:--|:--|:--|
|CuiHelperData.cs|コア|GUIパーツの双方向バインディング|
|CuiHelperAppManager.cs|コア|Windowsからのアプリ向けイベント処理|
|CuiHelperComboBoxData.cs|コア|ComboBox専用の双方向バインディング|
|CuiHelperFactory.cs|IF|Windowとの関連付け|
|CuiHelperAppInterface|IF|アプリケーションのIF|
|CuiHelperBot.cs|ツール|ImageBoxと出力用TextBox|
|CuiHelperBrowser.cs|ツール|HTML出力補助|
|CuiHelperJsonParser.cs|ツール|JSON解析系|
|CuiHelperProcess.cs|ツール|外部アプリ実行|
|CuiHelperShowFileDialog.cs|ツール|ファイル選択画面表示|
|DebugPrint.cs|ツール|デバッグ用|
|TextFile.cs|ツール|テキストファイルの読み書き|

### カテゴリについて

* __コア__はいわゆるフレームワーク的な部分になりますので、アプリケーションを作成する際に気にする必要はありません（ないといいな・・）。厳密に言うとCuiHelperComboBoxDataは多少絡むのですが、サンプルだけ見ればやれるようにしたつもりであります・・
* __IF__はCuiHelperがアプリケーションと繋げる部分を受け持ちます。CuiHelperFactory.csはWindow（普通に作るとMainWindow）クラスに関する部分を、CuiHelperAppInterfaceはアプリケーションとの口を、それぞれ担当します。
* __ツール__はCuiHelperが用意した入出力およびいくつかの処理で使う事が出来るクラス達です。アプリ側で適時使ってあげて下さい。

# アプリケーションを書くために（概要）

GitHubにある CuiHelperApp を参考にして戴けると助かります（ぶっちゃけしょっぱいコードなんで見た方が早いかも）。

ご自分のプロジェクトで以下の作業を行うことで、CuiHelperを利用したシステムを組むことが出来る…はず。

 *  CuiHelperLib.dllを参照します。
 *  setting.jsonを書いて、追加します。
 *  Windowsクラス（普通に作るとMainWindowクラス）でCuiHelperFactoryを生成、更にメソッドを呼び出す記述を書きます。
 *  CuiHelperAppInterfaceを継承したクラスを生成、そこにアプリケーションを書き込みます。

まずCuiHelperLibが提供するツールや、アプリとして書かないといけない処理について説明します。その後でアプリケーションの作り方をもう少し具体的に説明する構成で進めさせて下さい。

ちなみに一番簡単なのはGitHubに同梱したCuiHelperAppをベースにして自分のアプリ部分だけ修正する事だったりします。

# ツールについて

以下、ツールとして用意したオブジェクト／関数を紹介します。

### CuiHelperBotクラス Play関数

```csharp
void Play(string image, string serif)
```

画面左下のイメージファイルと右下のテキストをこれで表示してくれます。imageには画像ファイル名を、serifは表示するテキストの文字列をそれぞれ指定します。要はリアクションをこれで設定できます。こんな感じで書きます。

```csharp
 m_bot.Play("output.png", "レポートをまとめたので、上を見て下さいね。");
```

__imageですが、絶対パスを指定する必要はありません。__CuiHelperBotクラスはexeと同じフォルダにあるsetting.jsonに書かれたImagePathを利用します。例えばImagePathに「```c:\\CuiHelperContents\\img\\```」と記載されていれば、上記の例では「```c:\\CuiHelperContents\\img\\output.png```」が選択されます。

### CuiHelperBrowserクラス MakeHtmlWithTemplate関数

```csharp
public bool MakeHtmlWithTemplate(string file, string text)
```

fileは完成したHTMLファイルを保存するパス名を、textは生成したHTMLタグの文字列をそれぞれ指定して下さい。戻り値は成功(true)、失敗(false)です。

パスを指定する際は、CuiApplication.csのメンバ変数m_contentsPathにHTMLシステムのルートパスが入っていますので、これを使う事が出来ます。以下の感じです。

```csharp
    string url = m_contentsPath + "result.html";
    string html = "<p>結果</p>";
    bool success = m_browser.MakeHtmlWithTemplate(url, html);
```

処理結果は原則HTMLのタグで書いてもらう事を想定しています。本関数はそのタグを元にHTMLファイルを生成します。headタグなどはテンプレートをそのまま使いますので、処理結果の記載だけ加工したタグを書けばよいです。ぶっちゃけ面倒であれば処理結果の文字列をpreタグで囲む（以下）のでも良いです。

```csharp
string  html += "<pre>" + text + "</pre>";
```

その他、tableタグで表とかは定番かと思います。その場合tableタグだけ作って本関数に食わせて下さい。

### CuiHelperBrowserクラス SetURL関数

```csharp
public void SetURL(string url)
```

urlで指定したHTMLファイルを表示させます。
パスを指定する際は、CuiApplication.csのメンバ変数m_contentsPathにHTMLシステムのルートパスが入っていますので、これを使う事が出来ます。以下はその例。

```csharp
m_browser.SetURL(m_contentsPath + "result.html");
```

MakeHtmlWithTemplateで作ったHTMLでも良いですし、全て自作した独自のHTMLでも良いです。

ただしアクティブなページは現在想定していません。それするとWebBrowserが悲鳴を上げるかも。。

### CuiHelperBrowserクラス SetHTML関数

```csharp
public void SetHTML(string html)
```
SetURLと同じですが、こちらはHTMLを文字列で与えます。簡素なHTMLを表示する際に利用して下さい。

### CuiHelperJsonParserクラス（DynamicJson）

本アプリでは設定ファイルの解析で使っています。

実際にはDynamicJsonを使っています。アプリケーションでもDynamicJsonを使う際には、同ライブラリが提供するサービスを直ちに使う事が出来ます。

しかしながらｍDynamicJsonは文字通り、記載したJSONのアイテム名で直接やりとりできるものなので、本クラスのAPIを使うよりはDynamicJsonをそのまま使う方が良いと思います。使い方などは以下URLを参照ください。既に参照していますのでusing入れるだけで使えます。

https://dynamicjson.codeplex.com/

### CuiHelperProcessクラス Exec関数

こんなのクラスにせんでもええやろシリーズ第１弾。
__staticですので注意__　すみせんstaticおじさんで・・

```csharp
public static Process Exec(string name, string args, string work)
```

外部アプリを実行します。

nameは実行するファイル名をフルパスで指定して下さい。exeの他関連付けが終わっているファイルでも可能です（pdfとか）。
argsは引数が必要なら与えて下さい（エディタで開けるファイル名とかが該当します）。
workはワークスペースディレクトリが必要な際に指定して下さい。

argsやworkは不要ならnullで構いません。

### CuiHelperShowFileDialogクラス Show関数

こんなのクラスにせんでもええやろシリーズ第２弾。
__staticですので注意__　すみせんstaticおじさんで・・

```csharp
public static string Show(string title)
```

ファイル選択ダイアログを出してユーザにファイルを選択させ、選択した結果のパスを戻します。
tittleはダイアログのタイトルに出るメッセージです（例えば「画像を選んでね」とか）。

途中で選択がキャンセルされた際には、nullが戻ります。

### TextFileクラス  Read関数

こんなのクラスにせんでもええやろシリーズ第３弾。
__staticですので注意__　すみせんstaticおじさんで・・

```csharp
public static string Read(string path)
```

pathで指定したテキストファイルを読み込んでその文字列を戻します。
失敗した場合はnullが戻ります。

いや、fopenとかじゃないので、面倒だったので・・

### TextFileクラス  Write関数

__staticですので注意__　すみせんstaticおじさんで・

```csharp
public static bool Write(string path, bool append, string text)
```

textの内容をpathで指定されたファイルに書き込みます。appendは既にファイルがある場合の対応で、trueなら上書き、falseなら既存の内容は消します。

戻り値は成功でtrue,失敗でfalseです。

### DebugPrintクラス  output関数

__staticですので注意__　すみせんstaticおじさんで・・

```csharp
public static void output(string module, string text)
```

VisualStudioでのデバッグの際に使えます。以下のフォーマットで出力ウィンドウにメッセージを出します。

```js
時刻 + module + text で出します。以下はその例
2016/06/26 16:05:11:APP:enter constructor
```
__本APIを使う際は、Debugでビルドしたdllを使って下さい。__


# 処理結果をどう出力するか。

CuiHelperを使えば、.NETとかXAML系のリソースとかあまり考えずに出力動作を実装できます。

本節では、処理完了後、その結果を表示させるコードの基本的な書き方を説明します。以下の例はCuiApplicationクラス内に記述する前提です。

### 画像とコメント

画面下側のImageエリアに画像を出し、TextBoxにコメントを出力するには、CuiHelperBotクラス Play関数を利用して以下のように書きます。

```csharp
string path = "output.png"; // このようにファイル名で指定します。
string serif = "結果だよ。";
m_bot.Play(path, serif);
```

__pathですが、絶対パスを指定する必要はありません。__CuiHelperはexeと同じフォルダにあるsetting.jsonに書かれたImagePathを利用します。例えばImagePathに「```c:\\CuiHelperContents\\img\\```」と記載されていれば、上記の例では「```c:\\CuiHelperContents\\img\\output.png```」が選択されます。

### ブラウザ画面へのHTML出力

上記にあるCuiHelperBrowserクラスの関数を使って出力を記述出来ます。テンプレを使うのであれば、head系とか細かい事は考えなくて良いです。ファイル名はindex.html以外でまぁ適当にお願いします。

MakeHtmlWithTemplate関数で指定したタグからHTMLファイルを作成し、それをSetURLで指定する事で表示が出来ます。

Bootstrapを使うことも可能です。

### CuiHelperのサービスを利用して表示さす例

```csharp
{
    string url = m_contentsPath + "test.html";
    string html = "<ui class=\"list - group\">";
    html += "<li class=\"list-group-item\">項目１</li>";
    html += "<li class=\"list-group-item\">項目２</li>";
    html += "</ui>";
    if (m_browser.MakeHtmlWithTemplate(url, html) == true)
    {
        m_browser.SetURL(url);
    }
    m_bot.Play("pronama_execute.png", "testを実行してみたよ");
}
```

このように表示されます（pronama_execute.jpgは手を挙げたポーズの画像です）
![cui_sample1.png](https://qiita-image-store.s3.amazonaws.com/0/129334/21a3e5cf-e5c5-8f7b-5a9d-f474f36d2120.png)
___図１　表示例___

htmlファイルを作成するので、後からでもブラウザで確認が可能です。

# アプリケーションとして実装が必要な関数

必要な関数はCuiHelperAppInterfaceにまとめています。以下です。

```csharp
namespace CuiHelperLib
{
    public interface CuiHelperAppInterface
    {
        //以下の関数処理を実装する事で、アプリケーションが実現出来ます。
        //実際は CuiHelperApplication.cs を見てもらってもよろしいでしょうか・・
        int PrepareDragAndDrop(string[] files, string text);
        void DragAndDrop(string[] files, string text);
        int PrepareTextBoxEvent(string text);
        void TextBoxEvent(string text);
        int PrepareButtonEvent(string command, string text);
        void ButtonEvent(string command, string text);
        CuiHelperComboBoxData[] GetComboBoxData();
        void Init(CuiHelperBot bot, CuiHelperBrowser browser, string contentsPath);
    }
}
```
アプリケーション開発者はこれを継承して実装する必要があります。以下、各関数の説明をします。

### Init

```csharp
void Init(CuiHelperBot bot, CuiHelperBrowser browser, string contentsPath);
```

初期化時に呼び出されます。bot、browserは上記で紹介したツールが入っているクラスです。通常はメンバ変数に設定しておいて、処理する際に使うことになるかと思います。contentsPathはCuiHelperContentsフォルダへのパスが入っていますので、必要ならこれもメンバ変数などに記録して下さい。

アプリはここで以下のリソース設定を行います。

1. Imageに出すイメージファイルの指定
2. TextBoxに出す初期メッセージ（string）の指定
3. Comboboxに登録するデータの指定

1と2はbot.Playを呼び出して設定する感じです。上の項目も参考にしてみて下さい。

3のComboboxに登録するデータですが、実際にはCuiHelperComboBoxDataクラスの配列データです。詳細はCuiHelperComboBoxData.csなどを見て戴く方が良いのですが、使うだけなら割と簡単です。以下、実際の定義例としてGitHubに置いたサンプルからの引用です。

```csharp
private const string COMMAND_GO_HOME = "GO_HOME";
private const string COMMAND_CALC = "CALC";
private const string COMMAND_IMAGE = "IMAGE";

private void MakeComboBoxData()
{
    //CuiHelperComboBoxData[]の生成
    m_ComboBoxData = new[] {
        new CuiHelperComboBoxData { Name = "Goto Home", Commnad = COMMAND_GO_HOME },
        new CuiHelperComboBoxData { Name = "Calc", Commnad = COMMAND_CALC },
        new CuiHelperComboBoxData { Name = "View jpg/png file", Commnad = COMMAND_IMAGE },
    };
}
```

要は必要な項目分、CuiHelperComboBoxDataをnewして上記のようにNameとCommandの文字列を定義しておけば良いです。で、InitからMakeComboBoxDataを呼び出すようにします。この配列はクラスのメンバ変数に格納しておく事を想定しています。

NameはComboBoxに表示される文字列です。
Commandはイベント時に通知されるメッセージです。つまり、ユーザが項目を選んだ際に「ユーザはこれを選んだよ」の「これ」に相当する文字列です。そして後で説明するPrepareButtonEvent、ButtonEvent辺りでこれを使います。

他に実装するアプリとしての必要な初期化があれば行う感じです。

### GetComboBoxData

```csharp
CuiHelperComboBoxData[] GetComboBoxData();
```

これも初期化時、Initの後に呼び出されます。Initで生成したCuiHelperComboBoxData配列データを戻してあげてください。上記の例ならm_ComboBoxDataです。

### PrepareComboBoxEvent

```csharp
int PrepareComboBoxEvent(string command, string text);
```

ユーザがComboBoxから項目を選んで、GOをクリックした際に呼び出されます。但しこれは事前通告みたいなイメージです。ここに実処理は実装しないで下さい。

commandには選択した項目に該当するCuiHelperComboBoxDataのcommandデータが戻りますので、どの処理が選択されたかを判定する際に利用して下さい。

textは入力用のTextBoxの文字列データが入ります。パラメータを必要とする際には利用してみて下さい。

ここには事前処理を記述します。以下の例を想定しています。

* 前処理が必要な場合、その処理
* リアクションの設定（「CuiHelperのサービスを利用して表示さす例」参考）

戻り値はmsecの時間となります。ここで設定された時間経過後、ButtonEvent関数が呼び出される仕組みとなります。0にすれば直ちに呼び出します。

### ComboBoxEvent

```csharp
int ComboBoxEvent(string command, string text);
```

ユーザがComboBoxから項目を選んで、GOをクリックした際の実処理です。PrepareButtonEventの後に呼び出されます。

引数の意味はPrepareButtonEvent関数と同じです。commandを見て、何を選択したのか判断する処理を記述して下さい。

判断が出来たら処理の実体を記入し、処理が終わったら「CuiHelperのサービスを利用して表示さす例」で書いたような出力処理を記述します。

### PrepareTextBoxEvent

```csharp
int PrepareTextBoxEvent(string text);
```

ユーザがテキスト入力を行いENTERキーを押した際に呼び出されます。但しこれは事前通告みたいなイメージです。ここに実処理は実装しないで下さい。

textは入力用のTextBoxの文字列データが入ります

ここには事前処理を記述します。以下の例を想定しています。

* 前処理が必要な場合、その処理
* リアクションの設定（「CuiHelperのサービスを利用して表示さす例」参考）

戻り値はmsecの時間となります。ここで設定された時間経過後、ButtonEvent関数が呼び出される仕組みとなります。0にすれば直ちに呼び出します。

### TextBoxEvent

```csharp
void TextBoxEvent(string text);
```

ユーザがテキスト入力を行いENTERキーを押した際に呼び出されます。
PrepareTextBoxEventの後に呼び出されます。

引数の意味はPrepareTextBoxEvent関数と同じです。入力文字列がtextに入ります。

ここに処理の実体を記入し、処理が終わったら「CuiHelperのサービスを利用して表示さす例」で書いたような出力処理を記述します。

### PrepareDragAndDrop

```csharp
int PrepareDragAndDrop(string[] files, string text);
```

ユーザが処理したいファイルをドラッグ＆ドロップした際に呼び出されます。但しこれは事前通告みたいなイメージです。ここに実処理は実装しないで下さい。

filesには選択されたファイルのパスが配列で格納されています（複数選択にも対応しています）。textは入力用のTextBoxの文字列データが入ります

ここには事前処理を記述します。以下の例を想定しています。

* 前処理が必要な場合、その処理
* リアクションの設定（「CuiHelperのサービスを利用して表示さす例」参考）

戻り値はmsecの時間となります。ここで設定された時間経過後、ButtonEvent関数が呼び出される仕組みとなります。0にすれば直ちに呼び出します。

### DragAndDrop

```csharp
 void DragAndDrop(string[] files, string text);
```

ユーザがテキスト入力を行いENTERキーを押した際に呼び出されます。
PrepareDragAndDropの後に呼び出されます。

引数の意味はPrepareDragAndDrop関数と同じです。filesに指定されたファイルのパスが入っています。

ここに処理の実体を記入し、処理が終わったら「CuiHelperのサービスを利用して表示さす例」で書いたような出力処理を記述します。

# アプリケーションを書くために（もう少しだけ具体的に）

### 下ごしらえ

まずは以下の作業をアプリケーションをビルドするプロジェクトで行って下さい。

 * CuiHelper.dllとDynamicJson.dll、setting.jsonを用意して下さい。GitHubから落としたCuiHelperApp\CuiHelperApp\Resources にあったりします。
 * setting.json を[その１で説明しましたように](http://qiita.com/GDaigo/items/5b7d7cbf3429b271ccf5#%E3%83%93%E3%83%AB%E3%83%89)書きかえて下さい。　
 * CuiHelper.dllとDynamicJson.dllを自分にプロジェクトに加えます。
 　VisualStudioのメニュー「プロジェクト」→「(プロジェクト名)のプロパティ」→「リソース」で上にある「リソースの追加」→「既存のファイルの追加」でやると「Resources」フォルダに追加されます。
 * setting.jsonも同様に自分にプロジェクトに加えて下さい。
 * ソリューションエクスプローラから「Resources」→setting.jsonを選んで右クリック。プロパティで「出力ディレクトリにコピー」を「新しい場合はコピーする」を選択して下さい。
 * 「プロジェクト」→「参照の追加」→画面右下の”参照”とクリック。CuiHelper.dllを選択して取り入れます。
 * 画面用のWebBrowser、入力用のTextBox、出力用のTextBox、画像用のImage、処理選択用のComboBoxをxamlで配置し、x:Nameでメンバ変数として持たせておいて下さい。
 * Buttonなどを用意して下さい（ComboBoxで選択したコマンドを実行させるためです）
 *  xamlで出力用のTextBoxを記述する箇所で  ```Text="{Binding CommentText}"```  とバインドしておいて下さい。
 *  xamlで画像用のImageを記述する箇所で ```Source="{Binding BotImageData}"``` とバインドしておいて下さい。


下ごしらえはこれぐらいです。双方向バインディングはCuiHelperLibがやる前提です。それだと困る場合は別途対応が必要になります（後述しますがこの場合はちょっと厄介）

HTML系のリソース（html, css, 画像など）で追加あるようでしたら、CuiHelperContents内を修正・追加してあげて下さい。

また、応答時の女の子の画像が別にあったりとか、キャラを変更したい際にはそれらの画像を用意して戴き、setting.jsonのImagePathで定義した場所に入れて下さい。

### Windowクラス（MainWindowクラス？）の実装

CuiHelperFactoryクラスを利用して、コードを記述します。

具体的にはGitHubに同梱したCuiHelperAppのMainWindow.xaml.csを見てもらった方が早いかと思います。同ソースのコメントを見ながら、同じようにインプリメントしてみて下さい。

### CuiHelperAppInterface継承クラスの実装

CuiHelperAppInterfaceを継承したクラスを生成し、その中に実際の処理を記述します。

具体的にはお手数ですがGitHubに同梱したCuiHelperAppのCuiApplication.csとSample.csを見てもらえますでしょうか（手抜きでスミマセン）。

サンプルではCuiHelperApplicationとSampleに分割しました。CuiHelperApplicationでは主にDLLと実際のアプリケーションとをどう繋げるかという観点で実装しました。そして実際の処理をSampleにて実装しています。

### 双方向バインディングの問題

CuiHelperでは基本的にGUI部分をDLLで行う前提ですので、双方向バインディングをDLL内部で行い、値の反映もDLL内部で行います。

それ以外のケースは正直考えていない状態ですごめなさい。その場合は以下のように対策する事は可能です。

 * 変数を追加する場合は、CuiHelperLib側のCuiHelperDataを修正して追加します。
 * アプリ側から、CuiHelperFactoryクラスのGetBindingDataClass関数を呼び出すことで、そのクラスを取得できます。
 * 値を変更する場合はその取得したクラスを使って設定します。

ComboBoxはアプリ側で元々、設定・拡張が可能ですので、それでお願いしたい所です。

# ライセンスなど

以下使わせて戴きました。素晴らしいソフトウェアを提供して下さり、ありがとうございます。

 * 本プロダクトは[MITライセンス](https://opensource.org/licenses/MIT)とします。詳細はGitHubを。
 * [DynamicJson](https://dynamicjson.codeplex.com/)を利用しています。ライセンスは[Microsoft Public License](https://dynamicjson.codeplex.com/license)です。
 * bootstrapを利用しています。[MITライセンス](https://github.com/twbs/bootstrap/blob/master/LICENSE)です。
 * jQueryを利用しています。[MITライセンス](https://jquery.org/license/)です。
 * プロ生ちゃんの画像は[「プロ生ちゃん利用ガイドライン」](http://pronama.azurewebsites.net/pronama/guideline/)に従った利用が必要ですので、ご注意ください。
 * アイコンは[このサイトのbird-green](http://www.veryicon.com/icons/system/trainee/bird-green.html)を採用しています。商用利用に制限がありますので、ご注意下さい。
 * コードではありませんが、Web側のフォントは[Google Fonts](https://www.google.com/fonts#AboutPlace:about)を使っています。

以上です。