Delay's Blog is the blog of David Anson, a Microsoft developer who works with C#, XAML, HTML, and Azure.
At the bottom of the post on migrating SimpleSilverlightXpsViewer to Silverlight Beta 2, I hinted at "a cool, practical, relevant use of SimpleSilverlightXpsViewer that I'll be able to share sometime soon". "Soon" is now, and I'm happy to point readers at the "Read about Silverlight in XPS" post by Laurence Moroney in which he uses an adaptation of my viewer for showcasing the first three chapters of his new book, Introducing Microsoft Silverlight 2.
Here's what it looks like - just click the image to try it out for yourself:
In addition to modifying the sample for his purposes, Laurence went further and integrated mouse wheel support: zooming in and out is as easy as spinning the wheel. I've got to agree that it's a very nice usability improvement!
Since releasing the XPS Viewer Sample, a few people have expressed interest in repurposing the code for something similar. Kudos to Laurence for doing a great job with this - and I love that it's being used to help spread the word about Silverlight! :)
A few days ago the Silverlight team released a minor update to Beta 2, changing the version number from 2.0.30523.6 to 2.0.30523.8 in the process. The version number is part of Silverlight's install path and SilverlightDefaultStyleBrowser (background reading available here, here, and here) didn't know to look in the new location when automatically importing Styles. As such, when run on machines with the updated Silverlight bits, the list was missing Styles for the core controls like Button, ListBox, etc.. (As I discovered for myself a short while ago when I tried to use SilverlightDefaultStyleBrowser!)
I've just updated SilverlightDefaultStyleBrowser to look in all subdirectories of %ProgramFiles%\Microsoft Silverlight when starting up. Not only does this fix the current problem, but it should save me from having to do anything next time there's an update, as well! :)
The version number of SilverlightDefaultStyleBrowser always appears in the window's title and the latest release number is 1.0.3123.31689. (Note: I haven't updated the screen shot below which shows the introductory version number.) If installed via ClickOnce, the application should automatically prompt you to upgrade once it detects the update (which typically happens after running the app once or twice). If you're using the standalone EXE, you'll need to update manually.
Click here or on the image above to install SilverlightDefaultStyleBrowser via ClickOnce with automatic updating.
Click here to download the standalone SilverlightDefaultStyleBrowser executable and source code in a ZIP file.
I'm sorry for any trouble the recent Silverlight upgrade may have caused! The good news is that this particular problem shouldn't happen again. :) And if it does, you can always use the "Add Assembly" button to manually import Styles from any file(s) you want until I get around to fixing things.
When putting content on the web, it's important to get that content to the user as quickly as possible. In general, reducing the amount of data users need to download is a big step in the right direction. As such, the XAP packaging format used by Silverlight 2 wraps everything in a single, compressed archive file that's browser-friendly. At the moment, the compression for XAP files in Beta 2 is not as efficient as it could be, and XAP files tend to be a bit larger than necessary. Until this is addressed in a future release of the Silverlight tools, here is something that's almost as good. :)
XAP files are really just standard ZIP files with a different extension, so we can use ZIP-file tools to improve the XAP situation quite easily. I wrote a simple batch file named XapReZip.cmd (contents below) that can be added to a Visual Studio 2008 Silverlight project to automatically re-compress the project's XAP file more efficiently. All you need to do is add a single command to your project's post-build events (detailed below) and from then on all your XAP files will be even smaller and quicker to download!
To demonstrate its effectiveness, I've run XapReZip against three test applications, two simple demonstration applications of mine, and the current version of two professional-grade applications you're probably already familiar with. The table below shows the starting XAP file size, the size after running XapReZip, the difference between the two, and the percent difference. (All sizes are in bytes.)
Basically, you can expect to see about a 22% reduction in size for XAP files in general - slightly less for code-intensive XAPs and potentially much more for larger, richer XAPs. For example, it looks like Line Rider could shave a quarter of a megabyte off its download size without breaking a sweat - which is even more compelling given how easy it would be! :)
The complete code for XapReZip.cmd is below. As written, XapReZip assumes that Zip.exe and UnZip.exe will be located in the same directory as XapReZip.cmd (this is easy to change) and that all of the files that are part of the XAP are available in the same directory as the XAP file itself (which just happens to be true after compiling with Visual Studio or MSBuild). For the purposes of this demonstration, I've used Zip 2.32 and UnZip 5.52 from the Info-ZIP group because they're free and have a nice license. Of course, you can use whatever tools you're most comfortable with.
@REM XapReZip - Recompresses XAP files smaller
@REM Invoke as a VS post-build event like so:
@REM C:\XapReZip\XapReZip.cmd $(TargetName).xap
REM Define paths to zip.exe and unzip.exe
REM Define paths for intermediate files
REM Output a banner message
echo XapReZip: %XAP%
REM Change to XAP file directory
REM Create new XAP file with maximum compression
%UNZIPEXE% -Z -1 %XAP% | %ZIPEXE% -@ -9 -X %XAPZIP%
REM Abort if something went wrong
if ERRORLEVEL 1 goto :DONE
REM Replace original XAP file with smaller one
copy /y %XAP% %XAPBAK% > NUL
copy /y %XAPZIP% %XAP% > NUL
REM Output a success message
echo XapReZip: Success
REM Restore previous directory
Adding XapReZip to a Silverlight Project in Visual Studio is easy. Just go to the Project menu, choose Properties (it's the last item), switch to the Build Events tab, and set a post-build event command line like this: C:\XapReZip\XapReZip.cmd $(TargetName).xap. Here's what it looks like in Visual Studio:
After you've set that one command, you can forget about it - XapReZip will go to work every time you recompile the application and you'll be able to run and debug it just like always. Except a little smaller. :)
So if you're eager to keep your Silverlight applications as lean as possible, consider adding XapReZip to your project. It'll probably be the easiest 22% savings you get all day!
In the introductory post for LayoutTransformControl, I showed a trivial use case to demonstrate the need for LayoutTransform in some scenarios. I also noted that Silverlight 2 supports only RenderTransform, but went on to demonstrate how it was possible to use RenderTransform to get LayoutTransform behavior. I described how my LayoutTransformControl sample did just that, but implemented only RotateTransform functionality for its initial release. My impression then - as now - is that rotation is easily the most common use of LayoutTransform. However, there are plenty of scenarios where the other Transform subclasses (scale, skew, matrix, etc.) are required, and I wanted to have a solution for them as well.
So I've added full support for arbitrary transformations to LayoutTransformControl along with updating it for Beta 2! (The complete implementation - along with demo and test applications - can be found in LayoutTransformControl.cs in the attached ZIP.)
Where you might previously have written:
<TextBlock Text="I am rotated 15 degrees!"/>
You now write:
<TextBlock Text="I am rotated 15 degrees!"/>
Wait a second! That's more typing than before - why is this an improvement? Well, because you can also do this (just as you would on WPF):
<ScaleTransform ScaleX="1.5" ScaleY="2.5"/>
<TextBlock Text="I am a little wider and a lot taller!"/>
<TextBlock Text="I am flipped horizontally!"/>
Or even this:
<ScaleTransform ScaleX="1.5" ScaleY="2.5"/>
<TextBlock Text="I am all of the above - and tilted, too!!"/>
So maybe it's a bit of an improvement, after all... :)
Naturally, I updated my sample application to show off the new capabilities:
And I updated my cross-platform test suite as well (here's the WPF version):
LayoutTransformControl should now be just as powerful as WPF's LayoutTransform is. Your application can take advantage of complete LayoutTransform functionality today - even though the Silverlight platform still doesn't officially support LayoutTransform!
The examples above assume the "local" namespace prefix has been mapped to an assembly containing the LayoutTransformControl implementation:
My goal with LayoutTransformControl has always been to address a perceived need. It began life as a bit of an experiment, but by now I've become rather fond of the solution and plan to incorporate it into projects of my own. I hope that if you have a need for LayoutTransform behavior in Silverlight, you'll consider LayoutTransformControl, too!