この記事は、Windows Phone Advent Calendar 2013の8日目です。
markdownって知っていますか?
普段のメモもはてダ記法で書くくらい傾倒していた私ですが、markdownに触れてからというものこのブログ「酢ろぐ!」やWordPressで運用している「SOFTBUILD」でmarkdownで書く癖がついてしまいました。
ネタがなくて困っていたところ、たなかさんが、「はてなブログに予約投稿するクライアントを作ろうかなーmarkdownライブラリがあったらエディタ作っちゃおうかなー」と言っていましたので、勢いでmarkdownをhtmlに変換するライブラリをWindowsストアアプリでも使えるように移植してしまいました。
今、見返したら全然そんなこと言ってなかった……。
WindowsストアアプリとWindows Phone 8では同じコードがほぼそのまま使うことができるため、移植した「Markdown4winrt」ではついでにWindows Phone 8対応もおこないました。Windows Phone 8対応と言ってもユニットテストのテキストファイルを読み込む処理を書き換えた位です。
と、ここまでがWindows Phone Advent Calendarでmarkdownについて書こうと思った経緯になります。そして本題。
markdownライブラリだけではなくて、フロント側も僕が作ることになってました(汗
そんな高機能なものは作れないので、markdownを入力したらその結果を表示させるような簡単なWindows Phoneアプリを作ってみましょう。
アプリの仕様を考えてみよう
面倒くさいので保存機能は一切なしという漢らしい仕様でいきましょう。
ただ漢であっても電話着信や瞬断で記入中のテキストが消えてしまうのは、きっと悲しいと思うので、エディタページとプレビューページとの切り替え時だけ保存してあげるようにしましょう。
markdownを解釈する機能はどうするか
これは冒頭でも紹介した通り、僕があらかじめ用意しています。
GitHub/CH3COOH/Markdown4winrtからダウンロードしてください。右側メニューに「Download ZIP」と書かれたボタンがあるので、クリックすると最新のソースコードを取得することができるはずです。
このMarkdown4winrtのfork元はMarkdownSharpです。このライブラリをWinRT/WP8向けで動かさられるように移植しました。テストコードも一通り移植してチェックしているので機能的な差異はないと思います。
markdownエディタを実装しよう
さて、早速アプリを作っていきます。
ソリューションの新規作成
Visual Studio 2013を起動します。新規プロジェクトの作成を選択して、テンプレートから「Windows Phone ピボット アプリ」を選択します。
名前はそのまんま「MarkdownEditor」にしました。
Markdown4winrtプロジェクトの参照
アプリからmarkdownライブラリを使いたいので、MarkdownEditorプロジェクトからMarkdown4winrtプロジェクトを参照します。
先ほどダウンロードしてきたZIPファイルを任意のフォルダへ解凍しておいてくださいね。
まずは、Markdown4winrtプロジェクトをソリューションに追加します。
ソリューションエクスプローラーでソリューション 'MarkdownEditor'
を右クリックします。コンテキストメニューから追加
→既存のプロジェクト
を選択します。
先ほどダウンロードしたMarkdownプロジェクトを追加します。
次にMarkdownEditorプロジェクトからMarkdownプロジェクトを参照します。
MarkdownEditorプロジェクトの参照設定
を右クリックします。参照の追加
を選択すると参照マネージャーダイアログが表示されます。
これでMarkdownEditorプロジェクト側からMarkdown4winrtの機能が使えるようになりました。
画面を作ろう
画面を作りましょう!とは言っても、ベースのテンプレートにピボットアプリを選択しているので、このレベルの画面でしたらすぐに作ることができます。
実質やったことと言えば、以下の通りです。
- アプリケーション名を変更
- PivotItemのHeaderを変更
- PivotItemに元々入っている中身(ListViewとか)を削除
- PivotItemにTextBoxとWebBrowserを追加
もうすでにXAMLを用意しておきました。上図の画面はこのようなXAMLで構成されています。
<phonePhoneApplicationPage
xClass="MarkdownEditor.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlnsx="http://schemas.microsoft.com/winfx/2006/xaml"
xmlnsphone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlnsshell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlnsd="http://schemas.microsoft.com/expression/blend/2008"
xmlnsmc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mcIgnorable="d"
dDataContext="{d:DesignData SampleData/MainViewModelSampleData.xaml}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shellSystemTrayIsVisible="True">
<Grid xName="LayoutRoot" Background="Transparent">
<phonePivot xName="pivot" Title="MARKDOWN EDITOR"
SelectionChanged="pivot_SelectionChanged">
<phonePivotItem Header="edit">
<TextBox xName="editorArea" AcceptsReturn="True" />
</phonePivotItem>
<phonePivotItem Header="preview">
<phoneWebBrowser xName="previewArea" />
</phonePivotItem>
</phonePivot>
<Image Source="/Assets/AlignmentGrid.png" VerticalAlignment="Top"
Height="800" Width="480" Margin="0,-32,0,0" GridRow="0"
IsHitTestVisible="False" />
</Grid>
</phonePhoneApplicationPage>
これで画面の実装が完了しました。
ページ遷移時に保存してからmarkdownへの変換
Pivotはフリックでページを左右する際に、SelectionChangedイベント
が発生します。MainPageではそのSelectionChangedイベントハンドラ内で、ユーザーが記述したテキストの保存とmarkdownへの変更をおこないます。
MainPage.xaml.csは、下記のようになっています。ここから手を入れていきましょう。
using Microsoft.Phone.Controls;
using System.IO;
using System.IO.IsolatedStorage;
using System.Windows.Controls;
namespace MarkdownEditor
{
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
}
private async void pivot_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
var pivot = sender as Pivot;
if (pivot == null)
{
return;
}
}
}
}
まずは、テキストの保存をおこないましょう。Windows Phoneアプリでテキストを保存するには分離ストレージ(IsolatedStorage)を使います。
SaveTextAsyncメソッドでテキストを保存する処理を実装します。
SaveTextAsyncメソッドでは、IsolatedStorageFileクラスのGetUserStoreForApplicationメソッドでストレージの管理オブジェクトを取得します。あとはOpenFileメソッドでファイルを作成しテキスト情報を保存しています。
ページの切り替わりイベントハンドラのpivot_SelectionChangedメソッド
にて、入力されているテキストを保存する処理の実装ができました。
private async Task SaveTextAsync(string text)
{
var store = IsolatedStorageFile.GetUserStoreForApplication();
using (var strm = store.OpenFile("log.txt", FileMode.OpenOrCreate))
using (var writer = new StreamWriter(strm))
{
await writer.WriteAsync(text);
}
}
private async void pivot_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
var pivot = sender as Pivot;
if (pivot == null)
{
return;
}
await SaveTextAsync(editorArea.Text);
}
次は、markdownを変換してみましょう。こちらの方が簡単かもしれません。
MarkdownSharp.Markdownクラスのインスタンスmarkdown
を生成します。MarkdownクラスのTransformメソッドにユーザーが入力したテキストを渡すと、markdownをHTMLに変換したテキストを得ることができます。
HTMLを表示させるにはWebBrowserコントロールのNavigateToStringメソッドを使います。
private async void pivot_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
var pivot = sender as Pivot;
if (pivot == null)
{
return;
}
await SaveTextAsync(editorArea.Text);
var markdown = new MarkdownSharp.Markdown();
var transHtml = markdown.Transform(editorArea.Text);
previewArea.NavigateToString(transHtml);
}
これでmarkdownをHTMLに変換して表示させるWindows Phoneアプリができました。
こんな感じになりました
実際にWindows Phoneエミュレータで動かしてみましょう。エディタページで下記の文章を入力しました。
* 近い
* ch3cooh
* 遠い
* 🐱
ピボットをフリックして、プレビューページで見た時にどのようになっているか確認しましょう。
入力した通り綺麗にプレビューで表示されているのが確認できます。
おわり。