I've spent the better part of the last couple of days playing around with Silverlight 1.1 and it's been an interesting experience. It's both exciting and frustrating at the same time - exciting because it's incredibly nice to see .NET code running in the browser and being able to debug it. Frustrating because of the limited functionality that the Silverlight runtime has in terms of UI support specfically lack of controls and lack of a number of UI semantics. I'll post a more general post of impressions later this weekend.
But here is a more specific problem that I haven't found a solution for, but makes an interesting discussion of some of the things I hope you will be able to do with Silverlight.
A lot of focus has gone towards the visual and media aspects of Silverlight, but I think maybe the coolest feature of Silverlight is the fact that it brings the .NET platform and its richness to the browser. There are lots of ways to interact between HTML and the .NET runtime in this scenario.
As I was playing around I had this idea of building a small file upload control that can do in page uploads. I actually could use a more flexible way to handle file uploads to my photo album and so I set out with this small project.
And it's surprisingly easy to build such a thing. Silverlight includes an open file dialog that allows the user to select one or more files (which are exposed only as open file streams just like isolated storage) and so I pick up these files and store them in a List. The optional UI can then display the list of selected files. You can then call another method called UploadFiles to send the files to the server using the BrowserHttpWebRequest object which optionally can display a UI to display progress or alternately fire a StatusMessage event that can be handled by the browser app.
This is a very cool concept if you think about it: You can have an HTML page that interacts with a .NET component and the code used in that component can be fairly full featured. Silverlight is surprisingly feature-ful considering its small footprint... works great except the code runs on the main thread so while the upload is running the UI is frozen - not optimal but still an improvement from a UI perspective (it's much easier to pick files with the file dialog and do multiple selections for example then display the picked file list - big UI step up from a File control in HTML).
Anyway, creating the control's logic - minus the UI - plus the browser interop was surprisingly easy and took a couple of hours while fumbling with the documentation and figuring out the proper way to hook up the control from the HTML and expose properties and events (don't forget the [Scriptable] attribute on EVERYTHING that's visible to the browser. It's extremely satisfying to see the code work and interacting between the browser and the Silverlight control, using events for communication.
That part was easy. The tough part though is the UI. Silverlight is very rich but at the very same time extremely limited when compared to full WPF. I've been reading up and not doing much with WPF, so I feel somewhat comfortable with the concepts, but Silverlight is missing a ton of important features of WPF. The most annoying ones are lack of easy clipping support, lack of autosize support (no Auto sizing) and support for only one top level panel - Canvas. There are no StackPanels, WrapPanels or DockPanels for example. Also text functions are VERY limited. You basically have TextBlock and there's not even any support for text alignment. Without alignment and clipping it's pretty tough to build even simple display layout if the layout is not fixed sized. Some of these may seem like nitpicking but without better panel and flow support creating UI logic or even a fancy text display is not exactly trivial. For example, since there are no controls at all if you want to display data that overflows you have to create your own scrollers. Eh - no thanks I'll wait until there's better control support <s>...
So after spending a few hours playing around with various samples and trying to build a nice looking UI for this control I decided to bag it and just expose this control as a component.
BrowserHttpWebRequest on non-UI Threads
One important aspect of a control that does uploads would have to be multi-threading and one of the things that is awesome in Silverlight is that there's full threading support. You can spin up new threads and start doing processing on these threads. So naively I assumed that the threading would just work by moving the HTTP processing off to a separate thread then process the request synchronously on the separate thread.
Ha - it should be so easy. Silverlight uses the XmlHttp object of the browser and so although the .NET interface looks more like HttpWebRequest, it's really tied to the XHR object in the browser and all of its limitations. The main issue here is that XHR HAS TO run on the main UI thread so you can't fire it off syncrhonously off a new thread that you've spun up. So much for that idea. The only way to make this work is to use the Aysnc model which as it turns out is actually more obtuse than using XHR in the browser even - especially if you need to POST data to the server. I'll leave that for tomorrow <s>...
Multithreading and UI Access
But before I ran into this problem I had to deal with another: As soon as I started hooking together the threaded upload code with the user interface I hit the wall. With the limited visual UI I have built I wanted to update at least a status message and a simply progress bar simulation. Unfortunately I couldn't figure out a way to do this from the worker thread. Like in WinForms Silverlight doesn't allow updating of UI components from anything but the main thread so updating things like the text of the Textblock for thet file progress message didn't work. Unlike WinForms however, Silverlight does not (yet) have any way to marshal the thread as far as I can tell. There's Control.Invoke/BeginInvoke.
I thought - ah the UI is not that important anyway, I'll just fire the events back to the browser. But that also failed due to the UI thread limitation. Basically anything that goes back to the browser - presumably over COM at least in IE requires that it runs on the main UI thread. Same issue there - so no events from different threads work either.
This is a pretty big bummer actually. The XHR issue is understandable and there is a workaround by using the async event (BeginGetRequestStream() BeginGetResponse()), but the UI issue apparently has no workaround currently.
No doubt there will be a solution to this in the future but this limits what you can realistically do with threading currently pretty severely since there's no way to fire events directly back into the browser from a separate thread. For some things I'm thinking about this would be a crucial feature.
Exciting and Frustrating
The possibilities are definitely there but it's still very early in this product cycle. Actually, I think it's pretty amazing how stable all of this stuff is given its Alpha status. Even with the funky threading code and my UI awkardness I didn't once crash Silverlight or IE all day today. The code didn't blow up and performance of this stuff is excellent. Before I started with Silverlight I had visions of my previous work with Windows Mobile and the nightmare that entailed, but this development experience is nothing like this and it's pretty seamless. You can create two projects - one Web project to test with and one for the Silverlight library to create and from there it's as simple as debugging your code like you normally would. It just works as you would expect.
Good things will come of this!
Other Posts you might also like