Formsを使ってみる

FlowLayoutPanelを使ってみた。配置だけはうまくいくけど、自動リサイズやウェイトのかけ方が良くわからない。

  • scriptrunner.cs
namespace ScriptRunner {
  using System;
  using System.Collections.Generic;
  using System.Windows.Forms;
  
  using System.CodeDom.Compiler;
  using System.Reflection;
  
  using System.IO;
  using System.Text;
  
  public class ScriptForm: Form {
    private TextBox scriptBox;
    private TextBox resultBox;
    private TextBox classBox;
    private ComboBox langBox;
    private Dictionary langProviders = new Dictionary();
    private string items;
    private StreamToTextBox outRedirector;
    private StreamToTextBox errorRedirector;
    
    private const string InitScript =
      @"using System;

class MainClass {
    public static void Main(string args) {
        Console.WriteLine(""Hello World!"");
    }
}
";
    private const string InitMain = "MainClass";
    
    public ScriptForm(): base() {
      langProviders["C#"] = new Microsoft.CSharp.CSharpCodeProvider();
      langProviders["Visual Basic"] = new Microsoft.VisualBasic.VBCodeProvider();
      //langProviders["JScript"] = new Microsoft.JScript.JScriptCodeProvider();
      items = new string[langProviders.Count];
      langProviders.Keys.CopyTo(items, 0);
      InitControls();
      outRedirector = new StreamToTextBox(resultBox);
      errorRedirector = new StreamToTextBox(resultBox);
    }
    
    private void InitControls() {
      FlowLayoutPanel vPanel = new FlowLayoutPanel();
      vPanel.Dock = DockStyle.Fill;
      vPanel.FlowDirection = FlowDirection.TopDown;
      vPanel.WrapContents = false;
      vPanel.AutoSize = true;
      this.Controls.Add(vPanel);
      
      langBox = new ComboBox();
      langBox.Items.AddRange(items);
      langBox.SelectedIndex = 0;
      vPanel.Controls.Add(langBox);
      
      scriptBox = new TextBox();
      scriptBox.Multiline = true;
      scriptBox.AutoSize = true;
      scriptBox.Height = 100;
      scriptBox.Width = 280;
      scriptBox.Text = InitScript;
      scriptBox.ScrollBars = ScrollBars.Vertical;
      vPanel.Controls.Add(scriptBox);
      
      FlowLayoutPanel hPanel = new FlowLayoutPanel();
      hPanel.FlowDirection = FlowDirection.LeftToRight;
      hPanel.WrapContents = false;
      hPanel.AutoSize = true;
      vPanel.Controls.Add(hPanel);
      
      Label classLabel = new Label();
      classLabel.Text = "Main Class: ";
      hPanel.Controls.Add(classLabel);
      
      classBox = new TextBox();
      classBox.Text = InitMain;
      hPanel.Controls.Add(classBox);
      
      Button runButton = new Button();
      runButton.Text = "Run!";
      runButton.Click += delegate(object sender, EventArgs ev) {
        this.RunScript();
      };
      hPanel.Controls.Add(runButton);
      
      resultBox = new TextBox();
      resultBox.Multiline = true;
      resultBox.AutoSize = true;
      resultBox.Height = 100;
      resultBox.Width = 280;
      resultBox.ScrollBars = ScrollBars.Vertical;
      vPanel.Controls.Add(resultBox);
    }
    
    private void RunScript() {
      CodeDomProvider provider = langProviders[items[langBox.SelectedIndex]];
      
      resultBox.Clear();
      TextWriter outWriter = Console.Out;
      TextWriter errorWriter = Console.Error;
      Console.SetOut(outRedirector);
      Console.SetError(errorRedirector);
      
      try {
        ExecScript(provider, scriptBox.Text, classBox.Text);
      } catch (Exception ex) {
        Console.WriteLine(ex.ToString());
      } finally {
        Console.SetOut(outWriter);
        Console.SetError(errorWriter);
      }
    }
    private void ExecScript(CodeDomProvider provider, string source, string mainClassName) {
      CompilerParameters options = new CompilerParameters();
      options.GenerateInMemory = true;
      CompilerResults results = provider.CompileAssemblyFromSource(options, source);
      Assembly assembly = results.CompiledAssembly;
      
      Type type = assembly.GetType(mainClassName);
      BindingFlags flags = BindingFlags.Public | BindingFlags.Static |
        BindingFlags.DeclaredOnly | BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding;
      object parameters = new object{
        new string{}
      };
      type.InvokeMember("Main", flags, null, null, parameters);
    }
  }
  
  public class StreamToTextBox: TextWriter {
    private TextBox redirectBox;
    public StreamToTextBox(TextBox redirectBox) {
      this.redirectBox = redirectBox;
    }
    
    public override Encoding Encoding {
      get {
        return Encoding.UTF8;
      }
    }
    
    public override void Write(char ch) {
      redirectBox.Text += ch;
    }
  }
  
  public class MainClass {
    [STAThread]
    public static void Main(string args) {
      Application.Run(new ScriptForm());
    }
  }
}

GenericなCollectionは別名前空間のようだ。いまいち使いにくい気もするのだが。。。
delegateも使ってみたが、EventHandlerでもいいような気もしなくはないかな^^;

あとMSBuildもつかってみる。

  • Main.proj

  
    
  

(実際はProjectの上にはxml宣言があります。)こちらもドキュメントが少ないのでこんだけ。現状はNAntのほうがずっといい。