LoginSignup
5
7

More than 5 years have passed since last update.

C# WPFで作るJavaScript REPL

Last updated at Posted at 2016-02-02

背景

ChakraCoreという、C#から利用できるJavaScriptエンジンがあります。
WPFでユーザーインターフェースを作って、REPLにしてみましょう。

完成イメージ

JavaScriptを入力して実行(RUN)ボタンを押すと結果を表示します。
out.gif
分割代入が動くのが、(今の所)ChakraCoreならではです。

手順

VisualStudio Community 2015 Update1で新しいWPFプロジェクトを作ります。

ChakraCoreのdllを作る

ChakraCoreをビルドするを参考にしてビルドしてください。
ChakraCoreをC#から呼び出すと同様にプロジェクトに追加します。

NugetでReactivePropertyをインストールする

viewとviewModelをバインドするためにReactivePropertyを使います。
ReactivePropertyを使う理由はINotifyPropertyChanged実装のありえない面倒くささと、ReactivePropertyの信じられない素晴らしさを見てください。

MainWindowを作成する

コンポーネントを適当に配置します。

<Window x:Class="REPL.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:REPL"
        mc:Ignorable="d"
        Title="ChakraCore REPL"
        Height="450"
        Width="600" Closing="DisposeChakraRuntime">

    <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
        <TextBox
            Height="250" 
            Width="600"
            AcceptsReturn="True"
            TextWrapping="Wrap"
            Text="{Binding Script.Value}"
            VerticalScrollBarVisibility="Auto"
            FontSize="20"
            />
        <Button Click="Button_Click">実行(RUN)</Button>
        <Button Click="ResetContext">初期化(Reset)</Button>
        <TextBlock
            TextWrapping="Wrap"
            Text="{Binding Result.Value}"
            />
    </StackPanel>
</Window>

ViewModelを作る

JavaScript文字列と結果文字列持つビューモデルを作ります。

public class ViewModel
{
    public ReactiveProperty<string> Script { get; } = new ReactiveProperty<string>("(()=>{return \'Hello world!\';})()");
    public ReactiveProperty<string> Result { get; } = new ReactiveProperty<string>();
}

初期値に"(()=>{return \'Hello world!\';})()を入れます。
公式サンプルの真似です。

JavaScriptの実行部

Hosting

ChakraCoreをC#から呼び出すと同様に公式サンプルHostingディレクトリをコピーします。

実行エンジンの初期化

JavaScriptRuntime.Createメソッドでランタイムを作ります。
ランタイムのCreateContextメソッドで実行コンテキストを作ります。

private JavaScriptRuntime runtime;
private ViewModel vm;

public MainWindow()
{
    InitializeComponent();

    vm = new ViewModel();
    DataContext = vm;

    InitChakraRuntime();
    Run(runtime, vm);
}

private void InitChakraRuntime()
{
    runtime = JavaScriptRuntime.Create();
    JavaScriptContext.Current = runtime.CreateContext(); 
}

実行

事前に設定したJavaScriptContextRunScriptメソッドに文字列を与えます。
ConvertToStringメソッドとToStringメソッドで結果をC#の文字列に変換します。

private static void Run(JavaScriptRuntime runtime, ViewModel vm)
{
    try
    {
        vm.Result.Value = JavaScriptContext.RunScript(vm.Script.Value)
            .ConvertToString()
            .ToString();
    }
    catch (JavaScriptScriptException e)
    {
        vm.Result.Value = e.Error
            .ConvertToString()
            .ToString();
    }
}

イベントハンドラーを作る

ボタンのイベントハンドラーを設定します。

private void Button_Click(object sender, RoutedEventArgs e)
{
    Run(runtime, vm);
}

その他の雑用

コンテキストを初期化し直すボタンをつけます。
グローバル変数の定義を消すために使います。

private void ResetContext(object sender, RoutedEventArgs e)
{
    JavaScriptContext.Current = runtime.CreateContext();
}

Windowを閉じる時にランタイムを消します。

private void DisposeChakraRuntime(object sender, System.ComponentModel.CancelEventArgs e)
{
    // Dispose runtime
    JavaScriptContext.Current = JavaScriptContext.Invalid;
    runtime.Dispose();
}

ソースコード

githubにあります。

感想

公式サンプルのHostingのJavaScriptRuntime.csがC#っぽいAPIを提供しています。
これを使うと公式サンプルよりスマートに書けて良い感じです。

5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7