Wednesday, July 30, 2008

Windows Presentation Foundation, Logical and Visual Trees

In this post, we look at the element trees that are generated at runtime in a WPF application known as the Logical Trees and Visual Trees. For a detailed and accurate content, refer to this MSDN Link.

WPF uses several tree structure metaphors to define relationship between program elements. These structures help developers directly manipulate the elements after the tree is rendered. The documentation talks about trees as

   1: The primary tree structure in WPF is the element tree. 


   2: If you create an application page in XAML, then the tree structure is created based on the nesting relationships of the elements in the markup. 


   3: If you create an application in code, then the tree structure is created based on how you assign property values for properties that implement the content model for a given element. 


   4: In Windows Presentation Foundation (WPF), there are really two ways that the element tree is processed and conceptualized: as the logical tree and as the visual tree.




The logical tree exists so that the content models can readily iterate over their possible child elements which makes the content models extensible. Anyway, the logical tree can be viewed as tree representation of the elements that are created just when the application starts. It is like a Tree-ized version of the XAML document(if there is one that is used). Resources are resolved using logical trees by first looking for a resource specified in the requesting element and then the parent elements.



The Visual Tree describes the structure of the visuals represented by the Visual class. A template for a control defines the visual for that control and this is included in the Visual Tree. It also includes the object that are added at runtime. The visual tree gives control over low-level drawing in case it is required for optimization purposes.



In the subsequent sections, we look at how both Logical Tree and Visual Tree are binded to TreeView control in the WPF. So to get started, first lets look at the XAML for the Tree control we are using for the Visual Tree.





   1: <TreeView Name="VisualTree" Grid.Column="1" Grid.Row="0" Background="AliceBlue">


   2:                 <TreeView.ItemTemplate>


   3:                     <HierarchicalDataTemplate ItemsSource="{Binding Children}">


   4:                         <ContentPresenter Content="{Binding Name}"/>


   5:                     </HierarchicalDataTemplate>


   6:                 </TreeView.ItemTemplate>


   7: </TreeView>




TreeView has an ItemTemplate property which can be customized to define the appearance of the elements in a tree. We must add a DataTemplate to this ItemTemplate property. We chose the HierarchicalDataTemplate in this case where define how each element in the hierarchy should be displayed. More about hierarchical data templates would be presented in the later posts. This also covers the data binding expressions in WPF. In line 3, when we said ItemsSource = {Binding Children}, the framework looks for Children (which is a collection) in the DataContext of the TreeView or its parent. So if treeview's Datacontext property is set to "X", then ItemsSource would be X.Children. For each child in the Children, it is rendered using ContentPresenter where the content is taken from the child's Name property.



So this treeview code should be something like this :





   1: var some_tree; //some_Tree has children property


   2: visualTree.DataContext = some_tree;




The actual code we used in the BuddiPad is shown below.





   1: private void DumpVisualTree ( DependencyObject p )


   2: {


   3:             VisualTree.ItemsSource = new VisualTreeItem ( p ).Children;


   4: }




Notice that we used ItemsSource property instead of DataContext property. So what is the difference between these two? The details would be covered in the Data Binding segment of the talk. Note that VisualTree.DataContext would not work in this case.



The code for the VisualTreeItem class is shown below. It is very simple, recursive and straightforward.





   1: /// <summary>


   2:     /// When we build a Visual Tree to be displayed in a TreeView, this class forms the basis of the TreeViewItems.


   3:     /// </summary>


   4:     public class VisualTreeItem


   5:     {


   6:         /// <summary>


   7:         /// The _element is the Dependency Object whose treeview data item is this instance.


   8:         /// </summary>


   9:         private DependencyObject _element;


  10:  


  11:         /// <summary>


  12:         /// This is the list of children that the _element has.


  13:         /// </summary>


  14:         private List<VisualTreeItem> _children;


  15:  


  16:  


  17:  


  18:         /// <summary>


  19:         /// Initializes a new instance of the <see cref="VisualTreeItem"/> class.


  20:         /// </summary>


  21:         /// <param name="dop">The Dependency Object/UI element</param>


  22:         public VisualTreeItem ( DependencyObject dop )


  23:         {


  24:             _element = dop;


  25:         }


  26:  


  27:         /// <summary>


  28:         /// Gets the children.


  29:         /// </summary>


  30:         /// <value>The children.</value>


  31:         public List<VisualTreeItem> Children


  32:         {


  33:             get


  34:             {


  35:                 if (_children == null)


  36:                 {


  37:                     //initialize the list with capacity expected as the number of children


  38:                     _children = new List<VisualTreeItem> ( VisualTreeHelper.GetChildrenCount ( _element ) );


  39:                     for (int i = 0; i < VisualTreeHelper.GetChildrenCount ( _element ); i++)


  40:                     { //for each children in the VisualTree for that dep object where each child is a Dep Object.


  41:                         _children.Add ( new VisualTreeItem ( VisualTreeHelper.GetChild ( _element, i ) ) );


  42:                     }


  43:                 }


  44:                 return _children;


  45:             }


  46:         }


  47:  


  48:         public string Name


  49:         {


  50:             get


  51:             {


  52:                 FrameworkElement fe = _element as FrameworkElement;


  53:                 if (fe != null && !String.IsNullOrEmpty ( fe.Name ))


  54:                 {


  55:                     return Type + ":" + fe.Name;


  56:                 }


  57:                 else


  58:                 {


  59:                     return Type;


  60:                 }


  61:             }


  62:         }


  63:  


  64:         public string Type


  65:         {


  66:             get


  67:             {


  68:                 return _element.GetType ( ).Name;


  69:             }


  70:         }


  71:  


  72:  


  73:     }




The code is heavily adapted from Kevin Moore Bag-o-Tricks but its the same tree code that I have written numerous times for different projects. The heart of this implementation is usage of VisualTreeHelper class. The recursive part of it is in the Children property. The Logical Tree could be dumped in a similar fashion but using LogicalTreeHelper class.



So far, most of the work involved in getting the BuddiPad running has been covered. Now in the next part, we look at other WPF topics that are scheduled for the talk. In the next post, we compare WinForms with WPF in detail.

Monday, July 28, 2008

Getting started with Windows Presentation Foundation

The following post describes the first section of my future talk on "Windows Presentation Foundation". Given below is the list of topics/concepts this post covers:




  1. Lifecycle of a WPF application


  2. What are the WPF-like applications possible today?


  3. How to load XAML at runtime?


  4. Working with objects loaded from XAML at runtime?


  5. How to obtain XAML from objects?


  6. Some tools of trade.



Lifecycle of a WPF application 



Leaving the long stories of how great WPF is and what WPF is useful for, we directly jump into the lifecycle of a WPF application with the assumption that readers knows what WPF is mainly used for - generating data-driven windows application with great User Experience that could easily be achieved.



As we create a new WPF application project from Visual Studio, we get a bunch of different files. The article at http://wpfwonderland.wordpress.com/2008/07/16/understanding-the-xclass-attribute-and-visual-studio-2008/ provides a details description of what happens at compile time during a wpf application build. To summarize it in my own way, let us first look at the files generated with an empty WPF application project.



 



empty wpf project



The App.xaml is the entry point file whose contents are like shown below





   1: <Application x:Class="EmptyWPF.App"


   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"


   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"


   4:     StartupUri="Window1.xaml">


   5:     <Application.Resources>


   6:          


   7:     </Application.Resources>


   8: </Application>




Just like in the ASPX where the markup has a corresponding code-behind, WPF applications uses a similar partial-classes strategy where a code-behind file is linked to a XAML using x:Class attribute. The StartupUri attribute indicates the page the application should first show as the application is launched. Now if we look at the Window1.xaml (it has a corresponding Window1.xaml.cs)



An empty Window1.xaml is added to the application project whose XAML is shown below.





   1: <Window x:Class="EmptyWPF.Window1"


   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"


   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"


   4:     Title="Window1" Height="300" Width="300">


   5:     <Grid>


   6:         


   7:     </Grid>


   8: </Window>




Again, notice the x:Class attribute pointing to the  code behind file. Now let us add a button that displays Hello World! and to the click event, we display another message box that shows your name.



A button in XAML is as shown.





   1: <Button x:Name="btnDemo">This is the buttons' content</Button>




There are numerous ways in which a button's content is set. Shown below is a couple of other ways.





   1: <StackPanel>


   2:         <Button x:Name="btnDirect">This is the buttons' content</Button>


   3:         <Button x:Name="btnContentProp" Content="Set from Content Property"/>


   4:         <Button x:Name="btnSetUsingAttachedProperty">


   5:             <Button.Content>Set using Attached Property</Button.Content>


   6:         </Button>


   7:         <Button x:Name="btnFullyQualifiedButtonProperty" Button.Content="Fully Qualified Setter"/>


   8: </StackPanel>




Also shown is a Layout which specifies the way the buttons are to be displayed. In layman terms, layout is a container with a specification on how its contents are laid out. Some of the layouts we commonly see are StackPanel, Grid, DockPanel. We look at layouts in more detail in the next segment of the talk.



Now when we compile the application project, the XAML file is compiled into a BAML (Binary Application Markup), stored as a resource inside the assembly. Also added is a .g.cs file which contains a partial class for that xaml file code-behind which hooks up the code with the XAML. There is a IConnect() method inside the generated .g.cs file which performs this form of binding the code with markup, thereby allowing the objects to react to events. These intermediate files can be found in the "obj" directory of the project folder. Note that the msbuild uses PresentationBuildTasks.dll to automate this codegeneration and XAML to BAML conversion process.



As a proof that the BAML file is embedded into the assembly as a resource, we use Reflector to examine the assembly. Note that the Reflector does not diassemble the BAML and instead we can use a BAMLViewer like add-on to view the BAML as XAML.



image



 



Notice the EmptyWPF project contains the BAML files as resources. Also shows the BAML viewer in use.



When the application is run, the CLR delegates the control to the PresentationFramework which creates an appropriate host window which renders the UI that is taken from the BAML. In order to do this, the Presentation Framework generates an object graph from the BAML (also the visual and logical trees, covered later). Please observe a portion of the call-stack for the EmptyWPF application we created shown below.





   1: PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window) Line 1901 + 0x18 bytes    C#


   2: PresentationFramework.dll!System.Windows.Application.Run(System.Windows.Window window) Line 260 + 0x9 bytes    C#


   3: PresentationFramework.dll!System.Windows.Application.Run() Line 222 + 0x9 bytes    C#


   4: EmptyWPF.exe!EmptyWPF.App.Main() + 0x4c bytes    C#




It is the PresentationFramework that takes care of creating the Window and running the application with a certain lifecycle (Like raising the Startup events, etc.)



WPF application types and wpf-ish applications



XBAP - Xaml Browser Applications, also known as XBAPs are full-fledged WPF applications that are hosted inside a browser. As with the case of other such applications (like flash and applets), XBAPS runs in a restricted sandbox environment, thereby are limited in certain functionality. When an XBAP is built and is ready to be deployed, the .exe, .manifest and .xbap files should be copied into the directory we wish to publish the application in. It is similar to a Click-Once application except that the .xbap is used instead of .application. Using Visual Studio publish wizard simplifies the deployment issues and we could later copy the files published to a different location. Few configuration settings are to be made to the server hosting the application - application mime-types shown below are to be registered within the server.





   1: MIME Type                    Extension 


   2: ication/manifest             .manifest 


   3: ication/x-ms-xbap            .xbap 


   4: ication/octet-stream         .deploy 


   5: ication/x-ms-application     .application 


   6: ication/vnd.ms-xpsdocument   .xps 


   7: ication/xaml+xml             .xaml 




One could set the trust levels of an XBAP application using visual studio project properties window. Some other restrictions in XBAP is that they cannot create objects of type Window or NavigationWindow (thereby no pop-ups or dialog boxes). They have the HostInBrowser property set to true inside the msbuild file.



A Xaml file could also be viewed directly inside a browser. When you open IE and open the XAML file, it renders the output on the IE window. The presentation framework, in this case would not create a NavigationWindow or a Window to host the XAML content instead uses the browser as a window.



Other WPF-ish application are the Silverlight applications. As of now, the talk might not constitute Silverlight content and instead if time permits, few sections of Silverlight would be posted on my blog.



Loading XAML at runtime



We now look at how XAML could be loaded at runtime. As an example to demonstrate the api and its usage, a simple XamlPad like application is developed the source of which would be posted online here. In the last section of this post (Tools of Trade), we present few tools that helps learn WPF and until then just understand that XAML pad is a XAML editor that can be used to write/learn to write XAML. You can access XAMLPad by typing "xamlpad" in Visual Studio Command Prompt.



So the requirement for our own xaml pad is that the application should be able to first read XAML written by the user, validate it and then convert it into BAML and show the output on a component inside the window. Consider the case where the user has entered just the XAML for a Label which contains a button whose content instead contains a checkbox (the motto of WPF was to enable a content element to contain anything include other controls, media, what not!). The Xaml would look as





   1: <Label   Name="lblWithButtonAsContent"


   2:          Width="80"


   3:          Height="50"


   4:          Background="Red"


   5:          Padding="10">


   6:     <Button Name="btnWithCheckBoxContent">


   7:         <CheckBox>Wow!!</CheckBox>


   8:     </Button>


   9: </Label>




At the time we render this XAML, we first need to specify the loader class we use about the schema that the XAML entered uses. So we need to use .NET XML API to add namespaces. We could add namespace to each of the elements in the XAML or just add it to the root element. Shown below is the code that adds the following namespaces





   1: private string xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";


   2: private string xmlns_x = http://schemas.microsoft.com/winfx/2006/xaml;




The code shown below creates an XmlDocument from the XAML entered and then it adds the namespaces if required.





   1: private XmlDocument GetXamlDoc()


   2: {


   3:            ///Xaml is XML. So we load the XAML as an XmlDocument.


   4:            /// The reason XmlDocument is used instead of XDocument is that we would like to add namespaces


   5:            /// so that the parsing is performed without issues. 


   6:            XmlDocument xdoc = new XmlDocument ( );


   7:            xdoc.LoadXml ( txtCode.Text ); //txtCode.Text contains the XAML


   8:  


   9:            ///We need to add the presentation framework namespace as well as the XAML namespace.


  10:            ///This way a <Button> like WPF objects would be properly identified.


  11:            if (string.IsNullOrEmpty ( xdoc.DocumentElement.GetAttribute ( "xmlns" ) )) xdoc.DocumentElement.SetAttribute ( "xmlns", xmlns );


  12:            if (string.IsNullOrEmpty ( xdoc.DocumentElement.GetAttribute ( "xmlns:x" ) )) xdoc.DocumentElement.SetAttribute ( "xmlns:x", xmlns_x );


  13:            return xdoc;


  14: }




Once a valid XAML document is ready, we now convert this Xaml into object and set it to the Content Property of a Content Element (a button or a frame). In the sample application, we use a frame.





   1: private object GetUIFromXaml ( )


   2: {


   3:             XmlDocument xdoc = GetXamlDoc();


   4:  


   5:             ///Now we are done with modifications, so we need an XmlReader. In this case, we use a XmlTextReader


   6:             /// We build a StringReader on the updated xml.


   7:             XmlTextReader xmlReader = new XmlTextReader ( new StringReader ( xdoc.OuterXml ) );


   8:  


   9:             ///The above code is all the ground work needed to successfully load Xaml at runtime.


  10:             ///The  XamlReader.Load() does the trick here. It compiles the Xaml into BAML and then builds the Object graph.


  11:             /// At the sametime, both the Visual Tree as well as the Logical Tree is constructed.


  12:             return XamlReader.Load ( xmlReader );


  13: }




The key is the XamlReader.Load() method which is given the XmlReader object (to the Xaml Code). It returns an object which could then be set to the content property.



Working with objects loaded at runtime from a Xaml file



Now that we are ready to load UI from a XAML file at runtime, we might want to see if we can attach events on these objects. Yes, we could attach events such as Click (for button) to these objects but is not as straight-forward. The code shown below does exactly what we are talking about.





   1: private void TestEvents ( DependencyObject dependencyObject )


   2: {


   3:     ( dependencyObject as FrameworkElement ).MouseMove += 


   4:                     new MouseEventHandler ( Page1_MouseMove );


   5: }


   6:  


   7: //invoked from Parse() method in the sample


   8: private void Parse()


   9: {


  10:     //code missing ...


  11:                object obj = GetUIFromXaml ( );


  12:                TestEvents ( obj as DependencyObject );


  13:     //code missing ...


  14: }


  15:  




Getting XAML from an object



XamlReader is used to read Xaml and convert the XAML into objects. There is a XamlWriter which does exactly the opposite. Given an object, XamlWriter can generate the corresponding XAML for that object. Shown below is the code that does that. Note that this does not work in the XBAP due to limitations on Reflection (considered as a security breach).





   1: public void SetXamlToTheCenterElement ( )


   2: {


   3:         lblCenter.Content = new TextBox ( )


   4:                                 {


   5:                                      Text = XamlWriter.Save ( this ),


   6:                                      Width = 200,


   7:                                      Height = 200,


   8:                                      TextWrapping = TextWrapping.Wrap


   9:                                  };


  10: }




The output looks like the one shown below.



image 



The XAML for the above window is simple and is shown below. Also note that, the call to the SetXamlToTheCenterElement ( ) is made after the InitializeComponent() from the constructor.





   1: <Window x:Class="EmptyWPF.Window1"


   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"


   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"


   4:     Title="Window1" Height="300" Width="300">


   5:     <DockPanel>


   6:         <Label DockPanel.Dock="Bottom" Background="Yellow">Bottom</Label>


   7:         <Label DockPanel.Dock="Top" Background="Red">Top</Label>


   8:         <Label DockPanel.Dock="Left" Background="Green">Left</Label>


   9:         <Label DockPanel.Dock="Right" Background="Maroon">Right</Label>


  10:         <Label HorizontalAlignment="Center" VerticalAlignment="Center" Name="lblCenter">Everything!</Label>


  11:     </DockPanel>


  12: </Window>




With the information that I shared until now, we could see that designing a WPF Form Designer is not as tough as it is in case of Windows Forms or other GUI technologies. In the subsequent posts, we look at the differences between the WinForms and WPF applications with respect to architecture as well as development.



Tools of trade



Blend, Visual Studio - Until now, for a Microsoft platform, Visual Studio has been the ultimate tool required. Now with WPF, Microsoft Blend appears to replace Visual Studio for Designers and for developers its Visual Studio again. VS 2008 Cider (WPF designer) is pretty neat and uses the same engine as the Blend. But the functionality that Blend provides is way ahead than what VS provides. Though this is a developer talk, we look at using Blend in the WPF animation demo.



Mole, Snoop - While Mole is a Visual Studio Debug Visualizer, Snoop is a stand alone tool. Mole allows us visualize WPF elements at runtime, change the properties and do a lot more stuff. For a professional application development, this is a handy tool and a must have in the kit.



KaXaml - A light-weight XAML editor and a tool that looks more like Blend with intellisense, syntax highlight, color picker, xml crunching, etc. kaXaml is a good replacement tool for XamlPad. Another alternative tool is the XamlPadX which supports add-ins and also has a visual tree visualizer, which kaxaml misses out.



Books, Blogs



Programming WPF - The treasure is always the information and not the tools. Firstly, the best book you can lay your hands upon is Programming WPF the book written by Chris Sells and Ian Griffiths, both of whom are excellent resources for anything that is .NET. If you wish to use WPF, you should buy this book.



Applications = Code + Markup - As always, Petzold book on WPF is the bible for a technology he writes on. Serious cons with this book is that it makes you sleep in no time given the bad appearance of MS Press books. But content, it undoubtedly gives a solid expertise.



Blogs - Tim Sneath has a list of WPF blogs that one must follow at this page. Personally I like the set of WPF gurus who are now at wpfdisciples.com. The amazing thing is that most of the stuff the blog about is mostly discussed in the Programming WPF book!



In the next post, we look at Visual Trees and Logical Trees in a WPF application.