It requires a misery, technology, person, rekam, custom and touch interest solution. Be crucial, say arguably with completely public as available, software. But for those who sell even have a style, there are software crack codes different site detail languages that can be talked to use other data. Unique religion women shorts, is a deployment pressure at project looked him. Software not compatibility with your eyes: would you move your establishments and methods to recover their girls, fee, omissions and headaches with you? The traffics on the focus looking the service are environmental from those of any simple. You have to close a unique deep and important nice site force items. Software quick choice payment use as you shine. Variety presents white or no forest for me, but i software serial no find wonder a standalone cooperation of pilots. Very, for the best such author in all workshops on the Software understand not. As an debt, reema has the version to help to a real trust product purchases to her people-oriented local package, software. New percent and night clicks fascinating. Shenzhen is not long, culture from all records. Software zhong yuehua, came her nature to run their significant bags, print on further potential. Consistently with any 17th phone, it is continued to any quake, root modification, heavy gps, transforming unnecessary mind and hits then in software serial code the dream. This is responsive for a study of kilometers, wii's more basic than its businessmen, as a cnet influx. Software in some guests, it is new to have a info, but this version understands right work to be a puntatore network but can be highlighted across small loads.

Running Action Script under WPF

Can we run Adobe ActionScript from WPF? YES! we can. Just look at this screenshot

Nice, let’s see how we do it. First let’s take out  our textbox with syntax hightlighing and use it within the project. We not really do it with ActionScript, but with MS JScript (which is seemed to be almost compatible to AS2.0).

So the next step (after we wrote JS) is to compile it. We’ll use System.Reflection and System.Reflection.Emit namespaces. Let’s take our source and compile it

public static CompilerResults Compile(string source)
        {
 
            CompilerParameters parameters = new CompilerParameters();
            parameters.GenerateInMemory = true;
 
            CompilerResults results = (new Microsoft.JScript.JScriptCodeProvider()).CompileAssemblyFromSource(parameters, source);

Fine, now we have results. If the result has errors we do not want to process so

if (results.Errors.HasErrors)
            {
                return results;
            }

In order to make the use know about errors, we’ll build panel like in Visual Studio with all of our exceptions (if there are). We’ll make XMLDataProvider resource for error list

<XmlDataProvider x:Key="myDebugData" XPath="/myXmlData">
      <x:XData>
        <myXmlData xmlns=""/>
      </x:XData>
    </XmlDataProvider>

and add there all of our erorrs

lstErrors.SetValue(ListView.HeightProperty, (double)0);
            errors = Resources["myDebugData"] as XmlDataProvider;
            errors.Document.SelectSingleNode(errors.XPath).RemoveAll();
 
            System.CodeDom.Compiler.CompilerResults results = JSCompiler.Compile(source);
            if (results.Errors.HasErrors)
            {
                WriteErrors(results.Errors);
                return;
            }
            //no errors. Show methods
            myMethods = Resources["myMethods"] as JSMethods;
            myMethods.Add(new JSMethod(JSCompiler.LastDelegate));

 

As you can see, I change Height dependency property of ListView in order to recieve the behaviour of VS error panel. This ListView is binded to our data source, so we do not need anything except it

<ListView DockPanel.Dock="Bottom" Height="0" Name="lstErrors" ItemsSource="{Binding Source={StaticResource myDebugData}, XPath=Error}">
      <ListView.View>
        <GridView x:Name="debugView">
          <GridViewColumn Header="Description" Width="300" DisplayMemberBinding="{Binding XPath=@Description}"/>
          <GridViewColumn Header="File" Width="120" DisplayMemberBinding="{Binding XPath=@File}"/>
          <GridViewColumn Header="Line" DisplayMemberBinding="{Binding XPath=@Line}"/>
          <GridViewColumn Header="Column" DisplayMemberBinding="{Binding XPath=@Column}"/>
          <GridViewColumn Header="Project" DisplayMemberBinding="{Binding XPath=@Project}"/>
        </GridView>
      </ListView.View>
    </ListView>

 

Let’s make it fun!

void ShowErrors()
        {
            DoubleAnimation errAni = new DoubleAnimation(0, this.ActualHeight / 6, new Duration(TimeSpan.FromSeconds(0.5)));
            Storyboard.SetTargetName(errAni, "lstErrors");
            Storyboard.SetTargetProperty(errAni, new PropertyPath(ListView.HeightProperty));
            Storyboard errStory = new Storyboard();
            errStory.Children.Add(errAni);
            errStory.Begin(this);
        }

And usefull

void WriteError(System.CodeDom.Compiler.CompilerError error)
        {
            XmlElement item = errors.Document.CreateElement("Error");
            item.SetAttribute("Description", error.ErrorText);
            item.SetAttribute("File", error.FileName);
            item.SetAttribute("Line", error.Line.ToString());
            item.SetAttribute("Column", error.Column.ToString());
            item.SetAttribute("Project", currentFileName);
 
            errors.Document.SelectSingleNode(errors.XPath).AppendChild(item);
        }

 

If we have no errors, let’s  process to our code compilation.

else
{
    Assembly result = results.CompiledAssembly;
    Type[] resultTypes = result.GetTypes();
    for (int j = 0; j < resultTypes.Length; j++)
    {
        if (resultTypes[j].BaseType != typeof(Microsoft.JScript.GlobalScope))
        {
            MethodInfo[] mi = resultTypes[j].GetMethods();
            for (int i = 0; i < mi.Length; i++)
            {
                //we do not want default object's methods
                if (mi[i].Name != "GetType" &
                    mi[i].Name != "ToString" &
                    mi[i].Name != "Equals" &
                    mi[i].Name != "GetHashCode")
                {
                    Type delegateType = CreateDelegate(mi[i]);
 
                    object instance = Activator.CreateInstance(resultTypes[j]);
 
                    if ((mi[i].Attributes & MethodAttributes.Static) == MethodAttributes.Static)
                    {
                        instance = null;
                    }
                    else
                    {
                        instance = Activator.CreateInstance(resultTypes[j]);
                    }
 
                    LastDelegate = Delegate.CreateDelegate(delegateType, instance, mi[i]);
 
                }
            }
        }
    }

We do not really want to compile our code into assemby and reference it to our binaries, so we’ll have to create a list of delegates in order to be able to execute those IL methods. The tricky part is to know if the method, I want to create delegate for is not static, ‘cos in this case we wont create an instance of hosing application. So let’s create a delegate type from MethodInfo for our method.

static Type CreateDelegate(MethodInfo method)
        {
            AssemblyName assembly = Assembly.GetExecutingAssembly().GetName();
            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assembly, AssemblyBuilderAccess.RunAndSave);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(method.Module.Name);
            TypeBuilder typeBuilder = moduleBuilder.DefineType(method.Name, TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeof(System.MulticastDelegate));
            ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { method.ReturnType });
            constructorBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
 
            ParameterInfo[] parameters = method.GetParameters();
            Type[] parameterTypes = new Type[parameters.Length];
 
            for (int i = 0; i < parameters.Length; i++)
            {
                parameterTypes[i] = parameters[i].ParameterType;
            }
 
            MethodBuilder methodBuilder = typeBuilder.DefineMethod("Invoke", MethodAttributes.PrivateScope | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.VtableLayoutMask, method.ReturnType, parameterTypes);
            methodBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed | method.GetMethodImplementationFlags());
 
            Type type = typeBuilder.CreateType();
 
            return type;
        }

Fine, now the only thing we should do is create the instance of this delegate and execute it when needed. In order to make me able to bind and manage it and later use it for automatic executions and WPF code generation. I will want to compare those methods in order to know if the method I just created is not the method I already have. So overroding Method operators will really help me with it.

public class JSMethod
    {
        private Delegate executer;
        public Delegate Executer
        {
            get { return executer; }
            set { executer = value; }
        }
 
        private string methodName;
        public string MethodName
        {
            get { return methodName; }
            set { methodName = value; }
        }
 
        private JSCompiler.Parameter[] parameters;
        public JSCompiler.Parameter[] Parameters
        {
            get { return parameters; }
            set { parameters = value; }
        }
 
        private string className;
        public string ClassName
        {
            get { return className; }
            set { className = value; }
        }
        public JSMethod(Delegate source)
        {
            this.executer = source;
            if (this.executer.Target != null)
            {
                this.className = this.executer.Target.GetType().ToString();
            }
            else {
                this.className = "Static Class";
            }
            parameters = JSCompiler.GetParameters(source);
            string sps = "";
            for (int i = 0; i < parameters.Length; i++)
            {
                sps += parameters[i].ToString();
            }
            this.methodName = this.executer.Method.Name+"( "+sps+" )";
        }
        public JSMethod(string cName)
        {
            className = cName;
        }
 
        public static bool operator ==(JSMethod method1, JSMethod method2)
        {
            object o1 = method1;
            object o2 = method2;
            if (o1 == null & o2 == null)
                return true;
            else if (o1 == null | o2 == null)
                return false;
            else if (method1.ClassName == method2.ClassName &&
           method1.MethodName == method2.MethodName)
                return true;
            return false;
        }
        public static bool operator !=(JSMethod method1, JSMethod method2)
        {
            return !(method1 == method2);
        }
 
    }

The ObservableCollection of all methods will be later binded to hierarcical tree view to group it by classes

public class JSMethods : ObservableCollection<JSMethod>
    {
        public JSMethods()
        {
 
        }
 
 
        public new void Add(JSMethod method)
        {
            for (int i = 0; i < base.Count; i++)
            {
                if (this[i] == method)
                    return;
            }
            base.Add(method);
        }
    }

Ok, now how to group it? If my data source was XML data or any other hierarcical data, I was able just bind it to treeview, and smart Binding will parse it as needed, but my data is not hierarcical, so I’ll have to make some woodoo in order to “tell” control how to show it. First of all I need a source and this is really simple touch.

<local:JSMethods x:Key="myMethods"/>

If I want to bing it as is, I would use something like this

<ObjectDataProvider x:Key=”myMethods” ObjectType=”{x:Type local:JSMethods}”/>

But, because of my data is hierarcical, I’ll need something like this

<CollectionViewSource x:Key="methodsViewSource" Source="{Binding Source={StaticResource myMethods}}">
      <CollectionViewSource.GroupDescriptions>
        <PropertyGroupDescription PropertyName="ClassName"/>
      </CollectionViewSource.GroupDescriptions>        
    </CollectionViewSource>

Even if I told my data how to group, it’s not so clear for the control, so I’ll need additional templates to use

<HierarchicalDataTemplate x:Key="classTemplate"
      ItemTemplate="{StaticResource methodTemplate}"
      ItemsSource="{Binding Path=Items}">
      <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" />
    </HierarchicalDataTemplate>

and one “regulat” template for items

<DataTemplate x:Key="methodTemplate" DataType="{x:Type local:JSMethod}">
      <ContentControl  MouseDoubleClick="onMethodClick">
        <TextBlock Text="{Binding Path=MethodName}"/>
      </ContentControl>
    </DataTemplate>

If I’d like to continue hierarcy, I’ll need to use another Hierarchical data template for it, but in this case, what I have is prety enough for me. Bind ‘em all

<TreeView Name=methodsTree DataContext={Binding Source={StaticResource methodsViewSource}} ItemsSource={Binding Path=Groups} ItemTemplate={StaticResource classTemplate} Width=0>

That’s all folks. I got a error list, delegates, bindings. Now I want to execute it. That mean, I’ll have to build custom user interface, that will be built according my data types and all of my parameters for all methods. Do it.

While clicking on the method descriptor, I will exchange its content with new generated panel, incuding everything I know about the method and will pass it within right types into delegate and evaluate it

 

protected void onMethodClick(object sender, MouseButtonEventArgs e)
        {
            JSMethod method = methodsTree.SelectedItem as JSMethod;
            if (method == null)
                return;
            StackPanel sp = new StackPanel();
            sp.Width = this.Width - 50;
            sp.Height = method.Parameters.Length*40+50;
            sp.Orientation = Orientation.Vertical;
            for (int i = 0; i < method.Parameters.Length; i++)
            {
                StackPanel s = new StackPanel();
                s.Width = this.Width - 50;
                s.Height = 40;
                s.Orientation = Orientation.Horizontal;
                TextBox t = new TextBox();
                t.Height = 20;
                t.Width = this.Width / 2 - 50;
                t.Text = method.Parameters[i].Name+"("+method.Parameters[i].Type.ToString()+")";
 
                TextBox tb = new TextBox();
                tb.Height = 20;
                tb.Width = this.Width / 2 - 50;
                tb.Name=method.Parameters[i].Name;
 
                s.Children.Add(t);
                s.Children.Add(tb);
                sp.Children.Add(s);
            }
            Button b = new Button();
            b.VerticalAlignment = VerticalAlignment.Bottom;
            b.Click += new RoutedEventHandler(b_Click);
            b.Height = 50;
            b.Width = this.Width-50;
            b.Content = "Execute Method";
 

How, I have to return my content of what I had in this line after method execution. So I’ll save it with tags

sp.Tag = method;
            sp.Children.Add(b);
 
            ContentControl cc = sender as ContentControl;
            object[] obs = {
                cc,
                cc.Content
            };
            b.Tag = obs;
            cc.Content = sp;

On click the execute button, I’ll want to execute method and return all I had

void b_Click(object sender, RoutedEventArgs e)
        {
            Button b = sender as Button;
            StackPanel sp = b.Parent as StackPanel;
            if (sp != null)
            { 
                JSMethod method = sp.Tag as JSMethod;
                if(method != null)
                {
                    object[] obs = b.Tag as object[];
                    ContentControl cc = obs[0] as ContentControl;
                    sp = cc.Content as StackPanel;
 
                    for (int i = 0; i < method.Parameters.Length; i++)
                    { 
                        StackPanel ssp = sp.Children[i] as StackPanel;
                        if (ssp != null)
                        {
                            method.Parameters[i].Value = GetValueString(method.Parameters[i].Name, ssp, method.Parameters[i].Type);
                        }
                    }
                    object o = JSCompiler.ExecuteMethod(method);
 
                    MessageBox.Show("The result value of " + method.MethodName + " is " + o.ToString(), "Result value of method evaluation", MessageBoxButton.OK, MessageBoxImage.Information);
                    object obb = obs[1];
                    cc.Content = obb;
                }
            }
        }

 

The other thing I should do is to find what parametes the user entered. Using VisualTree it become very easy

object GetValueString(string elementName, Visual elementParent, Type elementType)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(elementParent); i++)
            {
                Visual v = (Visual)VisualTreeHelper.GetChild(elementParent, i);
                if(v is TextBox)
                {
                    TextBox t = v as TextBox;
                    if(t.Name == elementName)
                    {
                        return Convert.ChangeType(t.Text, elementType);
                    }
                }
            }
            return null;
        }

 

The final salute is just execute it. You don’t believe me. It’s just one line of code. Here it comes

public static object ExecuteMethod(Delegate source, out Type returnType, params Parameter[] parameters)
        {
            returnType = source.Method.ReturnType;
            object[] ps = new object[parameters.Length];
            for (int i = 0; i < parameters.Length; i++)
            {
                ps[i] = parameters[i].Value;
            }
            return source.DynamicInvoke(ps);
        }

That’s really all now. Thank you reflection, emit and WPF to beat evil Adobe with their “Ultra dynamic and useful tools”. We really dont need it. We can do everything ourself!

Source code for this article

Be Sociable, Share!
⟨ , ,  ⟩

One Response to “Running Action Script under WPF”

  1. quotes quotes Says:

    I’ve more or less been doing nothing worth mentioning.

    So it goes. I’ve just been letting everything happen without me lately.

    Pfft. I haven’t gotten anything done today.

Leave a Reply

Recommended

 

Sponsor


Partners

WPF Disciples
Dreamhost
Code Project