【WPF】C#スクリプト・エディター「RoslynPad」を組み込む

当ページのリンクには広告が含まれています。

自作プログラムにC#スクリプトの実行機能を組み込む場合、自作プログラムの中でC#スクリプトを編集したくなりますよね。

TextBoxを使っても構わないのですが、Visual Studioの様なコード補完機能がありません。

しかし、RoslynPadというフリーのコントロールを使うことで、一般のテキストエディタっぽい入力とC#コードの補完機能が使えるようになります。

今回は、このRoslynPadの組み込み方について解説いたします。

目次

RoslynPadの動作

あたかもVisual Studioでソースコードを編集しているのに近い補完機能が使えるようになります。

RoslynPadと .NET Frameowrkのバージョン対応について

この記事を最初に公開した 2021年4月時点では、RoslynPad.Editor.Windows 1.2.0 が最新でしたが、2022年12月に バージョンが4.4.0 に上がり、 2023年11月現在の最新バージョンは 4.8.0となっています。

お使いのFrameworkによって 動作する RoslynPad が変わりますのでご注意ください。

.Net Framework バージョンRoslynPad.Editor.Windowsの対応バージョン
Microsoft .Net Framework 4.7.21.0.4
Microsoft .Net Framework 4.81.2.0
.NET Core 6.04.40
.NET Core 7.0~4.8.0

インストール方法

インストール方法というか、自作プログラムのプロジェクトに組み込むには、NuGetを使います。

NuGetの詳しい使い方が知りたい方は、「Visual Studio のパッケージ管理機能 NuGetとは?」の記事をご覧ください。

Visual Studio のメニューから「ツール」→「NuGetパッケージマネージャ」→「ソリューションのNuGetパッケージの管理」を選択すると下記の画面が表示されますので、”Roslyn pad"で検索してください。

そして、"RoslynPad.Editor.Windows"を選択し、インストールします。

この時、お使いの .NET Framework に応じて、RoslynPadのバージョンを変更して下さい。

組み込み方法

RoslynPad を実際に使う場合、XAMLとC#に記述が必要です。

まず最初に、XAMLに次のような参照とコントロールを記述します。

ちなみに、RoslynPadの正式名称は RoslynCodeEditor なので、そのように記述します。

下記は具体的なサンプルです。

ここでは、RoslynPadに uxEditor という名前を付けていることに注意してください。

<Window x:Class="RoslynPadTest.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:RoslynPadTest"
        xmlns:editor="clr-namespace:RoslynPad.Editor;assembly=RoslynPad.Editor.Windows"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <editor:RoslynCodeEditor x:Name="uxEditor" ></editor:RoslynCodeEditor>
    </Grid>
</Window>

C#側では冒頭の参照設定に次の4行を追加します。


using System.IO;
using System.Reflection;
using RoslynPad.Roslyn;
using RoslynPad.Editor;

このままでも単なるエディタとしては利用可能ですが、インテリセンスのような補完機能を動作させるには初期化が必要です。ただし、RoslynPadのバージョンによって初期化方法が変わりますのでそれぞれについて紹介しておきます。

RoslynPad 1.2.0以下における初期化方法

コンストラクタに次の4行を記載します。

var host = new RoslynHost(additionalAssemblies: new[]
{
    Assembly.Load("RoslynPad.Roslyn.Windows"),
    Assembly.Load("RoslynPad.Editor.Windows")
});
uxEditor.Initialize(host, new ClassificationHighlightColors(), 
                    Directory.GetCurrentDirectory(), String.Empty);

上記2点を実際に組み込んだサンプルは次のようになります。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Reflection;
using RoslynPad.Roslyn;
using RoslynPad.Editor;

namespace RoslynPadTest
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var host = new RoslynHost(additionalAssemblies: new[]
            {
                Assembly.Load("RoslynPad.Roslyn.Windows"),
                Assembly.Load("RoslynPad.Editor.Windows")
          });
            uxEditor.Initialize(host, new ClassificationHighlightColors(),
                                Directory.GetCurrentDirectory(), String.Empty);
        }
    }
}

RoslynPad 4.4.0以上における初期化方法

Initializeメソッドが廃止され、非同期のInitializeAsyncメソッドが追加されました。これに伴いコンストラクタに記述することが出来なくなったので、初期化専用の InitRoslynPad メソッドを作成し、これをコンストラクタから呼ぶようにします。

private async void InitRoslynPad()
{
    var host = new RoslynHost(additionalAssemblies: new[]
       {
        Assembly.Load("RoslynPad.Roslyn.Windows"),
        Assembly.Load("RoslynPad.Editor.Windows")
    });
    await uxEditor.InitializeAsync(host, new ClassificationHighlightColors(),
            Directory.GetCurrentDirectory(), 
            String.Empty, 
            Microsoft.CodeAnalysis.SourceCodeKind.Regular);
}

上記2点を実際に組み込んだサンプルは次のようになります。

using ICSharpCode.AvalonEdit;
using RoslynPad.Editor;
using RoslynPad.Roslyn;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace RoslynPadTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            InitRoslynPad();
        }

        private async void InitRoslynPad()
        {
            var host = new RoslynHost(additionalAssemblies: new[]
               {
                Assembly.Load("RoslynPad.Roslyn.Windows"),
                Assembly.Load("RoslynPad.Editor.Windows")
            });

            await uxEditor.InitializeAsync(host, new ClassificationHighlightColors(),
                    Directory.GetCurrentDirectory(), 
                    String.Empty, 
                    Microsoft.CodeAnalysis.SourceCodeKind.Regular);
        }
    }
}

RoslynPad 4.4以降でコード補完/構文チェックを有効化する

RoslynPad 1.2.0 の場合は、C#でよく使う標準的なアセンブリ(System.IOやSystem.Linqなど)が自動で読み込まれるため、先ほど紹介した初期化のコードだけで、コード補完や構文チェックが有効になりました。

しかし、RoslynPad 4.4.0以降においては、仕様変更により標準的なアセンブリが自動で読み込まれなくなったため、そのままでは補完や構文チェックがほとんど行われません。

そこで、使用頻度が多そうなアセンブリを読み込むように InitRoslynPad() メソッドに追記しておきました。下記のコードをコピペして張り付けてもらえれば、一通りのコード補完と構文チェックが行われるようになります。

private async void InitRoslynPad()
{
   var host = new RoslynHost(additionalAssemblies: new Assembly[]
   {
       Assembly.Load("RoslynPad.Roslyn.Windows"),
       Assembly.Load("RoslynPad.Editor.Windows")
   },

   references: RoslynHostReferences.NamespaceDefault.With(assemblyReferences: new Assembly[]
   {
       //.NET Coreより前のFrameworkを使う場合は、必要に応じてLoadする
       //Assembly.Load("System.Core"),
       //Assembly.Load("System.Linq"),
       
       // 自作ライブラリを補完候補に表示したい場合は、DLLのパスを指定
       //Assembly.LoadFrom(@"E:\Common\bin\Debug\net6.0-windows\CommonLib.dll"),

       // よく使われるであろうアセンブリ。必要に応じて取捨選択する。
       Assembly.GetExecutingAssembly(),
       typeof(System.Collections.ICollection).Assembly,                // System.Collections
       typeof(System.Linq.Enumerable).Assembly,                        // System.Linq
       Assembly.Load(new AssemblyName("System.Runtime")),              // System.Runtime
       typeof(System.Data.DataTable).Assembly,                         // System.Data
       typeof(System.Xml.XmlDocument).Assembly,                        // System.Xml
       typeof(System.Net.Http.HttpClient).Assembly,                    // System.Net.Http
       typeof(System.IO.File).Assembly,                                // System.IO
       typeof(System.Threading.Tasks.Task).Assembly,                   // System.Threading.Tasks
       typeof(System.Text.RegularExpressions.Regex).Assembly,          // System.Text.RegularExpressions
       typeof(System.Reflection.Assembly).Assembly,                    // System.Reflection
       typeof(System.ComponentModel.INotifyPropertyChanged).Assembly,  // System.ComponentModel
       typeof(System.Collections.Generic.List<>).Assembly,             // System.Collections.Generic
       typeof(System.Dynamic.DynamicObject).Assembly,                  // System.Dynamic
       typeof(System.Linq.Expressions.Expression).Assembly,            // System.Linq.Expressions
       typeof(System.Threading.Thread).Assembly,                       // System.Threading
       typeof(System.Globalization.CultureInfo).Assembly              // System.Globalization

   }));
   await uxEditor.InitializeAsync(host, new ClassificationHighlightColors(),
           Directory.GetCurrentDirectory(),
           String.Empty,
           Microsoft.CodeAnalysis.SourceCodeKind.Regular);
}

補足ですが、Assembly.Load("System.Core")と Assembly.Load("System.Linq") のアセンブリは .NET Core のリリースに合わせて System.Runtimeアセンブリに統合されているためコメントにしています。もし支障が出るようならコメントを外してみて下さい。

       //.NET Coreより前のFrameworkを使う場合は、必要に応じてLoadする
       Assembly.Load("System.Core"),
       Assembly.Load("System.Linq"),

自作ライブラリをコード補完/構文チェックの対象にする

自作ライブラリのクラスやメソッドもコード補完のリストに表示したい場合は、Assembly.LoadFrom(~) のコメントを外して、引数にビルド済みのDLLを指定して下さい。

       // 自作ライブラリを補完候補に表示したい場合は、ビルドされたDLLをフルパスで指定
       Assembly.LoadFrom(@"E:\Common\bin\Debug\net6.0-windows\Common.dll"),

引数のパスは相対/絶対のどちらでも構いません。相対パスの場合は、Visual Studio のビルド済みファイル(EXE、DLL)が出力されるフォルダを基準に指定して下さい。

また、RoslynPad のエディタ上で using による参照設定をしないとコード補完/構文チェックの対象になりませんのでご注意ください。

下記はCommonLib ネームスペース上の自作ライブラリに含まれるCsvLibクラスを、補完候補に表示させたスクリーンショットです。エディタの先頭で CommonLibの参照設定を行ったことで、CsvLibが正しくリストアップされています。

まとめ

今回は、RoslynPadのインストール方法と画面への組み込み方を解説しました。Microsoft .NET Frameworkのバージョンと合わせないとインストールすらできませんので、ご注意ください。

また、2021年時点で 1.2.0 だったバージョンが、2022年4月に 4.4.0となり、2023年には4.8.0に進化したものの、仕様が変わってコード補完させたいアセンブリを自力で登録しなければりません。

新しくなって手間が増えたので、この点は残念です。

しかし、最初に設定してしまえば済むことですし、自作プログラムの中でC#スクリプトを記述する場合、補完機能はやはり便利です。

興味を持たれた方は、是非チャレンジしてみてください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次