Console.WriteLine()やConsole.ReadLine()で入出力を行うコンソールアプリケーションをSilverlightに移植するため、コンソールをエミュレートしてみました。サンプルの電卓プログラムです。 ⇒ 動作確認とソース
※Silverlightにデフォルトでフォーカスを与えることができないため、入力する前にクリックするようになっています。コメントで紹介していただいた方法(id:beta_magnus:20090806:1249550117)でフォーカスが与えられました。
構造を簡単にするため、TextBoxをログ出力用(textBox1)とコマンド入力用(textBox2)に分けます。出力はtextBox1に文字を追加するだけです。
public static void Write(string value) { textBox1.SelectionStart = TextBox.Text.Length; textBox1.SelectedText = value; }
SilverlightのTextBoxにはAppendText()がないためこのような回りくどいことをしています。
入力は少し厄介です。ReadLine()の中でイベントを回して、textBox2で[Enter]が入力されたら戻るようにしたいのですが、イベントを明示的に回す方法がありません。そのため以下のような構造にしてみました。
- コンソールアプリケーションのコードはサブスレッドで回す
- ReadLine()はMonitor.Wait()で待機
- UIスレッドで[Enter]を検出したらMonitor.PulseAll()を送る
- サブスレッド対応のためWrite()でDispatcherを使う
private static object mutex = new object(); private static string line; public static void ReadLine() { string ret = null; lock (mutex) { Monitor.Wait(mutex); ret = line; } return ret; } private static void textBox2_KeyDown(object sender, KeyEventArgs e) { switch (e.Key) { case Key.Enter: lock (mutex) { line = textBox2.Text; textBox2.Text = ""; Monitor.PulseAll(mutex); } e.Handled = true; break; } } public static void Write(string value) { textBox1.Dispatcher.BeginInvoke(() => { textBox1.SelectionStart = TextBox.Text.Length; textBox1.SelectedText = value; }); }
Consoleクラスの代替となるようにインターフェースを合わせたり、履歴機能を加えたりしたものが冒頭のサンプルです。Program.csを単独でコンパイルすればコンソールアプリケーションとして動きます。