カスタム ASP.NET 式を使う
にはどうすれば良いかという話です。AquaSKK とは全然関係のない話です。
業務系の ASP.NET 開発ではエラーメッセージを一元管理したいというニーズが持ち上がると思いますが、大規模な開発だと複数のプロジェクト(ソリューション)に分割して影響範囲を狭め、並行開発をガガガっと進めることになります。そうすると、メッセージ ID などもフレームワーク的なものに同梱して各プロジェクトで共有したくなるのですが、標準的な埋め込みリソースだといまいち使い勝手が悪い。これをなんとかできないかと悩むわけです。
理想としては、プロジェクトテンプレートを配布してフレームワークの参照設定だけすれば、サクサク開発が進むようにしたい。以下、記憶から掘り起こして書いてみます(未コンパイル)。
MessageId
まずはメッセージ ID 用の単純なクラスを定義します。
public static class MessageId { public static string E0001 = "エラーメッセージ1"; public static string E0002 = "エラーメッセージ2"; // ... }
このクラスは Excel 仕様書からの自動生成が前提になります(VBA マクロ)。コードからは MessageId.E0001 のようにしてアクセスできますね。So far so good.
ExpressionBuilder
メッセージ ID 用のクラスは定義できたので、これを検証コントロールで使いたい。
ASP.NET では「ASP.NET 式」なるものを使って様々な値をコントロールのプロパティに設定することができますが、標準では Web.config の特定のセクションかリソースだけしか設定できません。そこでまずは ExpressionBuilder を継承して MessageId 用の ASP.NET 式を生成するクラスを実装してみます。
static class Util { public static string GetMessage(string id) { var field = typeof(MessageId).GetField(id); return (field != null) ? field.GetValue(null) : id; } } [ExpressionPrefix("MessageId")] [ExpressionEditor(typeof(MessageIdEditor))] public class MessageIdBuilder : ExpressionBuilder { public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context) { return new CodePrimitiveExpression(Util.GetMessage(entry.Expression.Trim())); } }
要するに、"E0001" を評価して "エラーメッセージ1" を返すようなコードを生成して返しています。
ExpressionEditor
式の prefix として "MessageId" が選択された時に使用されるエディタを実装します。private クラスで OK。
class MessageIdEditor : ExpressionEditor { public override object EvaluateExpression(string expression, object parseTimeData, Type propertyType, ServiceProvider serviceProvider) { return Util.GetMessage(expression); } public override ExpressoinEditorSheet GetExpressionEditorSheet(string expression, IServiceProvider serviceProvider) { return new MessageIdEditorSheet(expression, serviceProvider); } }
キモは、GetExpressionEditorSheet でカスタムプロパティシートオブジェクトを返すところです。
ExpressionEditorSheet
デザイン時に設定する一連のプロパティを定義するクラスです。private クラスで OK。
class MessageIdEditorSheet : ExpressionEditorSheet { public MessageIdEditorSheet(string expression, IServiceProvider serviceProvider) : base(serviceProvider) { MessageId = expression; } [TypeConverter(typeof(MessageIdListConverter))]; [Description("メッセージ ID を設定します")] public string MessageId { get; set; } public string GetExpression() { return MessageId; } }
MessageId プロパティを定義しています。Description 属性はデザイン時の説明に利用されるので、定義しておいたほうが親切でしょう。面倒くさければここで終わっても良いのですが、せっかくなので、MessageId をドロップダウンリストから選択できるようにするために、独自の TypeConverter を実装してみます。
TypeConverter
メッセージ ID をリストするための TypeConverter です。
class MessageIdListConverter : StringConverter { public bool GetStandardValuesExclusive(ITypeDescriptorContext context) { return true; } public bool GetStandardValuesSupported(ITypeDescriptorContext context) { return true; } public StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) { var list = new SortedList<string>(); FieldInfo[] fields = typeof(MessageId).GetFields(); foreach(var id in fields) { list.Add(id.Name); } return new StandardValuesCollection(list); } }
MessageId クラスの全フィールドをリストして返しています。