Monday, October 19, 2009

Remove all empty XML elements using LINQ

While working on the XamlWriter I had to do some post processing on the generated Xaml. One was to delete all nodes that did not have any attributes or contain any elements. The first pass of removing the empty nodes could generate more empty nodes and hence this problem is recursive in nature.

This was my first attempt
var query = doc.Descendants().Where(c => !c.HasAttributes && c.IsEmpty);
while (query.Count())
   query.Remove();

This could be certainly improved using the .Any operator

var query = doc.Descendants().Where(c => !c.HasAttributes && c.IsEmpty);
while (query.Any())
   query.Remove();

The problem with the above solution(s) is that the query is executed twice, once for the Any/Count method and once for the Remove method. The next approach provided 2x performance gains (in the best case scenario) over the above approach

void RemoveEmptyNodes(XElement root)
{
   var query = root.Descendants().Where(e => !e.HasAttributes && e.IsEmpty).ToList();
   query.Remove();
   if (query.Any())
      RemoveEmptyNodes(root);
}

The reason for the performance improvement is that although both the Any and the Remove operations are executed on the query, the .ToList operator executes and caches the result and hence the query is executed only once.

The concern I have with the above recursive solution is the memory requirement for the local variable query which is of type IEnumerable.

Maybe something like this will help but I don't understand GC (garbage collection) in .NET well enough to recommend this approach

void RemoveEmptyNodes(XElement root)
{
   var query = root.Descendants().Where(e => !e.HasAttributes && e.IsEmpty).ToList();
   query.Remove();
   if (query.Any())
   {
      query = null;
      RemoveEmptyNodes(root);
   }
}

Anyone with better or alternate approaches please post your thoughts as comments.

Friday, October 16, 2009

Silverlight 3 XamlWriter - v0.4 - DataTemplate support

The new version of XamlWriter with DataTemplate support is now available. Check the previous posts for download and usage information.

While it is possible to recreate the DataTemplate it is not possible to recreate ContentTemplate. Hence I couldn't add support for ContentTemplate. There is also support for the Style class but there is an issue with it.

The DataTemplate example

Thursday, October 15, 2009

Silverlight 3 XamlWriter - v0.3 - Storyboard and TransformGroup support

An update every day - Wow! Thought I'd keep the momentum going while I have a liiittle free time. Once it goes on the back-burner, it will lie there to bite the dust!

If anyone has tried the XamlWriter (which I am sure no one has, yet!) it would be clear that it doesn't work for Storyboards and TransformGroups. That is because they are a slightly special case. Why? I'll leave that for some future post. Anyways it's fixed now.

Please check out my previous post for download and usage information.

I also thought I'd take this opportunity to point out some issue that I encountered. If you had read my previous posts on this subject you would know that I used reflection to implement the XamlWriter.

The way to retrieve the properties of an object using reflection is like this -
  PropertyInfo[] props = target.GetType().GetProperties();

I now needed to to check if the property is readonly. The reason for this is that a readonly property cannot be used in Xaml. So I went ahead and used the CanWrite property to check if the property could be written to, like this -
  if (!prop.CanWrite)

But, guess what? It doesn't work in all cases. For example, the IsFocussed property of a Button control returns true for CanWrite. I put the IsFocussed property in the Xaml and it threw an error indicating clearly that this was a read only property.

So there had to be a different way. After all the Xaml parser knows more about readonly properties than the CanWrite property. That is when I discovered the GetSetMethod method on ProperyInfo. This worked wonderfully -
  if (prop.GetSetMethod == null)

Whether this is a bug or some explainable feature, I don't know. Maybe I will post this on the Silverlight.net forums and see if there is an explanation. In the meantime, there is a workaround for me to continue making progress!

The Storyboard and TransformGroup example

Wednesday, October 14, 2009

Silverlight 3 XamlWriter - v0.2

I was just going through the Silverlight.net forums to see if there was any interesting question to answer and I came across a post which had some interesting Xaml content. This used the Accordian control and looked like a good test case so I copied the Xaml to my project and invoked XamlWriter on it.

And...it did not work! That was expected though. I would be very surprised if it did work.

So, back to the drawing board - a few fixes here, a few fixes there, discovered a few more bugs, fixed them, and stopped when I got it to work with the second Xaml test case.

Get the newer version of XamlWriter from here - XamlWriter.dll

The second example

Tuesday, October 13, 2009

Silverlight 3 XamlWriter - A basic implementation

I am sure that anyone who has worked extensively with Silverlight has felt the need for a XamlWriter at some time. I mostly need it for debugging purposes - to see the xaml of the dynamically assembled controls.

I have been taking the cumbersome route of stepping through the control hierarcy using the debugger, but enough is enough! Just takes too much time. It probably is quicker to just write some code which takes in a FrameworkElement and outputs the Xaml representation of it.

I did find 3 resources on the web that would prove useful (or not!)
  1. XamlWriter by Mehran (rambler.elf on the Silverlight.net forums) - A nice simple reflection based approach that would prove the starting point for my project
  2. XamlWriter by the SilverlightContrib team - Did not try this since it is embedded deep in another project. Not sure if this wuld work for me but since I like to have more control I decided to write one myself (based on Mehran's code)
  3. Silverlight Spy - A third party tool that could be used to extract the Xaml of a specific control. Not so useful for me since I need to hook it in my code
So I decided to take Mehran's code and make it work on Silverlight 3. Then I refined it and added some features and refined it a bit more and added some more features and...

It's by no means complete or well tested but if you feel brave enough
  • just download this file - XamlWriter.dll 
  • add a reference to this file from your project 
  • and use the following snippet of code to test it

using projectsilverlight.blogspot.com.XamlWriter;

XamlWriter xamlWriter = new XamlWriter();
string xaml = xamlWriter.WriteXaml(MyControl, XamlWriterSettings.LogicalTree);

Note that XamlWriter uses System.Xml.Linq for some processing so you will find this dll getting added to the xap as well.

XamlWriterSettings has 3 values which can be combined to get different output. The 4 valid combinations are

WriteXaml(MyControl, XamlWriterSettings.LogicalTree);
WriteXaml(MyControl, XamlWriterSettings.LogicalTree | XamlWriterSettings.AllAttributes);
WriteXaml(MyControl, XamlWriterSettings.VisualTree);
WriteXaml(MyControl, XamlWriterSettings.VisualTree | XamlWriterSettings.AllAttributes);
Like I mentioned before - this is not well tested. In fact, the example below is the only case I have tested. I am putting it up nevertheless to get some feedback. If you find that it is not working for a specific case, send me the Xaml/code that it is not working for and I will take a look. At some point in the future, if still relevant, I will open source this code. But now it is closed source for various reasons - the code quality sucks, haven't taken permission from Mehran yet, want better control so that a single codebase gets improved upon rather than each individual fixing it for his/her needs.

Enjoy!

An example

Friday, August 14, 2009

I am available for contract work

It's been a long time since I last put up a post on this blog! I kind of got buried in my work which got more hectic since we had a few layoffs, which is when I finally decided to take a break, after 5 long but incredibly exciting years, and spend some time with my 2 year old daughter. I had an absolutely wonderful time the last few months taking it easy, but now the time has come to get back in the game!

I recently peeked into the MSDN magazine (July edition) and noticed this article - 'Taking Silverlight Deep Zoom to the Next Level' - by Jeff Prosise, and suddenly realized how much I missed doing this Deep Zoom stuff. The first half of his article is similar to some of the code I have on this blog. I was kind of surprised by this since I thought that no one would be interested in reading this stuff because it was so old - so last year! :) Apparently people are still interested in Deep Zoom related articles. I corroborated this by looking at the hits this blog has been receiving and I was surprised that the activity in the recent few months has been more than last year. I thought this was hot last year when we got a glimpse of the hard rock site but I guess lots of developers have been recently getting into Silverlight, especially Deep Zoom related.

Anyways, I am free and passively looking for a contract assignment in .Net, Silverlight etc. I enjoy spending time with my daughter and would like to continue doing that so I am not looking for any assignment that includes travel (minimal travel like a day here and there is fine). So if you have an opening which doesn't include travel and think that I could be a good addition to your team (based on what you see on this blog), give me a buzz and we can chat.

Cheers,

Wilfred
contactwilfred@yahoo.com
Los Angeles, CA