[WPF][XAML]InkCanvasにTextBoxを追加してみる

# WPFでInkCanvasにTextBoxを追加してみる

## 開発環境
- Visual Studio 2017 (C#)
- Visual Studioの拡張機能の「Prism Template Pack」
  - Prism.Core 6.3.0
  - Prism.Unity 6.3.0
  - Prism.Wpf 6.3.0
  - CommonServiceLocator 1.3.0
  - Unity 4.0.1
- MahApps.Metro 1.5.0

## 初めに
前回のプロジェクトを使用するのでPrismを使っていますが、ViewModel側で記述する必要はない処理ですが、他のコマンドと合わせるためにViewModel側に記述しています。
※ 以前に作成した「WPFでInkCanvasを使ってみる」で作成したプロジェクトを使用しますので、途中までは、そちらを確認してください。

## 参考
HIRO'sさんのBlog
HIRO's.NET http://blog.hiros-dot.net/

人体図画像をお借りしました。
フリーイラスト http://www.sharots.com/ai.html

## 説明省略部分

「Prism Template Pack」のインストール
「MahApps」のインストール
「Prism Template Pack」のプロジェクト作成
「InkCanvas」の各種コマンド操作の実装
※「Prism Template Pack」のインストールは、以前の記事を参考にしてください。
[ PrismとUnityを使うWPFプロジェクトテンプレートを使ってみる](http://qiita.com/HAGITAKO/items/adedbb6c70d2763543f2)
※「InkCanvas」の各種コマンド操作の実装は、以前の記事を参考にしてください。
[WPFでInkCanvasを使ってみる](https://qiita.com/HAGITAKO/items/754039827678649ede82)


### 「MainUc.xaml」にコントロールを追加


```XML:MainUc.xaml
<Button Content="テキスト追加" Command="{Binding AddTextCommand}" CommandParameter="{Binding ElementName=inkCanvas}"/>
```

今回もViewModel側でInkCanvasを使用するため、「CommandParameter」にInkCanvas名を入れいています。

### 「MainUcViewModel.cs」にDelegateCommandを追加


```csharp:MainUcViewModel.cs
        /// <summary>
        /// テキストボタンコマンド
        /// </summary>
        private DelegateCommand<InkCanvas> addTextCommand;
        public DelegateCommand<InkCanvas> AddTextCommand =>
            addTextCommand ?? (addTextCommand = new DelegateCommand<InkCanvas>(AddTextCommandExectute));
```

#### ※DelegateCommandについて補足
※「Prism Template Pack」をVisualStudioに拡張済みであれば、「cmdg」と入力すれば、簡単に上記のDelegateCommandが作成できます。

```csharp:MainUcViewModel.cs(cmdg入力後Tabキーを2回押す前)
cmdg
```

```csharp:MainUcViewModel.cs(cmdg入力後Tabキーを2回押した後)
        private DelegateCommand<string> fieldNameCommand;
        public DelegateCommand<string> CommandNameCommand =>
            fieldNameCommand ?? (fieldNameCommand = new DelegateCommand<string>(CommandName, CanCommandName));
```

このように簡単にパラメータ付のDelegateCommandが作成されるので、fieldNameとCommandNameを変更するだけ済みます。

### 「MainUcViewModel.cs」にTextBoxの追加処理を追加

```csharp:MainUcViewModel.cs
        /// <summary>
        /// TextBoxの追加処理
        /// </summary>
        /// <param name="inkCanvas"></param>
        private void AddTextCommandExectute(InkCanvas inkCanvas)
        {

            InkEditingMode = InkCanvasEditingMode.None;

            // TextBoxの追加
            TextBox newTextBox = new TextBox();
            newTextBox.Text = "入力してください";
            newTextBox.FontSize = PenSize;
            newTextBox.Foreground = new SolidColorBrush(Colors.Green);
            newTextBox.Background = Brushes.Transparent;
            newTextBox.BorderBrush = Brushes.Transparent;
            newTextBox.SelectAll();
            inkCanvas.Children.Add(newTextBox);
            // TextBoxの表示位置
            InkCanvas.SetTop(newTextBox, 5);
            InkCanvas.SetLeft(newTextBox, 5);

            // フォーカスの設定
            FocusManager.SetFocusedElement(FocusManager.GetFocusScope(newTextBox), newTextBox);
            // IMEの変更
            InputMethod.Current.ImeState = InputMethodState.On;

        }
```


## デバッグ実行
デバッグを実行すると以下のようになります。
![1512705436iFZVXm1fsil6xJi1512705432.gif](https://qiita-image-store.s3.amazonaws.com/0/90597/65fdc12f-afe4-421d-fc6d-f65a55b4a5af.gif)
といった感じで、TextBoxの追加と選択が可能になりました。
なお、TextBlockやRichTextでも可能です。

## 完成かと思いきや。。。。
InkCanvasの子要素でTextBoxを追加して、表示できるところまで確認できましたが、致命的な問題が発生しました。
前回の記事で作成したStrokeを画像ファイルやisfファイルへの保存する方法のままですと、追加したTextBoxが認識されないため、保存ができません。
理由としては、TextBoxをStrokeCollectionに変換していないからです。
そもそもStrokeCollectionへの変換方法がわからなかったので、どうするべきか模索中です。
とりあえず、今回は画面に表示するところまでとしています。