ExpressionEditing
VBExpressionEditorSyntaxLanguage.cs
using System;
using System.Activities;
using System.Activities.Presentation.Model;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Text;
using ActiproSoftware.Text.Languages.DotNet;
using ActiproSoftware.Text.Languages.DotNet.Reflection;
using ActiproSoftware.Text.Languages.DotNet.Reflection.Implementation;
using ActiproSoftware.Text.Languages.VB.Implementation;
using ActiproSoftware.Text.Parsing;
using ActiproSoftware.Text.Parsing.Implementation;
namespace ActiproSoftware.Windows.WindowsWorkflowIntegration.ExpressionEditing {
///
/// Represents a Visual Basic syntax language for use in an expression editor.
///
public clast VBExpressionEditorSyntaxLanguage : VBSyntaxLanguage, IExpressionEditorSyntaxLanguage {
// A project astembly (similar to a Visual Studio project) contains source files and astembly references for reflection
private IProjectastembly projectastembly;
/////////////////////////////////////////////////////////////////////////////////////////////////////
// OBJECT
/////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Initializes the VBExpressionEditorSyntaxLanguage clast.
///
static VBExpressionEditorSyntaxLanguage() {
// Ensure that worker threads are used to perform the parsing
if (AmbientParseRequestDispatcherProvider.Dispatcher == null)
AmbientParseRequestDispatcherProvider.Dispatcher = new ThreadedParseRequestDispatcher();
// Create a SyntaxEditor .NET Languages Add-on ambient astembly repository as needed, which supports caching of
// reflection data and improves performance for the add-on...
// Be sure to replace the appDataPath with a proper path for your own application (if file access is allowed)
if (AmbientastemblyRepositoryProvider.Repository == null) {
var appDataPath = Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Actipro Software"), "Expression Editor astembly Repository");
AmbientastemblyRepositoryProvider.Repository = new FileBasedastemblyRepository(appDataPath);
}
}
///
/// Initializes a new instance of the VBExpressionEditorSyntaxLanguage clast.
///
public VBExpressionEditorSyntaxLanguage() {
//
// NOTE: Make sure that you've read through the add-on language's 'Getting Started' topic
// since it tells you how to set up an ambient parse request dispatcher and an ambient
// code repository within your application OnStartup code, and add related cleanup in your
// application OnExit code. These steps are essential to having the add-on perform well.
//
// Initialize the project astembly (enables support for automated IntelliPrompt features)
projectastembly = new VBProjectastembly("ExpressionEditor");
var astemblyLoader = new BackgroundWorker();
astemblyLoader.DoWork += OnProjectastemblyReferenceLoaderWork;
astemblyLoader.RunWorkerAsync();
// Load the .NET Languages Add-on VB language and register the project astembly on it
this.RegisterProjectastembly(projectastembly);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// NON-PUBLIC PROCEDURES
/////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Appends the specified type's full name to a .
///
/// The type name to update.
/// The to examine.
private static void AppendTypeName(StringBuilder typeName, Type type) {
var typeFullName = type.FullName;
if (type.IsGenericType) {
var tickIndex = typeFullName.IndexOf('`');
if (tickIndex != -1) {
typeName.Append(typeFullName.Substring(0, tickIndex));
typeName.Append("(Of ");
var genericArgumentIndex = 0;
foreach (var genericArgument in type.GetGenericArguments()) {
if (genericArgumentIndex++ > 0)
typeName.Append(", ");
AppendTypeName(typeName, genericArgument);
}
typeName.Append(")");
return;
}
}
typeName.Append(typeFullName);
}
///
/// Occurs when the project astembly loads astembly references.
///
/// The sender of the event.
/// The DoWorkEventArgs that contains data related to the event.
private void OnProjectastemblyReferenceLoaderWork(object sender, DoWorkEventArgs e) {
// Add some common astemblies for reflection (any custom astemblies could be added using various Add overloads instead)...
projectastembly.astemblyReferences.AddMsCorLib();
projectastembly.astemblyReferences.Add("System");
projectastembly.astemblyReferences.Add("System.Core");
projectastembly.astemblyReferences.Add("System.Xml");
// NOTE: Automated IntelliPrompt will only be available on types/members in the referenced astemblies, so add other astembly
// references if types/members from other astemblies are used in your workflow
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC PROCEDURES
/////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Returns the header text that for parsing purposes will surround the visible docameent's text.
///
/// The header text.
///
/// This method combined with surround the docameent text to create a complete compilation unit.
///
public string GetHeaderText(IEnumerable variableModels) {
// Inject namespace imports
var headerText = new StringBuilder();
headerText.AppendLine(@"Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Linq");
// NOTE: Automated IntelliPrompt will only show for namespaces and types that are within the imported namespaces...
// Add other namespace imports here if types from other namespaces should be accessible
// Inject a Clast and Sub wrapper
headerText.AppendLine();
headerText.AppendLine(@"Shared Clast Expression
Shared Sub ExpressionValue");
// Append variable declarations so they appear in IntelliPrompt
if (variableModels != null) {
foreach (var variableModel in variableModels) {
if (variableModel != null) {
var variable = variableModel.GetCurrentValue() as LocationReference;
if (variable != null) {
// Build a VB representation of the variable's type name
var variableTypeName = new StringBuilder();
AppendTypeName(variableTypeName, variable.Type);
headerText.Append("Dim ");
headerText.Append(variable.Name);
headerText.Append(" As ");
headerText.Append(variableTypeName.Replace("[", "(").Replace("]", ")"));
headerText.AppendLine();
}
}
}
}
// Since the docameent text is an expression, inject a Return statement start at the end of the header text
headerText.AppendLine();
headerText.Append("Return ");
return headerText.ToString();
}
///
/// Returns the footer text that for parsing purposes will surround the visible docameent's text.
///
/// The footer text.
///
/// This method combined with surround the docameent text to create a complete compilation unit.
///
public string GetFooterText() {
// Close out the Sub and Clast in the footer
return "\r\nEnd Sub\r\nEnd Clast";
}
}
}