The Silverlight APIsExperimenting with the IronPython Web IDE![]() Silverlight & IronPython
The IronPython Web IDEIn this article we will explore some of the APIs available to us in the Core-CLR that comes with Silverlight 2.0 Beta 1. We will do this with the aid of the IronPython Web IDE: www.voidspace.org.uk/ironpython/webide/webide.html You can download the Web IDE as a project: It comes with several pieces of example code, but also lets you explore the Silverlight API and load and save Python code. It uses the Javscript EditArea syntax highlighting Python editor. Standard out is diverted, so that print statements are sent to the 'debugging pane' at the bottom of the screen. Tracebacks are also printed there, to aid debugging. The examples here are all shortened forms of the full code in the Web IDE, so I highly recommend checking it out. In all these examples, root is the root visual element. This has already been set using code that looks like: from System.Windows import Application from System.Windows.Controls import Canvas The root element doesn't need to be a canvas. Some of the Microsoft examples use a UserControl or subclass. The programming model for Silverlight is based on WPF. It isn't identical, but in many cases some code and XAML could be shared between desktop and Silverlight applications. Those applications would only run on Windows though, there is currently no effort to port WPF to Mono (although it is possible that the Moonlight effort may change this of course). The Video PlayerOne of the impressive features of Silverlight is the video player. From code this is called the MediaElement, and we can use it from IronPython. from System.Windows.Controls import MediaElement from System import TimeSpan, Uri, UriKind m = MediaElement() u = Uri('HelloWorld.wmv', UriKind.Relative) t = TimeSpan(0) m.Source = u m.Position = t The example in the Web IDE also shows setting events on the MediaElement to handle it being clicked and the video ending. Accessing the Browser DOMChanging HTML elements and setting style attributes. HtmlPage.Document gives us access to the browser DOM. We can access elements as attributes on the document (just like in Javascript - something you can't do from C#!), or use the GetElementById method. CSS attributes are set with the SetStyleAttribute method on elements. from System.Windows.Browser import HtmlPage html = '<strong>Set from IronPython</strong>' HtmlPage.Document.experimental.innerHTML = html e = HtmlPage.Document.GetElementById('experimental') e.SetStyleAttribute('border', 'solid black 2px') # Call a javascript function "writesomestuff" HtmlPage.Window.CreateInstance("writesomestuff", 'One last thing...\n') The last part of the code (HtmlPage.Window.CreateInstance) calls a Javascript function defined in the web-page. We can also attach event handlers to Javascript events from Silverlight: from System import EventHandler from System.Windows.Browser.HtmlPage import Document from System.Windows.Controls import TextBlock root.Children.Clear() t = TextBlock() t.Text = 'Nothing yet...' root.Children.Add(t) def OnClick(sender, event): text = Document.input_field.value t.Text = text handler = EventHandler(OnClick) Document.OkButton.AttachEvent("onclick", handler) Open File Dialogfrom System.Windows.Controls import ( OpenFileDialog, DialogResult ) dialog = OpenFileDialog() dialog.Filter = "Python files (*.py)|*.py|All files (*.*)|*.*" if dialog.ShowDialog() == DialogResult.OK: print dialog.SelectedFile.OpenText().ReadToEnd() Inexplicably in-between Silverlight 1.1a and 2.0b1 the OpenFileDialog lost the ability to set the Title. Presumably it was judged a security risk... There is no save file dialog, but you can hack it up by bouncing data off a CGI script that sends the right headers back to the browser! (See this blog entry for details.) IsolatedFileStoragefrom System.IO.IsolatedStorage import ( IsolatedStorageFile, IsolatedStorageFileStream ) from System.IO import ( FileMode, StreamReader, StreamWriter ) store = IsolatedStorageFile.GetUserStoreForApplication() isolated = IsolatedStorageFileStream(name, FileMode.OpenOrCreate, store) writer = StreamWriter(isolated) writer.Write(data) writer.Close() isolated.Close() Silverlight provides 1 megabyte of local storage ('in the browser') per application, which presumably means per URL. Your application can request that this limit be raised, but it requires user confirmation. You access it through the IsolatedStorageFile class. Isolated storage provides a filesystem. You can create subdirectories and read / list / change files in those directories. Accessing Server Resources with the WebClientfrom System import Uri, UriKind from System.IO import StreamReader from System.Net import WebClient uri = Uri('/', UriKind.Relative) web = WebClient() def completed(s, e): print 'Completed' print 'Error?', e.Error print 'Cancelled?', e.Cancelled print e.Result def changed(s, e): print 'Bytes Recieved', e.BytesReceived print 'Progress Percentage', e.ProgressPercentage web.DownloadStringCompleted += completed web.DownloadProgressChanged += changed web.DownloadStringAsync(uri) The changed and completed events are raised asynchronously. This means that if you need to know when they are completed then you will have to signal from the event handler. Because they are asynchronous they are also raised on another thread. If you want to interact with the user interface (the WPF event loop) then we need to know a little bit about the WPF threading model. Silverlight and ThreadingIn order to invoke code back onto the GUI thread (the main thread) we need to use the Dispatcher. from System.Windows.Controls import TextBlock from System.Threading import Thread, ThreadStart text = TextBlock() text.Text = "Nothing yet" text.FontSize = 24 root.Children.Clear() root.Children.Add(text) def wait(): Thread.Sleep(3000) def SetText(): text.Text = 'Hello from another thread' text.Dispatcher.BeginInvoke(SetText) t = Thread(ThreadStart(wait)) t.Start() This model can also be used for keeping calculations on a background thread whilst leaving the user interface responsive. Reading Files from the 'xap'Silverlight doesn't give us access to the user's filesystem (except through the open file dialog). The file type is still present from IronPython though, and we can use it to read files contained in the 'xap'. This provides a convenient way of packaging data for your app: from System.Windows.Controls import TextBlock # Read from a file in the 'xap' handle = file('app.py') data = handle.read() handle.close() t = TextBlock() t.Text = data root.Children.Clear() root.Children.Add(t) There are several other examples in the Web IDE that we haven't covered here. These include setting the position of objects on a canvas, loading XAML and so on. Another potentially useful example is the Button class that is used to make the wonderful blue and yellow buttons in the Web IDE. This is contained in the file button.py and illustrates initialising a control from XAML (amongst other things). The next article looks at the scriptable attributes, and how we can use them to communicate between C# and Javascript. Unfortunately this needs some C#, but we can compile this from the command line without needing to install Visual Studio. For buying techie books, science fiction, computer hardware or the latest gadgets: visit The Voidspace Amazon Store. If you're looking for a new techie job, try the Voidspace Tech Job Board. This is part of the Hidden Network of technology and programming jobs.
Last edited Sat Mar 22 00:53:32 2008. Counter... |
|
|
Blogads
Follow me on: Tech Jobs |