What would be covered in this post?
- Creating classes in IronPython and comparing with C# classes. Adding public properties in IronPython class.
- Using classes/interfaces in IronPython class which is in the hosting assembly. For example, if the application hosting the DLR and executing the IronPython class at runtime has an interface IDyn, this article covers on how to use that interface within the Python script.
- Accessing the dynamic type created in the IronPython and making an instance of it.
- Finally, binding the dynamic type to WPF controls.
Before, we get started, I recommend you go through the article I posted previously which shows how to use the IronPython engine within .NET applications. I will be using the same PythonEngine class with a new method added as shown below.
In the above method, we see that the engine (refer to the previous article, it would be useful if you want to understand it) creates an instance of ScriptSource object from the script file. Then we pass the current ScriptScope we created earlier and pass it to the Execute() method which would make the class be available to be used. Line 7 shows using GetVariable() on the engine and we pass the scope (which knows where the class we are looking for is) and also the name of the class, which is DynObject. Once we have the class (I assume its the IL, or at least i understood it that way), we use the Create() method on the engine passing the class which would return instance of that class. Then we simply return the instance by casting it to type T (a generic, so we use default(T) which is like null but for generics). So this method basically executes a python script and returns an instance of the class we specify. May be I would just refactor the method to make it look like shown below and which allows the method itself to be more generic than it is.
The method is used as shown below.
Creating IronPython class with public properties
Consider the C# class shown below.
The class is named DynObject which implements the interface IDyn and which has two public properties Name and Age. The python code for the same is shown below.
The statement followed by # are the comments. Hope they help you relate the classes properly and with that one should be able to write basic classes on their own.
Importing Namespaces in IronPython and setting up default namespaces
Now the problem with the above script when you Execute() it in the method I first discussed is that it would complain about not knowing what IDyn is. So basically we do an import the namespace. But the interface IDyn was created inside a namspace “Dynamics” which is the same application that is executing the python script. Had it been a ‘Debug’ then one could have done the following to import System.Diagnostics.*
But the issue I has was to know what assembly should I mention in the AddReference and I was wondering if there was a good way to import some default namespaces into the engine without having the user mention them manually. For that reason we have ScriptRuntime.LoadAssembly(Assembly asmToLoad) which can be used to add reference to assemblies of your choice. In order to support this, I felt that it would be a good idea to load the assemblies before you even generate the ScriptSource object from the script file. For this reason, I modified the PythonEngine (the wrapper I talked about in my previous post on IronPython) constructor and now it looks like as shown.
What should be of interest to import default assemblies into the system are in lines 7-11. Then on we can move on to add the imports to the python file as shown. No more AddReference() required.
Note that you still need to do the “from NAMESPACE import CLASSNAME/*”.
How about integrating the python code in WPF?
The IDyn was just an empty interface which was added to explain how one could use .NET interfaces within IronPython classes. So back to the WPF application, which is simple and straight forward. The XAML code for the Window is shown below.
From the bindings shown above, the Name property is looked for in the DataContext of TextBlock, StackPanel or Window. So in the code-behind we use our PythonEngine to obtain an instance of the dynamic type we created and set the DataContext of the window to the instance we obtained. The code behind is shown below.
This ability to bind WPF controls to dynamic types would be a great feature if you would like to generate UI based on the user controlled params. This would be even easier with the dynamic support in C# 4.0 which I hope to see another release during the MIX 2009.
Next I would like to work on generate the python classes from XML which would be provided by the user and even the XAML would be generated from the XML. This would be the basis for my reporting suite which would be powered by Silverlight, DLR and WCF.