Archive for category XAML

GetObject vs StartObject in System.Xaml

I recently had a question about the differences in StartObject and GetObject in XAML so I wanted to go over it here.

In a nutshell, StartObject means create the object and GetObject means we should call the parent property’s getter to retrieve the value and use that as the instance instead.

StartObject

This is used when we want to create the instance of the XamlType specified.  Normally, this means we just call the default constructor.  In XAML 2006, we could also call TypeConverters with the text specified in the content and also call non-default constructors in MarkupExtensions.

<Button/> – Default constructor

<Brush>Red</Brush> – Calling the TypeConverter

In Xaml2009, we also added support for factory methods and non-default constructors (using x:FactoryMethod and x:Arguments).  (You can also pass arguments into FactoryMethods)

<sys:Guid x:FactoryMethod=”NewGuid”/>

<sys:DateTime>
    <x:Arguments>
        <x:Int32>2010</x:Int32>
        <x:Int32>3</x:Int32>
        <x:Int32>18</x:Int32>
   </x:Arguments>
</sys:DateTime>

Node order dependencies

One of the important things to note though is that because these “construction” directives (Arguments, FactoryMethod, Initialization, PositionalParameters and TypeArguments) come after the StartObject in the node stream, we can’t actually create an object the moment we see the StartObject node.  We have to wait until we see all the construction directives first.  So, the XamlObjectWriter will wait until either 1) we see a start member that’s not a construction directive. 2) see a EndObject (because there are no properties being set. 3) We process a construction directive that results in creating the object.  Initialization & PositionalParameters would trigger construction.

This all means that the XamlObjectWriter has an order dependency on how nodes are passed into it.  While we considered having the XamlObjectWriter buffer and sort things out, we decided against doing that because of performance.  While some XamlReaders like XamlXmlReader could have benefitted from having the ObjectWriter sort, there are other readers like the Baml2006Reader that wouldn’t benefit from this (since the XAML Compiler reorders and optimizes the nodes).  We decided to push requirement of reordering nodes to the XamlReaders of the world since that would make the XamlObjectWriter as fast as possible.

XamlXmlReader reordering

So that means that we had to push the reordering requirement into the XamlXmlReader.  The XamlXmlReader will try its best at reordering as much as possible.  For example, this scenario would be reordered by the XamlXmlReader:

<MyButton Background=”Red” x:FactoryMethod=”CreateInstance” Content=”Click me”>
  <x:Arguments>
    <x:String>Some argument</x:String>
  </x:Arguments>

</MyButton>

The node stream would look something like this:

SO MyButton
  SM FactoryMethod
    V “CreateInstance”
  EM
  SM Arguments
    SO String
      SM Initialization
        V “Some Argument”
      EM
    EO
  EM
  SM Background
    V “Red”
  EM
  SM Content
    V “Click me”
  EM
EO

The XamlObjectWriter would be able to handle this fine since all the Construction directives have been moved forward.  While this works for most scenarios, we can’t reorder everything in the XamlXmlReader (or rather we chose not to).  If you chose to place the construction directive as the last possible property element in the object, we’d have to scan through the entire object (and all its children) before we could know how to create it.  If you did this for the root object, we’d have to buffer the entire document before outputting a single XAML node.  What makes this even worse is that even if there’s no construction directives, we’d still have to buffer the entire document in order to do any processing.  Because of this, we chose to implement a few rules on where construction directives could appear.  All construction directives MUST come before any non-constructor directive property elements.  You can have non-construction directive property attributes before but you can’t have them as property elements.  <Foo Background=”Red” x:FactoryMethod=”bar”/> is fine but

<Foo>
  <Foo.Background>Red</Foo.Background>
  <x:FactoryMethod>Bar</x:FactoryMethod>
</Foo>

is not allowed.  We believe this is a far compromise between needing performance and usability.

GetObject

GetObject is very similar to StartObject except that instead of creating an object, we get the value of the parent property to use as the instance.  So if the XamlObjectWriter sees SO Window, SM Resources, GO, we’ll call the getter on the Resources property and use that instance.  It’s also different from StartObject in that we call the getter immediately and don’t have to wait around for construction directives.  GetObject is currently only used for retrieving collections (or dictionaries) (CLR guidelines recommend that you have read only collection properties).

The rules for whether the XamlXmlReader outputs a StartObject or GetObject are pretty simple. If the first element inside is assignable to the Property, generate a StartObject.  If it’s not, generate a GetObject.  It gets a little more complex if the first child a MarkupExtension though.  Since MarkupExtensions can return objects that could assign to property, we assume that they are value of the property.  For example, in this case

<Window.Resources>
  <StaticResource ResourceKey=Blah”/>
</Window.Resources>

We assume that the StaticResource will return something from ProvideValue that is assignable to the parent property.  You can avoid this by either making the MarkupExtension not the first element or by putting an x:Key on it if you’re inside a Dictionary property.

Tags: , ,

Use XamlReader.Load for WPF XAML (not XamlServices.Load)

While it’s great that we have a common Xaml stack that works across WPF, WF, and WCF, there are some slight differences in the way that WPF loads XAML that doesn’t work with the simple XamlServices.Load API.

 

For WPF XAML, you should use System.Windows.Markup.XamlReader.Load and System.Windows.Markup.XamlWriter.Save.  This will ensure that your XAML will load and save correctly.

 

Here’s a list of some of the special things that XamlReader.Load does: (this isn’t a full list)

  • Enables Journaling (a WPF navigation feature)
  • Sets special attached DependencyProperties on all DependencyObjects (e.g. BaseUri, XmlnsDictionary, XmlSpace etc…)
  • Ignores x:Uid on property elements.  Early in V3 (before we shipped), there was a bug in the UpdateUid build task that put x:Uid on every XML element including property elements.  XAML doesn’t support properties on properties which means that Uid isn’t support on property elements.  We ignored it in V3 and we ignore it in V4 if you use XamlReader.Load (we actually just set XamlReaderSettings.IgnoreUidOnPropertyElements)
  • Wire up events inside of templates and styles
  • Freeze freezables
  • Uses the Wpf XamlSchemaContext (which you can get from System.Windows.MarkupXamlReader.GetWpfSchemaContext())
    • IProvideValueTarget.TargetProperty returns DependencyProperties instead of PropertyInfos.  Binding and DynamicResource require this.
    • There were several other quirks that we added for compat reasons

 

As you can see, most of this stuff isn’t very generic.  It’s pretty specific to WPF and thus we couldn’t justify putting it in the generic System.Xaml parser.

Tags: , ,

XAML Toolkit CTP – November 2009 is now live!

The XAML Toolkit CTP is now live at the code gallery website

Here’s a guide on how to run the rules in FxCop.

Tags: , , , ,

Running FxCop rules against Silverlight or WPF XAML

Read the README that’s included as part of the XAML Toolkit CTP.

The big thing to note is that FxCop 10 Beta 2 does not currently support Silverlight.  You’ll have to use FxCop 1.36 and force it to run in .NET 4 to get things to work for Silverlight.  If you’re running WPF, FxCop 10 should be fine.  (FxCop 10 RC & RTM wills support Silverlight)

After running FxCop, add the XAML Rule

AddRule

Go to the folder where you installed the XAML Toolkit (C:\Program Files\Microsoft XAML Toolkit\) and add Microsoft.Xaml.Tools.FxCop.dll

XamlToolsFxCopdll

You should see all the XAML rules added in the Rules section:

XamlRules

Add your Silverlight/WPF assembly and hit F5 (or Analyze).  You may get a popup about finding System.Windows.dll.  Have it point to C:\Program Files\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0

WPF users can point to PresentationFramework/PresentationCore/WindowsBase in C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0

You may also need to point FxCop towards System.Windows.Controls.dll which can be found in: C:\Program Files\Microsoft SDKs\Silverlight\v4.0\Libraries\Client

SystemWindows

If everything goes smoothly you should see the rules run:

FinalRules

You should be able to do similar things for adding your own custom rules to FxCop as well.

 

 

One of the most common requests I had at PDC was to be able check if your WPF XAML was Silverlight friendly and vice versa.  Over the next few weeks, I’ll try working on some simple rules to validate WPF/Silverlight compatibility and whether you can use the XAML between the two platforms.

Tags: , , , , ,

XAML Toolkit CTP

At PDC, we’re announcing a CTP of the XAML Toolkit.  This should make analysis of XAML for both .NET & Silverlight very easy to do.  We’re adding some preliminary FxCop integration for XAML and allowing you to write your own custom rules.

Our talk will be published here in the near future and you can go through our presentation.

The components that are shipping as part of the November 2009 CTP are:

  • XamlDom – A XAML DOM that is LINQ friendly.  Enables easy static analysis.
  • XAML FxCop integration – A BaseXamlRule implementation that allows you to write custom FxCop rules that target XAML.  We’re also shipping a couple of simple ones including a ValidationRule that will validate your XAML.
  • SilverlightSchemaContext – A XamlSchemaContext that allows System.Xaml to parse Silverlight XAML for tools use. 
  • UISchemaContext – A XamlSchemaContext that allows you to go between .NET & Silverlight XAML.  This allows you to write custom FxCop rules that can be written against one framework but works against both platforms.

I’ll dive into more detail on each of the components in the next few weeks.

Here’s a simple example of going through a document and writing out all the types used in the file:

 

XamlDomObject rootObject = XamlDomServices.Load("Window1.xaml");

foreach (XamlDomObject domObject in rootObject.DescendantsAndSelf())
{
  Console.WriteLine(domObject.Type);
}

 

By calling XamlDomServices.Load, we get a XamlDomObject for the root object in the XAML document.  From there, we can call DescendantsAndSelf on the root object which returns an IEnumerable<XamlDomObject> that you can loop through.

Here’s another example.  Imagine you want to set Background on every single Control in your document but only the ones that don’t already have one set currently:

 

XamlDomObject rootObject = XamlDomServices.Load("Window1.xaml");
foreach (XamlDomObject objectNode in
        from control in rootObject.DescendantsAndSelf(typeof(Control))
        where !control.HasMember("Background")
        select control)
{
  objectNode.SetMemberValue("Background", "Red");
}
XamlDomServices.Save(rootObject, "NewFile.xaml");

Like before, we’re calling DescendantsAndSelf but this time we’re passing in typeof(Control).  This will limit it to return only things that are assignable to Control.  We’re also using LINQ to be able to get the XamlDomObjects we want faster.  After we call DescendantsAndSelf, we’ll then call ‘where !control.HasMember("Background")’.  This limits it to only objects that don’t have a member called "Background" set on it currently. We select only those Controls.  We then call SetMemberValue("Background", "Red") to set the background property to Red.  Finally, we call XamlDomServices.Save to save the file back out to XAML.  This is a pretty simple example of a transformation but we can do much more complex transformations with our XamlDom.

Over the next few weeks, I’m going to try to post a couple of examples of using the XamlDom and FxCop.  If you have any requests, please feel free to leave a comment/message.

The XAML Toolkit CTP can be found here.

Tags: , , ,

PDC 2009 – XAML Futures in Microsoft .NET Framework, Microsoft Silverlight and Tools

I’m giving a talk with Rob Relyea at PDC 2009.  The talk is in Hall F on Thursday at 1:45 PM.  Here’s the excerpt for the talk:

Dive into advances in XAML happening in future versions of .NET, Silverlight, Microsoft Visual Studio, and Microsoft Expresssion Blend. Hear about XAML parsers, markup compilers, analysis, transformations, localization, and tools. Dig even deeper into performance optimizations possible in .NET, and explore possibilities with a XAML DOM and DLR based scripting.

Link to the talk

Tags: ,