Denis's profileDenis Vuyka .Net Playgro...BlogListsNetwork Tools Help

Denis

Occupation
Location

Denis Vuyka .Net Playground

WPF Diagramming
February 08

Blog is moving

Ladies and gentlemen,

The blog has been moved to Wordpress (http://denisvuyka.wordpress.com).

Please update your bookmarks in order to follow new posts and get new information.

Thanks for your interest to my blog.

August 05

Online Mind Mapping Software

For those who are fond of mind mapping and corresponding tools the following project might be of great interest: http://mindomo.com/
mindomo_home_logo
 
Mindomo
July 03

Dynamic Geometry with Silverlight 2.0

While preparing an updated article related to diagramming with Silverlight 2.0 I came across an awesome project at CodePlex named "Dynamic Geometry" made with Silverlight 2 Beta 2. So I've decided to postpone my article for a while and mention this project worth looking at.

DynamicGeometry

June 05

Your own WPF PropertyGrid control in a couple of hours

About a week ago I found a very interesting implementation of a simple WPF PropertyGrid control at CodePlex. It inspired me writing my own vision of PropertyGrid that could help me within my projects. Special thanks to Robby Ingebretsen who gave me permissions using Kaxaml controls styles and a couple of classes within this article.

First thing you should always keep in mind is that with WPF the GDI age is over. You don't need drawing and rendering everything from code. This brings out that something like PropertyGrid control is now nothing more but a collection of brushes, data templates and the most simple steps to introduce the desired layout. It might take about 5 or 6 hours implementing the same control from scratch assuming you already have styles/themes for the controls.

I won't describe the code line by line and would rather prefer concentrating on key aspects of the implementation. Complete sources and demo application can be found at my SkyDrive at the end of this article.

Final results. Demo application.

image

The Property grid control is implemented in a full isolation inside a separate custom control library. This means that all control styles and effects are fully encapsulated within the control assembly and so do not impact the final application design. All you need is to add a reference to the property grid assembly and declare something like the following

[MARKUP CUT]

<GridSplitter Width="2" Background="Black" />
        <pg:PropertyGrid 
            xmlns:pg="clr-namespace:DenisVuyka.Controls.PropertyGrid;assembly=DenisVuyka.Controls.PropertyGrid"                
            Grid.Column="1" 
            SelectedObject="{Binding ElementName=button}" 
            ShowAttachedProperties="False"
            ShowReadOnlyProperties="False"
            ExpandCategories="False"/>

[MARKUP CUT]

The PropertyGrid is presented by a customized System.Windows.Controls.Control class and alongside the native properties defines only four property grid related properties for the moment. They are:

1. SelectedObject (object): Same as for the canonical Windows Forms PropertyGrid. It is an instance of an object the properties are to be changed for.

2. ShowAttachedProperties (true/false): Defines whether to show attached properties. Though this version is not capable of maintaining attached properties properly (still working on it) the control is capable of displaying them visually. The default is "False".

3. ShowReadOnlyProperties (true/false): Defines whether to show dependency properties that are readonly so having only getters. You won't be able to edit them but simply to see the values. For experimental purposes you can switch it on to see that readonly checkboxes will be properly reacting on such readonly properties like the "IsMouseOver". The default is "False".

4. ExpandCategories (true/false): Defines whether categories should be expanded upon control load. I personally like it to be initially collapsed but nevertheless set the default value to "True". So by default all the categories will be expanded.

Usually I guess the only "SelectedObject" definition/binding will be enough for everyday usage. You can omit the rest of the properties and rely on the default values.

UI features

1. PropertyGrid control

Supports only one "Black" color scheme for the the moment. After having estimated the time required to duplicate the Blend or Kaxaml color scheme I've decided to reuse the existing wonderful implementation and got Kaxaml permission for the styles, component templates and a couple of classes that I needed to change a bit according to my needs. Though everything I reused was reviewed, refactored and changed I still consider Kaxaml set to be the most awesome set of the control templates that can be found today.

The Control can be stretched within your panels without having any hardcoded width or height. For demo application I've used the common Grid layout with a vertical splitter between property grid and playground content so to see how it can be stretched in case property names are too long to be fully displayed.

2. Categories

Categories are smooth and animated :) It cannot be demonstrated by screenshots so you'll see that only after launching the demo application. Category templates are based on restyled Expander elements and so have their own Collaped/Expanded states unlike the Kaxaml approach within the TabControl where only one panel could be opened at a time.

3. UI Editors

UI Editors are the heart of any PropertyGrid control. They have to be efficient and convenient enough for the user to change the values. All editors in this control are based on DataTemplates for CLR types, inherited/base types or user configured properties. This will be described further on.

image

All editors can be represented either by common controls or by user created ones.

PropertyGrid performs re-templating and re-styling for the following set of common controls:

1. CheckBox

2. ComboBox

3. Expander

4. ScrollBar

5. ScrollViewer

6. Slider

7. TextBox

8. ToggleButton

alongside with a couple of user defined custom editors for demo purposes (will be described further on). But these controls above take part in most of the editor templates.

As I've mentioned earlier the property grid has the capability of choosing this or that editor according to the type of the property being edited. The key aspects and knowledge references will be given in the second half on the article. Now I'd like to dwell on the following features of the editor selection:

Default editor

Among all the scope of properties and their editors there will always be situation when there's no UI editor defined. In this case the fallback UI is needed to display the property in any way and rely on Type Converters that might still define the property value converted from a string at some kind of TextBox element.

So the default fallback editor here might possibly be a TextBox control. Thus I've tried covering different types of properties by relying on the default editor, like Width, Height, etc

image

All property value assignments are proxied by TypeConverters so in this case I can still have a valid property editor by means of the most basic Validation applied (I'm still working on more powerful validation and error notifications)

image

As for the existing editors the property grid control prioritize template selection based on CLR type. There's a set of already predefined ones but it is quite an easy thing importing them during runtime or extend the template selection factory (actually I'm also working on providing a service bus support with IServiceProvider/IServiceContainer but it's a point of future releases).

"Boolean" editor

Boolean editors are represented by CheckBox elements. Among the rest I think this is the less error-prone approach possible.

image

This editor reflects the readonly/writable state of the property properly so you won't be able defining getter-only property values.

"Enum" editor

Represented by a ComboBox element containing all the possible value for the corresponding enum-based property reflecting the values of the Enum.

image

Like the CheckBox editor this one neither allows user define error-prone values as the proper values are limited to a list. This editor is applied to all property types that are based on "System.Enum" type.

Alongside there are customized templates that provide more rich capabilities of editing property values:

ComboBox editor

There are many properties that are not based on Enums but nevertheless have a fixed (or nearly fixed) set of options to be chosen by the end-user. Let's take Font Families for example. It can be regarded as a fixed set as the user defining the Font Family value will be obliged keeping the existing list of possible values rather that typing anything he wants. So in this case Font Family is not an Enum-based value but is a perfect candidate to be displayed as a ComboBox selector. The same goes for example for FontStyle FontWeight, FontStretch, etc properties.

image

Meanwhile there might be, let's say, dual-oriented editors that support both either existing values or manual typing property value definition. The perfect sample for such a case might be a "Brush"-based properties. There have always been a set of predefined or named colors developers could use and the possibilities for defining/constructing any color based on it's ARGB members. This means that "Brush" editor should support either named colors or manual definitions:

"Brush" editor

image

The "Brush" editor is presented by an editable ComboBox that has a list of all Named colors (dynamically loaded) and yet is capable of converting user typed values from strings to appropriate brush instances where possible, the BrushConverter is used for this purpose. Also the combo is styled so that each Named color can be previewed before selection. The "Brushes" that don't belong to Named color family can be still displayed in the property grid in their native view.

"Thickness" editor

The "Thickness" editor was the first attempt to demonstrate the user defined templates and how the Point or Thickness based property can be edited in a different way. So I've created a separate editor control having two editing possibilities:

1. Common default-based text control. It can take only one value so that it will be set to all four members.

image

2. Expandable area for editing each value member separately:

image

This is just one of the samples to get the idea that you can provide any UI you want to edit a common property.

"Opacity" editor

Another feature of this PropertyGrid control is editor (template) selection based on named properties. I'm still working on a more efficient way of properties definition for that purpose but for present moment you don't need changing anything to the object type you are editing within the property grid. All required is to define an editor template with a name of the property that don't have any build in predefined editor.

"Opacity" property is a Double-based one. For all the doubles it comes out that the "Default" editor with an appropriate TypeConverter is quite enough to define a Double value. But there are many cases when the user can be restricted in the values he type. For example the "Opacity" takes a range between 0.0 and 1.0 as a valid value. So it is a perfect candidate for having a tuned editor for example looking like a Slider:

image

So you can get the most of a slider features like defining the Minimum/Maximum properties, TickFrequency, AutoToolTipPrecision, etc. and make this property editor less error-prone for the end-user as soon as you restrict the value setting possibilities only for a range of valid ones.

Also I've implemented a custom "Point" editor providing possibilities of editing parts of the Point structure similar to the "Thickness" editor and based on it another customization for "RenderTransformOrigin" property.

"RenderTransformOrigin" editor

RenderTransformOrigin property thus based on a Point structure also has a valid range for each member of the structure. Same as the opacity both X and Y expect the range between 0.0 and 1.0 doubles so this property can also be tuned in order to be more safe and restrictive. I've again used the Slider approach here for demo purposes:

image

This is a composite editor that is presented by a Default one to define the values manually and having Two sliders for each member of the Point structure. The editable part is automatically updated upon changing the slider values, hints and tooltips are also provided while dragging the slider.

That's all as for the key UI editor aspects. More details you will get from the sources and demo project. Again, I have to mention that you can implement any sort of UI required to edit this or that value type and I find this very appealing for future enhancements. I'm still working on more complex editors and their dynamic integrations outside the property grid control.

 

Interopability and Windows Forms

Until now I was mainly concentrated on Dependency Objects and editing Dependency Properties. It is quite easy to extend the control to provide Native properties support in future so that it can be used within any object instance.

Demo application solution contains a Windows Forms project for interop capabilities demonstration where the PropertyGrid holds another instance of PropertyGrid control as a SelectedObject.

private void Form1_Load(object sender, EventArgs e)
{
  this.elementHost1.Child = new DenisVuyka.Controls.PropertyGrid.PropertyGrid()
  {
    SelectedObject = new DenisVuyka.Controls.PropertyGrid.PropertyGrid()
  };      
}

This will look like the following:

image

So as I've said the Windows Forms support is on the way but not a difficult task to accomplish.

 

What are the key points and aspects you should get acquainted with in order to implement your own vision?

Step 1. From property descriptor to business object.

The main task of the property grid is displaying object properties and giving possibilities of changing their values in convenient way. So collecting properties is the first step do be thought over and performed. Each object to be displayed in a property grid has a set of public properties and each property has a special descriptor giving possibilities analyzing them from code. So you will have to implement a wrapper around each property encapsulating the process of value changing and ready to be bound to the UI elements as some business object.

Each property can provide the following minimum set of properties to the UI elements:

1. Name (mandatory). Each property has a name and this name should be displayed as a Label right before the value editor control.

2. Category (optional). The properties can be grouped by different categories so that user can easily manipulate a set of properties belonging to some logical family.

3. Type (mandatory). Property type describes the type of the value that is to be assigned for the instance of the object. This is the only way to choose the correct UI editor for each property.

4. Value (mandatory). This is a what to be set by UI editors and to be passed to underlying editable object instance.

5. IsReadOnly (optional). The property might occur to be read only (having only a getter) and so UI should react on that in a proper manner.

So you might work out something similar to the following diagram:

ClassDiagram1

Note that here and later on I'll be dealing with Dependency Properties only. I've reserved the Native properties and their maintenance for future enhancements and posts.

Property Category has only the "Name" mandatory property and serve a container for property items. It might look like given below:

ClassDiagram1

I've added additional optional boolean property called "IsExpanded" just for visualization purposes. The property grid will have an option defining whether all the property categories should be collapsed or expanded by default.

Here's the whole diagram for properties and related infrastructure

Grid Items

So upon setting the object to be edited your property grid control has to enumerate all the dependency properties and wrap them into some entities called here "DependencyPropertyItem" that will be bound to UI elements for end users.

You can get enumerate all property descriptors using the following snippet:

PropertyDescriptorCollection descriptors = TypeDescriptor.GetProperties(component,
  new Attribute[] { new PropertyFilterAttribute(PropertyFilterOptions.SetValues | 
                                                PropertyFilterOptions.UnsetValues | 
                                                PropertyFilterOptions.Valid) });

Next thing you can get is extracting a DependencyPropertyDescriptor from a common PropertyDescriptor in the following way:

DependencyPropertyDescriptor dpDescriptor = DependencyPropertyDescriptor.FromProperty(descriptor);

It will give you possibilities getting the Dependency Property only related metadata like determining whether it is an Attached Property, adding the value change and coerce callbacks, getting default values, etc.

Step 2. From business object to data template

Now as you already have some sort of business object it is time to start thinking of possible ways to display it in a proper way. Visually property grid displays a two-column grid where first column displays labels or text blocks identifying property names and second column displays different types of UI editors for setting values in a convenient way.

This control will be using a plain custom Control where the whole layout and control template will be declared within XAML. To get the basic idea of data templates used within the property grid I'd recommend you referring to the following articles. Guess this will be more efficient than I will be copy-pasting information that is already clarified everywhere:

Data Templating Overview

WPF DataBinding, Styling and DataTemplates

How can I display time information more graphically in WPF

Here it will be used a Control-based class templated in a way to expose ItemsControl. Something like the following:

<ItemsControl
   ItemsSource="{TemplateBinding local:PropertyGrid.Properties}"
   Background="<Some color>" />

DataTemplate for each dependency property wrapper may look like the following snippet:

<DataTemplate DataType="{x:Type data:DependencyPropertyItem}">
    <Grid Margin="4">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <TextBlock 
            Grid.Column="0"                
            Margin="0,0,8,0" 
            TextAlignment="Right" 
            VerticalAlignment="Center" 
            Text="{Binding Mode=OneTime, Path=Name}"
            ToolTip="{Binding Mode=OneTime, Path=Name}"/>
        <ContentControl
            Grid.Column="1"
            VerticalAlignment="Center"
            Content="{Binding Mode=OneWay}"
            ContentTemplateSelector="{StaticResource propertyTemplateSelector}" />
    </Grid>
</DataTemplate>

Snippet above presents one common row in your property grid control. It is layouted as a two-column grid where column 1 will contain a TextBlock element bound to the "Name" property of the underlying business object. Column 2 will be presented as a dynamic ContentControl or "Value Editor". According to the property type it will be "replaced" to the proper UI element.

To get more information on ContentControl and it's usage details you can refer to the following articles:

WPF Control Templates - An Overview

Why WPF Rock... (The content model)

Dr. WPF blog

Choosing the proper UI editor

I assume that at this moment you are already aware of templating the ItemsControl and providing basic data templates for the items. The next question that might arise from your side is how exactly the ContentControl is turned into the proper UI editor and how to create different types of editors for different property types.

This is where you might need nested templating or data templates inside the data templates and this is when you need details on ContentTemplateSelector property of a ContentControl or custom DataTemplateSelector implementations. I've also prepared a couple of links to start digging from in case you hear these words for the first time:

"Routed Template Selection" by Josh Smith

"How do I display items in an ItemsControl using different templates?" by Beatriz Costa

As you've seen from the snippets above the DependencyPropertyItem data template declares a ContentControl that has a PropertyTemplateSelector assigned for the ContentTemplateSelector property. It is a custom implementation of a DataTemplateSelector and it's job will be to get an appropriate DataTemplate for the UI editor according to the ItemsControl item being templated.

Step 3. UI Editors

As soon as you can style ItemsControl and aware of DataTemplating the next task you'll have to perform is to implement as much UI editors as you want and give them any desirable view. You can think over having UI editor templates outside the control so having possibilities extending your external collections later on. For a set of sample predefined editors and control templates please refer to the "/Themes/PropertyEditors.xaml" resource dictionary within the property grid control. This will give you all the required material and ideas needed to implement you own vision of value editors.

 

Conclusion:

Of course, there are still plenty of tasks for me to finalize in order to produce a fully-fledged property grid control and there's a lot of stuff for anyone else to change or study. But with the appearance of WPF I think we have reached the point in time where we can actually implement all the requirements rather than thinking over how to do that. As I've mentioned several times across the article I will continue working on this project so you may expect to hear more news and get more updates here. So thanks for your attention and keep on the line...

Source code and demo application for the article

Updated information:

The PropertyGrid control described here moved to the CodePlex. All new information and updates can be found there.

April 26

Immediate Window. Generating and executing lambdas across application domains.

First I'd like to say thank you words to Igor Moochnick. His article CodeDom extensions and dynamic LINQ (string/script to LINQ emitting) gave me a lot of pleasure extending it a bit and creating shorter code in a Linq manner flow. Refer to his article for more details on CodeDom and extension methods he introduced.

Introduction

Due to some purposes I needed creating a quick implementation of some kind of "Immediate Window" that could allow me executing methods and setting properties for object instances at live running application. I tried several approaches. Among them were "Dynamic Methods", extending "Linq Dynamic API" and parsing commands and property paths to be able using them against reflection. But at last moved to code generation as the most easiest and quickest way of accomplishing the task.

Imagine you have a small TextBox based pad in the running WPF application similar to "Immediate Window" pad in Visual Studio and you are willing to execute the following snippet against the main application window:

this.Title = "NewTitle"

(this.FindName("btnExecute") as Button).SetValue(Button.ContentProperty, "NewContent")

(this.FindName("stackPanel") as StackPanel).Children.Add(new Button() { Content="xxx" })

So these lines should be transformed into the code from their string representation and executed in runtime against the running Window as the code is supposed to perform some actions against the Window instance.

What I've decided to do was similar to the following ideas:

1. We should have the dynamically generated method that will have our text line as it's body (though with some possible transformations)

2. Method should accept our Window instance as parameter and perform defined text line against parameter.

3. It should return something if we are requesting the property value.

So we need here something similar to the code we could write down manually in the application wrapped into a method, for example

this.Title = "NewTitle" can be imagined as following:

public static void SetTitle(Window obj, string value)
{
  obj.Title = value;
}

So upon processing the command our environment has to generate some method called for example "SetTitle", provide the execution context (in this case a Window) and pass the command typed by the user. During that it should redirect all "this" aliases to the execution context detected (in this case all "this" should be translated into "obj"). Regard this as you are typing the body of some method without body declaration and are sure that all the missing stuff will be automatically generated.

Implementation

Code generation for this case will require dealing with separate application domains due to assembly management issues and possible memory leaks. The steps will be as following:

1. Transform and wrap user defined method/function body with appropriate method, class, namespace, etc. declarations using the CodeDom (so to get the ready to compile sources either into memory or physical file)

2. Compile the resulting Dom into the assembly (I'll be using physical files)

3. Create a separate application domain and load compiled assembly into it.

4. Extract the generated method from the loaded assembly and invoke it against the execution context (in this case it will be a Window)

5. Free resources, unload second application domain and perform a temporary files cleanup.

This is similar to implementing an Add-In or Plug-In support for your application where your external algorithms may be added to main application, executed against some provided execution context and finally destroyed without any impact on main application.

It is obvious that you might don't want passing whole your window across application domain boundaries (i.e. .net Remoting scenario) and you don't want marking anything as Serializable to pass into another domain. So all we need here is getting some delegate or lambda somewhere outside for applying it against our Window locally.

Void execution

Under Void execution I mean some operation that is invoked against your execution context and doesn't return any results. For example setting the property value.

So what happens when user types this.Title = "New Title" and presses Enter or some "Execute" button

1. "this" alias is converted into "context"

2. Lambda action is generated that performs your logic against some "context" parameter:

Action<T> action = context => { context.Title = "New Title"; };

3. Wrapper method and class container is generated that will help you getting lambda from another domain:

namespace GraphSquare.AutoScript
{
  using System;
  using System.Windows;

  public class Script
  {
    public static Action<T> CreateLambda<T>() where T : Window
    {
      Action<T> action = context => { context.Title = "New Title"; }; 
      return action;
    }
  }
}

As you can see this method will be valid for all the types based on Window, so you'll have possibilities running the resulting lambda against your different custom windows and dialogs that inherit Window type. Note that this rules are introduced for clarification purposes and <T> constraint may differ. According to this constraint we ensure that the method will be compiled successfully as each Window object has a Title property.

CodeDom for this method is generated using the Igor's CodeDom extensions I mentioned at the beginning of the article:

public static CodeDom GenerateActionDom<T>(string actionBody)
{
  string body = string.Format(
    "Action<T> action = context => {{ {0}; }}; return action;",
    actionBody.Replace("this", "context"));

  CodeDom c = new CodeDom();
  c.AddReference(DefaultReferences)
      .AddNamespace(DefaultNamespace)
        .Imports(DefaultImports)
          .AddClass(
            c.Class(DefaultClassName)
              .AddMethod(c.LambdaAction("CreateLambda", typeof(T).Name, null, body))
           );

  return c;
}

I won't dwell on extension methods implementation and my contribution to it as it is more understandable when looking through the sources. Please refer to the source code link at the end of this article. In two words you are creating the source for the class mentioned earlier and specifying the <T> constraint passing the generic type provided for the method. Also "this" alias is converted into "context" and passed to CodeDom as a body of newly generated method.

Function execution

If you want invoking the command that user had typed and expect some results to be returned and displayed you might want in this case getting Func<T,K> lambda, running it against some T parameter and present the K result back to user. For simplicity purposes I've decided to reuse native .net "return" keyword and so being close to method body declaration in a common way it is used.

So what happens when user types return this.Title and presses Enter or some "Execute" button:

1. "this" is converted into "context"

2. Lambda function is generated that performs some logic against your "context" and returns results

Func<T, object> func = context => { return context.Title; };

3. Wrapper function is generated for getting lambda from another domain, constraints and types are defined according to the calling application

namespace GraphSquare.AutoScript
{
  using System;
  using System.Windows;

  public class Script
  {
    public static Func<T, object> CreateLambda<T>() where T : Window
    {
      Func<T, object> func = context => { return context.Title; };
      return func;      
    }
  }
}

Here's how CodeDom is generated to get such a class:

public static CodeDom GenerateFunctionDom<T>(string fucntionBody)
{
  string body = string.Format(
    "Func<T,object> func = context => {{ {0}; }}; return func;",
    fucntionBody.Replace("this", "context"));

  CodeDom c = new CodeDom();
  c.AddReference(DefaultReferences)
      .AddNamespace(DefaultNamespace)
        .Imports(DefaultImports)
          .AddClass(
            c.Class(DefaultClassName)
              .AddMethod(c.LambdaFunction("CreateLambda", typeof(T).Name, null, body))
           );

  return c;
}

Compilation and assembly loading

I've provided additional method for CodeDom class providing capabilities compiling sources to file without keeping the strong reference to Assembly file at the end so providing possibilities of removing the assembly later on when it is no more in use. You'll be calling CodeDom.CompileAssembly method that gets string parameter for full final assembly path and returns CompilerResults for results processing in order compilation exceptions.

According to common approach patterns for loading assemblies inside separate application domains you need implementing a proxy Loader class to serve also as a contract and bridge between your two domains. So exactly the loader being instantiated in the second application domain will load compiled script assembly, extract the desired lambda and execute it against your context or simply return you the lambda so you can execute it inside the main application domain whenever required.

Assembly Loader

using System;
using System.IO;
using System.Reflection;

namespace GraphSquare.Scripting.CodeDom
{
  [Serializable]
  public class AssemblyLoader
  {
    Assembly assembly;

    public AssemblyLoader()
    {
      assembly = null;
    }

    // Loads the content of a file to a byte array to
    // prevent file locking, so user can remove or modify assembly 
    // while using it loaded into memory
    static byte[] LoadFile(string filename)
    {      
      FileStream fs = new FileStream(filename, FileMode.Open);
      byte[] buffer = new byte[(int)fs.Length];
      fs.Read(buffer, 0, buffer.Length);
      fs.Close();
      return buffer;
    }
    
    public void Load(string assemblyPath)
    {
      byte[] rawAssembly = LoadFile(assemblyPath);
      this.assembly = Assembly.Load(rawAssembly);
    }
  }
}

This is a basic implementation providing only assembly loading facilities. It will be extended later on. Note that it is situated in the separate assembly in order to serve a contract between different domains.

To create additional application domain our main application will have the following method:

private static AppDomain CreateNewDomain()
{
  // Create a simple application domain
  return AppDomain.CreateDomain(
    typeof(AssemblyLoader).Name, 
    AppDomain.CurrentDomain.Evidence, 
    AppDomain.CurrentDomain.SetupInformation);
}

This is the most basic implementation of second domain that takes Evidence and Setup Information from the main one and so loads all the references that the main domain has. In our case it will also load the contract library with the AssemblyLoader so we could establish communication between domains easily.

To create a valid loader in the second domain and loading external assembly file into it we'll be using the following method:

private static AssemblyLoader CreateLoader(AppDomain domain, string assemblyPath)
{
  // Create a new instance of AssemblyLoader in the separate domain
  AssemblyLoader loader = domain.CreateInstanceAndUnwrap(
    "GraphSquare.Scripting", 
    typeof(AssemblyLoader).FullName) as AssemblyLoader;

  // Load compiled assembly into the loader
  loader.Load(assemblyPath);      
  return loader;
}

Extracting compiled lambdas

Fine now we have two possible members of the generated wrapper class needed to be discovered and loaded (action and function) to be used in lambda generation. As we have a separate domain with compiled assembly loaded into it and know exactly the namespace, type and name of the wrapper class and even the name of the method to generate lambda - "CreateLambda" (as we did it's generation actually) the process of it's loading and invokation becomes quite trivial.

Using Assembly.GetType(string...) method it becomes easy loading types and activating objects. For each type you can call GetMethod(...) to get the necessary method info to be used in invokaction. Thus discovering and invoking generic methods are a bit different. Here's how can extract our generated "CreateLambda" method from AssemblyLoader:

public Action<T> GetLambdaAction<T>(string type, string action)
{
  // Extract type method info from assembly
  MethodInfo methodInfo = assembly.GetType(type).GetMethod(
    action, 
    BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);

  // Create generic arguments for generic method
  Type[] genericArguments = new Type[] { typeof(T) };

  // Create generic function info for invokaction
  MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);

  // Invoke generic function and get return value as Action<T>
  Action<T> returnValue = (Action<T>)genericMethodInfo.Invoke(null, null);

  // return results
  return returnValue;
}

As compiled assembly is loaded into the second application domain where the AssemblyLoader is already present so loader is capable of discovering our generated type to work with further.

When executed this method returns us ready to use lambda with the body we defined earlier. In most of the cases guess you'll have to get compiled lambda, execute it against some context and dispose it. So we can introduce two more members for the AssemblyLoader for invoking actions and functions directly from AssemblyLoader.

public bool InvokeLambdaAction<T>(string type, string action, T argument)
{      
  // Extract type method info from assembly
  MethodInfo methodInfo = assembly.GetType(type).GetMethod(
    action, 
    BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);

  // Create generic arguments for generic method
  Type[] genericArguments = new Type[] { typeof(T) };

  // Create generic function info for invokaction
  MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);

  // Invoke generic function and get return value as Action<T>
  Action<T> returnValue = (Action<T>)genericMethodInfo.Invoke(null, null);
  if (returnValue != null)
  {
    // Execute received action against argument provided
    returnValue(argument);
    return true;
  }
  return false;
}
public object InvokeLambdaFunc<T>(string type, string function, T argument)
{
  // Extract type method info from assembly
  MethodInfo methodInfo = assembly.GetType(type).GetMethod(
    function, 
    BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);

  // Create generic arguments for generic method
  Type[] genericArguments = new Type[] { typeof(T) };
  // Create generic function info for invokaction
  MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);
  // Invoke generic function and get return value as Func<T,K>
  Func<T, object> func = (Func<T, object>)genericMethodInfo.Invoke(null, null);
  //return execution result of func against the argument provided
  return func(argument);
}

As you can see both methods are not so different. Both of them require full type name of the class holding the method, method or function name to be searched and argument of your needed type to be processed as an execution context.

So the process of executing user typed command that doesn't require results can be as following (at main application side):

// Generate CodeDom
CodeDom c = CodeDomSmith.GenerateActionDom<T>(methodBody);
string assemblyPath = GenerateAssemblyPath();
// Compile sources into assembly
CompilerResults results = c.CompileAssembly(assemblyPath);

// Process compilation errors
if (results.Errors.Count > 0)
  return false;

// Create separate application domain
AppDomain domain = CreateNewDomain();
// Create loader proxy based on application domain created 
// and load compiled assembly to it
AssemblyLoader proxy = CreateLoader(domain, assemblyPath);

try
{
  // Extract and execute lambda against the context object
  proxy.InvokeLambdaAction<T>(
    CodeDomSmith.DefaultClassFullname, "CreateLambda", context);
}
catch (Exception ex)
{
  return false;
}

if (domain != null)
{
  // Unload and dispose second application domain
  AppDomain.Unload(domain);
  domain = null;
}
if (File.Exists(assemblyPath))
  // Remove used assembly
  File.Delete(assemblyPath);

The only difficulty that arise is determining what type of lambda to generate according to the user input. I mean how to decide whether he wants executing a Void or getting some results. I've accomplished that again as I've mentioned earlier by reusing the "return" keyword. So due to this sample when the user starts the command from "return" keyword we are generating the Func<T,K> otherwise Action<T>

Samples:

Here's the sample environment I've prepared for the article:

image

You'll have the Window that will be assigned as an execution context for all upcoming commands typed in the bottom TextBox control.

"Execute" button compiles and executes the command putting all the output to the "Debug window" TextBox control. You will also be able to see the content of the class generated and executed for development purposes.

"Help" button shows a list of dummy samples that can be copy-pasted and tested against the window.

"Execution Result" TextBox shows the results of the command execution. This can be either "void()" if method was compiled and executed or some value.

Here's the possible result of execution of the command:

this.Title = "GraphSquare Scripting"

image

Note that execution result is "void()" as we didn't try to return anything and the Title of the window has changed from "Window1" to "GraphSquare Scripting"

Let's try running the application once again and executing the following command:

return this.Title == "Window1"

image

As you can see command was successfully evaluated and returned "True" value that is a valid result as the Window's Title property value is "Window1"

Now let's try typing a command that cannot be valid and compiled by default, something like

this.ExecuteMissingCommand()

If you remember the execution context for our commands is being set to Window. This means that as a common Window class does not contain the method typed the resulting code won't be compiled and cannot be executed against a window. This brings to a compilation exception:

image

The exception message will be the following:

error CS1061: 'T' does not contain a definition for 'ExecuteMissingCommand' and no extension method 'ExecuteMissingCommand' accepting a first argument of type 'T' could be found (are you missing a using directive or an assembly reference?)

This is mainly for your debugging purposes. The real life implementation can hide the developer oriented details and present more user-friendly message.

Also as you might have noticed all lambda generation methods are generic ones, for example

public static bool InvokeContextMethod<T>(T context, string methodBody, ...)

this means that you can specify different execution contexts or even change them on the fly.

As for the suggestions I think there could be some contracts to serve as execution context instead of applications or windows. Remember not providing the end-user more power that he is expected to have. As you will see from the samples provided within the "Help" section of this tool you can simply add or remove new elements to the window, rename buttons, etc.

Hope this helps someone enriching his tools with runtime command support or Debug features.

The source code for the article can be found here