酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

Windows Phoneでmarkdownで書いたテキストをhtmlに変換して表示する

この記事は、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 ピボット アプリ」を選択します。

f:id:ch3cooh393:20131204101701p:plain

名前はそのまんま「MarkdownEditor」にしました。

Markdown4winrtプロジェクトの参照

アプリからmarkdownライブラリを使いたいので、MarkdownEditorプロジェクトからMarkdown4winrtプロジェクトを参照します。

先ほどダウンロードしてきたZIPファイルを任意のフォルダへ解凍しておいてくださいね。

まずは、Markdown4winrtプロジェクトをソリューションに追加します。

ソリューションエクスプローラーでソリューション 'MarkdownEditor'を右クリックします。コンテキストメニューから追加既存のプロジェクトを選択します。

先ほどダウンロードしたMarkdownプロジェクトを追加します。

f:id:ch3cooh393:20131204101723p:plain

次にMarkdownEditorプロジェクトからMarkdownプロジェクトを参照します。

MarkdownEditorプロジェクトの参照設定を右クリックします。参照の追加を選択すると参照マネージャーダイアログが表示されます。

f:id:ch3cooh393:20131204101733p:plain

これでMarkdownEditorプロジェクト側からMarkdown4winrtの機能が使えるようになりました。

画面を作ろう

画面を作りましょう!とは言っても、ベースのテンプレートにピボットアプリを選択しているので、このレベルの画面でしたらすぐに作ることができます。

f:id:ch3cooh393:20131204230220p:plain

実質やったことと言えば、以下の通りです。

  • アプリケーション名を変更
  • PivotItemのHeaderを変更
  • PivotItemに元々入っている中身(ListViewとか)を削除
  • PivotItemにTextBoxとWebBrowserを追加

もうすでにXAMLを用意しておきました。上図の画面はこのようなXAMLで構成されています。

<phone:PhoneApplicationPage
    x:Class="MarkdownEditor.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DataContext="{d:DesignData SampleData/MainViewModelSampleData.xaml}"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait"  Orientation="Portrait"
    shell:SystemTray.IsVisible="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">

        <phone:Pivot x:Name="pivot" Title="MARKDOWN EDITOR" 
                SelectionChanged="pivot_SelectionChanged">

            <!-- 編集領域 -->
            <phone:PivotItem Header="edit">
                <TextBox x:Name="editorArea" AcceptsReturn="True" />
            </phone:PivotItem>

            <!-- プレビュー領域 -->
            <phone:PivotItem Header="preview">
                <phone:WebBrowser x:Name="previewArea" />
            </phone:PivotItem>

        </phone:Pivot>

        <Image Source="/Assets/AlignmentGrid.png" VerticalAlignment="Top" 
            Height="800" Width="480" Margin="0,-32,0,0" Grid.Row="0"
            IsHitTestVisible="False" />
    </Grid>

</phone:PhoneApplicationPage>

これで画面の実装が完了しました。

ページ遷移時に保存してから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);

            // markdownからhtmlに変換してプレビューページに表示する
            var markdown = new MarkdownSharp.Markdown();
            var transHtml = markdown.Transform(editorArea.Text);
            previewArea.NavigateToString(transHtml);
        }

これでmarkdownをHTMLに変換して表示させるWindows Phoneアプリができました。

こんな感じになりました

実際にWindows Phoneエミュレータで動かしてみましょう。エディタページで下記の文章を入力しました。

* 近い
  * ch3cooh
* 遠い
  * 🐱

ピボットをフリックして、プレビューページで見た時にどのようになっているか確認しましょう。

f:id:ch3cooh393:20131204230233p:plain

入力した通り綺麗にプレビューで表示されているのが確認できます。

おわり。