I’ve started blogging on InsideRIA recently, and I must say – I’m enjoying it.
Latest post is on Flash & Silverlight.
http://www.insideria.com/2009/06/flash-and-silverlight-an-unlik.html
I’ve started blogging on InsideRIA recently, and I must say – I’m enjoying it.
Latest post is on Flash & Silverlight.
http://www.insideria.com/2009/06/flash-and-silverlight-an-unlik.html
In August this year, O’Reilly and 360 Conferences are running the first InsideRIA Conference.
What appeals to me about this conference over so many others is:
a) It’s not about the fluff, it’s developer-to-developer; and
b) It’s platform agnostic.
As such, the topic I’m speaking on is what the two main players in the RIA sphere are doing within their markup languages.
State of the Union: XAML and MXML in 2009
An honest and objective look at the two markup technologies dominating RIA development today. There is something for both Silverlight and Flex devs to learn from each other, and this is a discussion that is sorely lacking in the RIA industry at the moment. Topics covered include Styles, Resources, Databinding and Layout.
Come along! I always enjoy a yarn about RIA.
April 15, 2009 Update: Unfortunately, DynamicCollection performs badly when the underlying arrays exceed a thousand elements. Stay tuned for an update.
What if you have a few Arrays or ArrayCollections of the same object data, and you want them to display as a single dataProvider?
Using the below schema as an example, say you loaded a list of Projects from the DB and you want to display all the Companies in a single DataGrid. Or a list of all Employees. How would you do it?
Sure you could append them all to one big Array or ArrayCollection. Although you leave open the door for inconsistencies when you add a Company to some Project object.
This is where the DynamicCollection comes in.
Essentially it is an ArrayCollection containing Arrays of the same object type.
However, when iterated over, it behaves as a single ArrayCollection.
This means, when you alter the source arrays, the DynamicCollection will change also.
I have written the solution twice, once using Arrays and once using ArrayCollections as the elements. If you use the former, you have to call “refresh()” on the collection after updating any of the child arrays to enable databinding.
I’ve found it better to stick to Arrays noting that from Jon Rose’s blog and examples, you lose performance with a high number of ArrayCollections.
Below is the DynamicCollection class and an example implementation.
NOTE: I haven’t had the time to test it out with other ListBase implementations – feel free to comment on any issues you encounter.
(Right-click flash movie to view source).
So, to put my money where my mouth is, I’ve finally starting to approach Silverlight from a Flex perspective.
Personally, I develop in both .NET and Flex/AIR. Last year, I saw this example by Robby Ingebretsen and decided that there was more to Silverlight than meets the eye.
Part One: Basic Layout in Blend 3
I’ve decided to start this series with layout and components. Now, I’m making a few guesses and assumptions as I go, so I encourage anyone who notices discrepancies to comment away.
First off, Download Expression Blend 3 Preview. It’s free until September 09, so go get it. (Blend is actually a WPF application).
Second, create a new Silverlight application.
Now, having a look inside Blend take a gander at the Layout containers:

Layout Containers
Collapsed Visibility
Something to note here too is collapsed visibility. A nice feature of XAML that Flex has yet to implement . Say you have a Flex VBox with 3 buttons and you wanna remove a button, you’d use either a ViewStack or a State, right? (or maybe actionscript if you were keen) - in Silverlight, you can set visibility to Collapse to achieve the same thing.
Anchoring & Margins
Essentially, components can either use a margin to determine how wide and high they are or use alignment + width and height. The latter must be placed in a Grid/ScrollViewer/Border and then using both the width/height and the HorizontalAlignment and VericalAlignment tools to lay them out.
If you opt for the Canvas container instead, you then use the typical top, left and z-index to layout the items.
Attached Backgrounds
Another nice feature is how the background can be easily customised. For example, try out the Gradient tool and apply it to any container (or component for that matter – like shapes, text or buttons).

See the XAML? (switch to Split view). See how applying the Gradient tool to a
This is similar to accessing the graphics property of any UIComponent in Flex. However, the obvious advantage here is how easy Expression tooling makes applying gradients to any object.
The aim of this post is to get an AIR application to take a collection of files dragged n dropped onto it, zip them up on the client, and send them off to the server (ASP.NET).
There are a few things to note here:
Step 1. The Drag & Drop in AIR
This is quite trivial. Allowing the user to drag and drop as many files/folders onto your application.
Client (AIR) code:
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication
nativeDragEnter="onDragEnter(event)"
nativeDragDrop="onDragDrop(event)"
layout="absolute"
xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:Script>
<![CDATA[
import mx.managers.DragManager;
import mx.events.DragEvent;
private function onDragEnter(evt:NativeDragEvent):void
{
//ensure clipboard contains files
if (evt.clipboard.hasFormat(ClipboardFormats.FILE_LIST_FORMAT))
{
NativeDragManager.acceptDragDrop(this);
}
}
private var _filesToUpload:Array;
private function onDragDrop(evt:NativeDragEvent):void
{
_filesToUpload = evt.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
}
]]>
</mx:Script>
</mx:WindowedApplication>
Step 2. Zipping on the client
The nicest solution I could find for compressing files in AIR to ZIP is FZip.
I tried another library, but ISharpLib didn’t like it, it was giving me EOF file header issues in the ZIP decompression.
So the solution is to take the ZIP byteArray and to send it via the lower level URLLoader class.
NOTE: this uses the FileStream.open is sync mode. You could use FileStream.openAsAsync though it would obviously require listening and handling the corresponding events.
Client (AIR) code [URLLoader.load() solution]:
var request:URLRequest = new URLRequest("http://example.com/Handlers/UploadHandler.ashx");
request.method = URLRequestMethod.POST;
request.contentType = "application/octet-stream";
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.addEventListener(Event.OPEN, onFileUploadStart,false,0,true);
//no point listening for progress, because it doesn't work for URLLoader uploads, only downloads
//loader.addEventListener(ProgressEvent.PROGRESS, onFileUploadProgress,false,0,true);
loader.addEventListener(Event.COMPLETE,onFileUploadComplete,false,0,true);
var fzip:FZip = new FZip();
for each (var file:File in model.filesToUpload)
{
var fs:FileStream = new FileStream();
fs.open(file, FileMode.READ);
var data:ByteArray = new ByteArray();
fs.readBytes(data);
fs.close();
fzip.addFile(file.name, data);
}
var bytes:ByteArray = new ByteArray();
fzip.serialize(bytes);
request.data = bytes;
loader.load(request);
What about sending extra parameters?
var request:URLRequest = new URLRequest("http://example.com/Handlers/UploadHandler.ashx?someVariable=" + someVariable);
What about the upload progress bar?
If you need the progress bar, then you’re best option is writing this zip file to the client and uploading that.
This also means that if you have optional parameters, you don’t have to append them to the URL but can send them in the data.
This changes the client code to use File.upload().
Client (AIR) code – [File.upload() solution]:
var params:URLVariables = new URLVariables();
params.someVariable = someVariable;
//add other variables here
var request:URLRequest = new URLRequest(model.UPLOAD_URL);
request.method = URLRequestMethod.POST;
request.data = params;
var fzip:FZip = new FZip();
for each (var file:File in model.filesToUpload)
{
var fs:FileStream = new FileStream();
fs.open(file, FileMode.READ);
var data:ByteArray = new ByteArray();
fs.readBytes(data);
fs.close();
fzip.addFile(file.name, data);
}
//get the zip as a byte array
var bytes:ByteArray = new ByteArray();
fzip.serialize(bytes);
//write the zip to a local file
var fsW:FileStream = new FileStream();
//change "tmp.zip" to a better name
var wFile:File = File.applicationStorageDirectory.resolvePath("tmp.zip");
fsW.open(wFile, FileMode.WRITE);
fsW.writeBytes(bytes);
fsW.close();
//listen to upload events
wFile.addEventListener(Event.OPEN, onFileUploadStart,false,0,true);
wFile.addEventListener(ProgressEvent.PROGRESS, onFileUploadProgress,false,0,true);
wFile.addEventListener(Event.COMPLETE,onFileUploadComplete,false,0,true);
//start the upload
wFile.upload(request);
Step 3. Unzipping on the server
Now, I use SharpZipLib in .NET because it’s Open Source, and because it’s also bundled with WebORB .NET, the remoting gateway that I often use.
If you use the URLLoader.load() option above (from Step 2) – then you must use Request.InputStream to access the parameters
Server (ASP.NET C# Handler – ashx) code: (SharpZipLib extraction)
using ICSharpCodeInternal.SharpZipLib.Zip;
public class UploadHandler : IHttpHandler {
public void ProcessRequest (HttpContext context)
{
String someVariable = context.Request["someVariable"];
ZipInputStream zipStream = new ZipInputStream(context.Request.InputStream);
ZipEntry zipEntry;
while (true)
{
zipEntry = zipStream.GetNextEntry();
if (zipEntry == null)
{
break;
}
//choose location to extract files to
string serverFolder = context.Server.MapPath("~/Uploads/");
FileStream streamWriter = File.Create(( serverFolder + zipEntry.Name));
int size = 2048;
byte[] data = new byte[2048];
while (true)
{
size = zipStream.Read(data, 0, data.Length);
if (size > 0)
{
streamWriter.Write(data, 0, size);
}
else
{
break;
}
}
streamWriter.Close();
}
zipStream.Close();
}
}
If you are using File.upload() on the client
You’re Handler in ASP.NET now will be looking in the context.Request.Files array for the attached ZIP.
Modified Server (ASP.NET C# Handler – ashx) code:
ZipInputStream zipStream = new ZipInputStream(context.Request.Files[0].InputStream);
If you need folder structures
To do ZIP folders, you simply add the folder name before the file when you ZIP:
Modified Client (AIR) code:
fzip.addFile(folderName + "/" + file.name, data);
And then in the server code, you need to create directories if required:
Modified Server (ASP.NET C# Handler – ashx) code:
//existing code
...
string serverFolder = context.Server.MapPath("~/Uploads/");
string dir = Path.GetDirectoryName(serverFolder + zipEntry.Name);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
//existing code
FileStream streamWriter = File.Create(( serverFolder + ze.Name));
...
Recent Comments