Using LINQ To XML on XAML files.

10. March 2011 22:17

XML isn't new, it's been around for quite awhile, and will most likely be around for awhile longer.  The basic concept of nodes and attributes has been used in a lot of different areas of design in an effort to bring uniformity.  Admittedly in the past, I wasn't to thrilled about dealing with some of the nastier XML documents, but with the arrival of LINQ to XML, me and XML became friends again.

 

Looking at an XAML file, we can see that essentially it is just namespaced XML.  It can be loaded an parsed like any other XML document.  Here I have an example of a exported canvas from Expression Design.

 

<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="LinqToXaml" Width="3600" Height="3600" Clip="F1 M 0,0L 3600,0L 3600,3600L 0,3600L 0,0">
	<Canvas x:Name="Layer_1" Width="3600" Height="3600" Canvas.Left="0" Canvas.Top="0">
		<Path x:Name="Path" Width="1361" Height="1371" Canvas.Left="989.5" Canvas.Top="899.5" Stretch="Fill" StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FF451616" Data="F1 M 1670,900C 1795.22,900 1912.53,934.093 2013.28,993.567C 2214.72,1112.47 2350,1332.82 2350,1585C 2350,1828.51 2223.87,2042.34 2033.82,2163.81C 1928.62,2231.06 1803.82,2270 1670,2270C 1294.45,2270 990,1963.32 990,1585C 990,1490.42 1009.03,1400.32 1043.44,1318.37C 1146.67,1072.51 1388.33,900 1670,900 Z "/>
		<Path x:Name="Path_0" Width="968.593" Height="1018.48" Canvas.Left="2567.52" Canvas.Top="408.874" Stretch="Fill" StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FF9F0E0E" Data="F1 M 3050,410C 2570,600 2560,990 2570,1010C 2580,1030 2840,1130 2940,1300C 3040,1470 3300,1420 3300,1420L 3400,1050C 3400,1050 3660,950 3460,730C 3260,510 3050,400 3050,410 Z "/>
	</Canvas>
</Canvas>

So in the above file we have a Canvas object as a container, and it contains a Canvas with some basic size attributes. That canvas then contains two path objects that  I drew while in Expression Design.  So lets drop a lot of the fluff and just get down to how we actually get to the values of this XAML file.  Use whatever platform your comfortable with, console application, web site, or a LINQPad type program.  First thing to do is make sure you have access the the xml objects were going to use.

using System.Xml.Linq;

 

 Now we need to load our xaml file. The XDocument object handles this for us nicely in one handy line of code.

 

XDocument xDoc = XDocument.Load("C:\\LinqToXAML.xaml");

 

So, the XDocument.Load method brings in for us our entire document, and if you take the xDoc object and output it as a string, you'd have your entire Xaml file at this point.  But, accessing individual values in the XAML file requires accessing it via the namespaces attached to it.  If you look at the root canvas, you'll see the namespaces listed as attributes.

 

<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="LinqToXaml" Width="3600" Height="3600" Clip="F1 M 0,0L 3600,0L 3600,3600L 0,3600L 0,0">

 

The first name space starts with xmlns and this is the document namespace, the second namespace is has the "x" prefix to identify it, and anything that lives in this namespace will use that "x" prefix to identify that it belongs to that namespace.

 

Lets add get our XNamespace object declared and initialize it's value.

 

XDocument xDoc = XDocument.Load("C:\\LinqToXAML.xaml");
XNamespace xspc = xDoc.Root.Name.Namespace;
XNamespace otherSpc = "http://schemas.microsoft.com/winfx/2006/xaml";

This is a handy way to make the root name space available to us in code as Is shown above by accessing the namespace property of the root, and for example you can also see how to hard-code the namespace if needed.  With these namespaces setup, were now ready to write our LINQ statements to access our XAML.

XDocument xDoc = XDocument.Load("C:\\LinqToXAML.xaml");
XNamespace xspc = xDoc.Root.Name.Namespace;
XNamespace otherSpc = "http://schemas.microsoft.com/winfx/2006/xaml";

var theVals = from x in xDoc.Descendants(xspc + "Canvas")
				select x.Elements();

This query isn't very good, because it'll give us duplicate data, but the main point to see is that when specifying the descendants we want, we specify the root namespace and join it to the Canvas object we wanted to look for.  This is the basic concept of how we access namespaces with LINQ to XML.

Lets start to refine our query a bit and return only our Path Objects.

XDocument xDoc = XDocument.Load("C:\\LinqToXAML.xaml");
XNamespace xspc = xDoc.Root.Name.Namespace;
XNamespace otherSpc = "http://schemas.microsoft.com/winfx/2006/xaml";

var theVals = from x in xDoc.Descendants(xspc + "Canvas")
		select x.Elements(xspc + "Path");

 Now were filtering our query to say only give me the path elements, again when accessing the path element, we include our root name space declaration.  But what if we want to access the Name attribute in this xaml file which happens to be in a different namespace.  We extend our query and include the other namespace.

XDocument xDoc = XDocument.Load("C:\\LinqToXAML.xaml");
XNamespace xspc = xDoc.Root.Name.Namespace;
XNamespace otherSpc = "http://schemas.microsoft.com/winfx/2006/xaml";

var theVals = from x in xDoc.Descendants(xspc + "Canvas")
		select x.Elements(xspc + "Path").Attributes(otherSpc + "Name");

 The other name space is used because that attribute is prefixed by the "x" namespace.  Do we have to use the root namespace though when we access the other attributes that are not in the "x" namespace? No.

XDocument xDoc = XDocument.Load("C:\\LinqToXAML.xaml");
XNamespace xspc = xDoc.Root.Name.Namespace;
XNamespace otherSpc = "http://schemas.microsoft.com/winfx/2006/xaml";

var theVals = from x in xDoc.Descendants(xspc + "Canvas")
		select x.Elements(xspc + "Path").Attributes("Data");

As you can see, when we access the Data attribute, of our Path object, we didn't need to specify the namespace like we did when accessing the object itself. Obviously I haven't provided the output results of these queries, but I encourage you to use whatever your tool of choice is and try this out for yourself.

 

In our last query, we accessed the Data property of a path object.  If we wanted to find a particular path object, we could of put in a where clause to our query and specified the name of the path object, and then taken it's "Data" values and manipulated it as we see fit. 

Designing for Silverlight.

8. March 2011 17:23

When developing for Silverlight or WPF based applications, like anything else, there is a lot of tools and information out there to assist you in the development process.   Microsoft has made quite a few tools to help us in these endevours, among those tools, that' I'd like to discuss, is Expression Design, and Expression Blend.

 

Some people would say "well duh", obviously you can use those, and talk about them in great detail.  For some people it's not quite so obvious where to start at, and when.  Perhaps they stumbled upon a tutorial that shows them how to perform one function in Blend, and then another tutorial showing the same thing in Visual Studios.   None of these even mention bothering to use Expression Design....   so when and why would we use one tool over another.

 

Expression Blend is a powerful tool, and a lot of tutorials will lead you toward it, but what is the tool essentially? To me, it's a layout manager, control designer, and animation studio.  That's my own personal definition of it.  Can you do more then that in it? Yes, but is it ideal for more then that? In my opinion, not really.  When I'm writing complicated code, I'd prefer to use visual studios. I'm not going to define a C# double animation in Expression blend, I'm going to code it in VS.  But will I write a storyboard or state in Expression Blend? yes, preferably every time if I can pull it off.

 

So, where does design come in? Many of you may know, that you can export design as a silverlight canvas or WPF canvas.  What does this accomplish for you?  A lot if you really take an open-minded look to it.  The drawing tools in design are obviously superior to that of Blend, and essentially whatever you can draw in design can be exported to a canvas.

 

So lets actually think about leveraging the design abilities of Expression design and draw UI that throw out the normal squares, rectangles and circles....Lets make some crazy shapes that bring us interfaces that break the norm.   And when designing these interfaces think of the animations you can use against them.  You can draw a bunch of wonky shapes in expression design..apply gradients.....whatever you can think of, and then export these objects as a canvas...open it in expression blend, and have an animation field day with them.

So great, were using design to make really unique objects that were exporting, and then animating in blend.  What else can we do with Design and the canvas export?  Well what is XAML in it's basic form? It's namespaced XML.  You can take Linq to Xml and iterate through any XAML so long as you load your namespaces correclty....Linq to XML and XAML will be saved for another blog post in the future.

Another thing to let your mind rumble on.... If I'm using Design to make objects, which in the end have paths and coordinates, and I"m parsing it with Linq to XML, what can I do with those path objects?  Think Sql 2008 Geomertry types...and equating images to a database....yeah more on that in the future. 

 

About the author

My name is Brian, I'm A .NET programmer for Hard Rock. Causing trouble one line of code at a time.

Month List