Better late, than never, right? I’m happy to announce that my Silverlight book’s code is (finally) online. If you’ve bought the book, then you can head to FCA’s site and download it from the book’s page. Sorry for the delay…
SilverlightArchive
StaticResource extension and lookup behavior
While I was investigating Silverlight for my next PT book, I’ve found this official document from MS that describes the lookup algorithm for the StaticResource extension. According to it, here’s the algorithm used by this extension:
The lookup behavior for a StaticResource is that the markup compile pass for XAML first checks whether the object where the actual usage is applied can hold aFrameworkElement.Resources value. If it can, that ResourceDictionary is checked for an item that has that key. This level of lookup is rarely relevant because you usually do not define and then reference a resource on the same object.
I know that English is not my main language, but after reading, and re-reading it I’m really under the impression that it’s saying that StaticResource will always search the element’s resources where it is applied before going through the ancestors in the logical tree. Now, that means that this should work:
<StackPanel x:Name="panel" Orientation="Vertical" Background="{StaticResource brush}">
<StackPanel.Resources>
<SolidColorBrush x:Key="brush" Color="Red" />
</StackPanel.Resources>
<Button Content="Hi"
Background="{StaticResource brush}"/>
</StackPanel>
If you look at it, you’ll notice that the StackPanel is trying to use a resource defined in its Resources collection. Unfortunately, it really doesn’t work. Not even in WPF! From a parsing point of view, that’s not that unexpected because the parser hasn’t yet reached the resource definitions when it encounters the StaticResource (I believe that is why you can only reference previously declared resources when creating a new resource).
If I’m not wrong in my analysis, can someone at MS (please!) update the docs?
If you’ve been following this blog, then you know that I’ve been updating an existing project to .NET 4.0 (btw, don’t forget to download VS 2010; it’s already available for MSDN subscribers). This upgrade has been a great way to start using several great new features in a real world project. One extra benefit has been using Silverlight (4.0 RC) for building the UIs of the apps.
Since I’ve finally been able to use Silverlight in a “real world project”, I’ve went ahead and tried several things (including the so called view model pattern – MVVM pattern, if you really must be picky :),,). Now, one of the things I needed to do was add paging to a DataGrid control. If you’ve played with it, you’ll know that everything works just fine for auto-paging (ie, when you pass everything and set the page size to something smaller than the total number of items in the collection).
Unfortunately, this is something which isn’t really useful, right? In the real world, I do need to page data but I’m only returning a limited number of items from my server. After reading the docs and following some very good posts from Brad Abrams, I’ve noticed that I could do what I wanted by making my collection implement the IPagedCollectionView interface. As always, I’ve went with a hunch and implement the interface in a “logical” way. Now, the problem was that my pager was always returning page X of 1. WTF? 1? Why? Simple: ItemCount is supposed to return the *total* number of elements *before* pagination. Out of curiosity, I’ve went ahead and read the docs for TotalItemCount (notice that their definitions in the interface page are really similar). And that’s where I’ve found the difference: TotalItemCount is supposed to return –1 when the total number of items is unknown (btw, the DataPager does have a IsTotalItemCountFixed property which you can also set to configure the behavior of the pager when it reaches the last page of data).
Bottom line: whenever you’re implementing the IPagedCollectionView interface for “custom” paging, don’t forget that ItemCount is supposed to have the number of items before paging (and not the number of items maintained in the current collection). Lesson learnt…
As I’ve said before, I’ve started porting an existing project to .NET 4.0. I’ve tried using the new features .NET 4.0 introduces (ex.: code contracts). One of the objectives I had was replacing the traditional WCF service calls with RIA services. Until now, I’ve watched a couple of presentations (for instance, Nikhil’s presentation on MIX 2010) and it really seemed great.
I must say that I was a little suspicious about it because all the presentations I had seen used EF (and if you know me, you know that I’m still not ready to say goodbye to NHibernate and I do really believe in hiding/abstracting my backend behind an OO domain model). Anyway, I’ve decided to go ahead and tried to reuse my domain model in a RIA Service after reading about presentation models in the RIA Services documentation. What a bad mistake…It did cost me a day and a hald…Unfortunately, RIA Service don’t really integrate well with “real world” objects. For instance, take a look at my DTO (which I was trying to expose to the SL client):
[Serializable] [DataContract(Namespace = "http://sra.pt/Entidades")] public class OcorrenciasPaginadas { [Key]//don’t like this, but can live with it [DataMember()] public Int32 TotalElementos { get; set; } [DataMember()] public IEnumerable<ResumoOcorrencia> Ocorrencias {
get; set; } }
As you can see, I had to add annotate the TotalElementos with the KeyAttribute (even though TotalElementos is not an ID; anyway, it seems like objects must always be annotated with a key). The worst of all is that the client proxy that is automatically generated in the client side doesn’t include the Ocorrencias property. After talking with Fredrik, he mentioned the IncludeAttribute. So,I’ve started by adding it. Unfortunately,it started complaining that the IncludeAttribute can only be used in association with the AssociationAttribute.
After reading the docs, it was really obvious that RIA Services considers each entity as a lightweight wrapper around a row of a table (that’s the only justification I can think of for making me add an Id property to ResumoOcorrencia that “points back” to the “main” OcorrenciasPaginadas object). In other words, RIA Services does some really cool things, but it’s just not for me because I’m not exposing my backend tables directly to my clients (I’m sorry, but I have a domain model which is responsible for everything and my clients only consume DTOs – which in most situations are really different from the tables that the domain uses to persist data).
I really expected much more from MS, especially because they’ve been presenting RIA Services as something which can be used with any backend you have (if you don’t believe me, just watch any RIA Services presentation. I bet the guy that is presenting will always say something like “I’m using EF because this is quicker than building my own domain; don’t worry to much with this because you can expose any backend/model you’ve got with this wonderful technology”; this is not true, though I can confirm that if you’re using EF, then RIA Services do really rule).
Bottom line: goodbye RIA Services; Hello again “plain WCF”!
No more ObservableCollection for collections in Silverlight 4.0 RC?
While migrating a simple project from Silverlight 3.0 to 4.0 RC, I’ve noticed that the my project no longer compiles. I’ve started getting errors which said that something like “Array does not have an Add method”. After looking at the proxy that was generated by the add reference dialog, I’ve noticed that the ObservableCollection option is no longer available on the Service Reference Dialog (as you can see from the following image):
The good news is that this is a bug in the RC version and it should be fixed in the final release. Thank god for that!
Silverlight: getting started with commands
Silverlight 4.0 added the notion of command. In practice, a command is any object which implements the ICommand interface (btw, this is another of those interfaces which have been imported from WPF). Currently, the interface exposes the following members:
- Execute: this method is responsible for executing the logic associated with this command;
- CanExecute: this method should return true if the command is enabled (that is, if the command can be executed);
- CanExecuteChanged: this event is raised when the value of the CanExecute property changes.
Before going on, I’d like to poin out that, unlike WPF, Silverlight doesn’t really define any default commands (I’m just saying this because if you’re coming form WPF, you might expect to find some of the default commands that exist there; however, that is not the case).
It’s important to understand what commands give you. Before going on, I should say that you could (almost) get away without commands since you can always handle events and add your custom logic to them. However, commands give you superior support for encapsulating logic and reusing them in several places. This is especially true because several Silverlight control’s add logic for interacting with commands.
For instance,all Silverlight buttons (ie,all controls that inherit form ButtonBase) expose a Command (dependency) property which you can set to any object which implements the ICommand interface. As you might expect, the button will try to execute the command in response to any click that is performed over it. Besides that, it will also keep its IsEnabled property in sync with the command’s CanExecute property (this info is updated in response to the CanExecuteChanged event of the command). As you can see, there really is no reason for skipping commands, right?
Notice that you can reuse commands in several places. For instance, Fredrik Normen shows in this post how you can reuse the command concept to support the MVVM pattern. And that’s all for now. Stay tuned for more on Silverlight.
Protected: Still no support for “attached events” in Silverlight
Protected: XAML improvements in Silverlight 4.0
Getting exception error message in Silverlight
One of the things I needed to do in a recent project is get the error message returned from a WCF service in a Silverlight user control. The MSDN docs have a nice article which explains the changes you need to perform in order to get the server generated exception in your SL app (basically, you need to change the status code from 500 to 200 so that SL can access the body of the returned message).
It won’t be long until you notice that there’s a bug in WCF and that you need to use the full assembly name (yes, the one which takes type, assembly, version, etc, etc) so that WCF is able to get the custom behavior extension element you’ve written. What I did find out (the hard way – ie, after several lost minutes trying to check the name of the service) is that it won’t work if you’re using a strongly typed or versioned assembly.
There’s an entry in connect which says that this will be fixed in .NET 4.0, but this is not really good enough if you’re still in .NET 3.5 land…
Routed events in Silverlight
Routed events were introduced by WPF and they’re responsible for enabling several advanced scenarios in that platform:
- tunneling: in this case, the event is first raised in the root and goes “down the tree” until the source element that generated the event is reached;
- bubbling: in this case, the event bubbles from the source element to the root element;
- Direct: the event is only raised in the source element.
Once again, the use of routed events in Silverlight is limited. By default, it only exposes a couple of routed events and it only supports bubbling (ie, there’s no tunneling for routed events in Silverlight).In order to illustrate the bubbling feature, we’ll start running the following example:
<UserControl x:Class="Tests.test" x:Name="uc" xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:my="clr-namespace:Tests"> <Canvas Width="150" Height="200" x:Name="cv"> <StackPanel x:Name="sp"> <TextBlock Text="Click me" x:Name="bt" /> </StackPanel> </Canvas> </UserControl>
And here’s the code-behind:
public partial class test : UserControl { public test() { InitializeComponent(); bt.MouseLeftButtonDown += PrintInfo; sp.MouseLeftButtonDown += PrintInfo; cv.MouseLeftButtonDown += PrintInfo; MouseLeftButtonDown += PrintInfo; } private void PrintInfo(
Object sender, MouseButtonEventArgs e) { var info = String.Format(
"elemento original: {0} - elemento actual: {1}n", ((FrameworkElement)e.OriginalSource).Name, ((FrameworkElement)sender).Name); MessageBox.Show(info); } }
If you run the previous sample, you’ll notice that the event bubbles from the button until it reaches the root user control. The MouseButtonEventArgs class ends up inheriting from the RoutedEventArgs class. Due to that, we can access the OriginalSource property and find out which object is responsible for the event that is bubbling. Notice that the MouseButtonEventArgs ends up adding the read/write Handled property: when you set it to true,the event won’t be propagated beyond the current element that is responsible for the event that is being fired.
Unfortunately,you can’t really create custom routed events in Siverlight. The reason is simple: there isn’t a public API for letting you do that (if you dig into the code of the MouseLeftButtonDown event instantiation, you’ll notice that routed events are created through the RoutedEvent constructor which is internal). What this means is that you’re limited to creating “normal” events in your custom classes. I’m not sure if this limitation will ever be removed from Silverlight. And I guess this sums it up quite nicely. Stay tuned for more on Siverlight.
Creating attached properties
Now that you understand what attached properties are, we’re in the position to look at what is needed for creating attached properties. Since we’re building custom code, we do really need to rely in the RegisterAttached method (of the DependencyProperty class). Creating a new attached properties means doing the following:
- adding a static DependencyProperty field to the class;
- using the RegisterAttached method for creating the field which is used as a store for the dependency property;
- add a couple of static methods named GetXXX/SetXXX (where XXX is the name of the property) used as shortcuts for getting and setting the attached property from code.
Let’s suppose that we were creating a new look-a-like Canvas class. Here’s the code you’re expected to add to your class for the Left property:
public class MyCanvas: Panel { public static DependencyProperty LeftProperty; static MyCanvas() { LeftProperty = DependencyProperty.RegisterAttached( "Left", typeof (Double), typeof (MyCanvas), new PropertyMetadata(null)); } public static Double GetLeft(UIElement element) { return (Double) element.GetValue(LeftProperty); } public static void SetLeft(
UIElement element, Double value) { element.SetValue(LeftProperty,value); } }
As you can see, we need to start by registering the attached property through the RegisterAttached method. The method expects four parameters: the name of the property, the type of the property, the type of the “owner” of this property (generally, this will be the class that exposes the attached prop) and the associated metadata (notice that if you’re not interesting in setting a default value or in associating a callback method with the property,then you can simply pass null to the PropertyMetadata constructor like I did in the previous snippet).
After registering the property,you’re supposed to add a setter and a getter: in this case, I’ve called them GetLeft and SetLeft in order to comply with the recommendations. Once again, these methods are there as helpers and you can bypass them when writing you code (though I do recommend using them whenever possible).
And that’s really it…you don’t need anything extra for exposing an attached property. Stay tuned for more on Silverlight (there’s still a long road to go!)
Attached properties
An attached property is an interesting concept. The docs define it as:
An attached property is intended to be used as a type of global property that is settable on any object
An attached property lets you define properties in an object which are only defined by its parent element. Once again, if you have any experience with WPF, you should take into account that the number of attached properties is much smaller than what you have in WPF (for instance, TextElement.FontStyle is implemented as an attached property in WPF, but it’s a simple dependency property in SL).
There is also another interesting gotcha (when compared with WPF): it seems like the XAML parser “knows” about several predefined attached properties (registered as core dependency properties) and lets you use them without registering them through the RegisterAttached method (ex.: Canvas.Left is an attached property, but it’s not registered through the RegisteredAttached method). I guess this is just another of those quirks which make Silverlight a much less “predictable” framework than WPF.
The simplest way to understand these type of properties is to look at an example: we’ll simply take a look at how you can use the Canvas.Left/Canvas.Top attached properties to position an element.
<Canvas Width="500" Height="500"> <Rectangle Canvas.Left="10"
Width="100" Height="20" x:Name="rect1"> <Rectangle.Fill> <SolidColorBrush Color="Blue" /> </Rectangle.Fill> </Rectangle> <Rectangle Canvas.Left="200" Width="100" Height="20"> <Rectangle.Fill> <SolidColorBrush Color="Red" /> </Rectangle.Fill> </Rectangle> </Canvas>
The Left and Top properties are exposed by the Canvas class. If you take a quick peek at the class, you’ll notice that each attached property is backed up by a dependency property (notice the TopProperty and LeftProperty fields). Attached properties can also be accessed from code through a pair of static methods on the form GetXXX/SetXXX, where XXX is the name of the property (in these case, you’ll have GetLeft and SetLeft for setting the Left attached property). Do notice that both GetXXX and SetXXX expect a reference to an object (the type of the object depends on the types of objects you’re extending with the attached properties). The SetXXX method expects a second parameter, generally of type Object, which is used for setting the value of the attached property.
Typically, custom attached properties need to be registered through the DepedencyProperty.RegisterAttached method (something which is done from within the static constructor). However,in the case of predefined Silverlight control’s attached properties,they’re simply registered with predefined IDs which (I think?) are used internally by the platform to identify the type of behavior which is associated with that specific property.
I was thinking about showing you how to create a custom attached property, but I’ll leave that for a future post. Stay tuned for more on Silverlight.
Clearing values of dependency properties
In the previous posts, we’ve met several interesting features associated with dependency properties. I’m not sure if you’ve really had the time to understand the implications of having multiple “providers” (or if my writing was good enough for making you take into account those implications – which probably is true!), so I’ve though about writing a post on how to correctly clear the value of a dependency property. Suppose we’ve got the following XAML:
<UserControl x:Class="Tests.MainPage" xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" FontSize="30"> <UserControl.Resources> <Style TargetType="TextBlock"> <Setter Property="Foreground" Value="Blue" /> <Setter Property="Height" Value="100" /> </Style> </UserControl.Resources> <TextBlock Text="Hello, world!" x:Name="info" /> </UserControl>
And that we’ve used the following C# code for handling mouse enter/leave events:
public MainPage() { InitializeComponent(); info.MouseEnter += (sender, e) => { info.Foreground = new SolidColorBrush(Colors.Red); }; info.MouseLeave += (sender, e) => { info.Foreground = new SolidColorBrush(Colors.Blue); }; }
And yes, you’re right: we don’t need the { } to delimiter the instructions in the previous lambdas. Now that we’ve moved that out of the way, it’s time to remember what we’ve discussed in the previous post: the order by which you can influence the value of a dependency property. As we’ve seen, the value of a dependency property can be influenced by several “providers” where each “provider” might end up overriding the value set by another “provider” (it all depends on the priority of each provider!).
If you pay attention to the code (XAML), you’ll notice that the initial Foreground color of the TextBlock is set from a style setter. However, the code used to handle the MouseEnter/MouseLeave ends up setting the *local* value of the dependency property. In this case, there really isn’t any problem because we’re setting the local value of the dependency property to the same value as the one we had in the style setter. However,that is probably not what the author intended…He probably would really love to be able to just change the color to red on enter and go back to the previous existing color (whatever that color is) when the mouse exits the area delimited by the TextBlock.
This feature is known as “cleaning the value of a dependency property” and there’s a method for doing that: ClearValue. Take a look at the rewritten MouseLeave event handler:
info.MouseLeave += (sender,e) =>
info.ClearValue(TextBlock.ForegroundProperty);
As you can see, the ClearValue method expects a reference to an existing DependencyProperty object (in this example, that would be the ForegroundProperty field of the TextBlock class) which ends up being cleared. Whenever you need to do something like this (clear a value which has been temporarily set), you should always use the ClearValue method. Notice that using this method lets you change styles dynamically and you’ll always get the correct color when the mouse leaves the element.
And I guess that is all for now. Stay tuned for more on Silverlight.
Setting the value of a dependency property
One of the things I’ve mentioned in the previous posts is that the value of a dependency property at runtime can be influenced by several “providers”. That means that there needs to be some sort of order which governs the way providers affect the final value of a dependency property (this order is known as precedence list). The final value of a dependency property at runtime is obtained after all the items in the following list have been evaluated by the presented order:
- Default value;
- Style setters;
- Templated properties;
- Local value;
- Animations.
The default value of a dependency property depends on whether you’ve passed a default value through the property metadata or not. When you pass a value through the PropertyMetada object during the dependency property registration (my preferred method for defining a default value), that value is used as the default one. If you don’t set the default value through metadata, then the default value depends on the type used for storing the dependency property (reference types use null, value types use the default constructor and primitive types default to the default primitive values – another extra note: the docs say that the default value for a string-type dependency property is the empty string; however, my tests always return null as the default value when string is used as the type of the dependency property. are my tests wrong? or are the docs wrong?).
Style setters will overwrite any style value that has been defined through the default value of a dependency property (you’ll need to look at the docs to see which style values you can define for each control).
Template properties will only be used for objects that are built dynamically from templates. Typically, you’ll end up using TemplateBinding reference for setting the values of the dependency properties. However, you can also define the value of a property directly (without using a TemplateBinding), making that the value of that dependency value in all objects generated from the template.
Local values are set through direct property access or by using the SetValue method inherited from the DependencyObject class. Finally, animation values will always “override” the value of a dependency property. If that was not the case, then the value of the property wouldn’t change and there simply wouldn’t be any animation.
And I guess this sums it up quite nicely…Stay tuned for more on Silverlight.
Dependency properties and XAML gotchas
As I’ve said before, dependency properties introduce several advantages over the traditional CLR properties. However, there might some gotchas associated with their use from XAML. As we’ve seen, dependency properties are defined through static fields and exposed through .NET properties for easy consume from C#/VB code (as we’ve seen, getting and setting the value of the property is achieved through the GetValue/SetValue methods inherited from the DependencyObject class). If you’re coming to Silverlight from WPF, you already know that getters and setters of the property wrappers are “bypassed” at runtime when you set the properties from XAML and that’s probably what’s going to happen in Silverlight too. Is it? Are you sure? The docs say that is the correct behavior, but I’m not seeing that in my Silverlight 4.0 tests…
Take a look at the following (dumb) custom control:
public class MyTextBox:TextBox { public static readonly DependencyProperty DurationProperty; static MyTextBox() { DurationProperty = DependencyProperty.Register( "Duration", typeof(Int32), typeof(MyTextBox), new PropertyMetadata( 0, (sender, e) =>{} ) ); } public Int32 Duration { get { return (Int32)GetValue(DurationProperty); } set { if (value <= 0) { throw new ArgumentOutOfRangeException(); } SetValue( DurationProperty,value );
} } }
Now,check the following XAML:
<my:MyTextBox Duration="-1" />
If you’re expecting to see an exception during loading, then you’re correct. If you’re thinking that the code will run without any problems, then you’re wrong. This is another interesting gotcha that might bite you if you’re coming to Silverlight from WPF (btw, the docs *do* say that the behavior is the same as the one we get in WPF, but the truth is that I’ve run the previous code and the setter is always hit when setting the value from XAML – is this a changed when compared with SL 3?).
So, how can you build a control which works in both platforms with minimum work? For instance, in the previous example, I wanted to make sure that you can only pass positive values to the Duration property. The correct way of doing that type of check is by relying on the metadata that is passed during the property registration. Take a look at the revised code:
static MyTextBox() { DurationProperty = DependencyProperty.Register( "Duration", typeof(Int32), typeof(MyTextBox), new PropertyMetadata( 0, (sender, e) => { if ((Int32)e.NewValue <= 0) { throw new ArgumentOutOfRangeException(); } }) ); } public Int32 Duration { get { return (Int32)GetValue(DurationProperty); } set { SetValue( DurationProperty, value ); } }
As you can see, we’re passing a lambda to the property changed callback method. Whenever you try to set a new value, this method ends up being called. The NewValue property gives you access to the new value that is being passed to the dependency property and that’s why we’re using it to see if we’re getting a positive number.
Besides getting the new value, you can also get a reference to the current existing value (OldValue property) and a reference to the dependency property that is being changed (Property property). And I guess that is all for now. Stay tuned for more on Silverlight.
Protected: Dependency property and value inheritance
Getting started with dependency properties
The dependency property concept was introduced by WPF 1.0 for exposing rich functionality from XAML. Dependency properties support several features exposed by Silverlight (styling, animation and data binding, for instance). Unfortunately, they also increase the complexity associated with property definition. Dependency properties values at runtime depend on several things. For instance, it could depend on an animation which continuously changes the value of a property or it could depend on the value of its parent property (ie, it could inherit the value from its parent if the value isn’t explicitly set). When compared with the basic CLR properties, dependency property introduces the following advantages:
- change notifications;
- property value inheritance;
- support for multiple “providers” which can set its value.
Now that I’ve presented some of the ideas behind the concept, lets see how dependency properties are implemented. Dependency properties are exposed through “normal” CLR properties which wrap access to a field created through the DependencyProperty.register method. Take a look at the following snippet (from the ButtonBase class):
public abstract class ButtonBase : ContentControl { public static readonly DependencyProperty ClickModeProperty; static ButtonBase() { ClickModeProperty = DependencyProperty.Register( "ClickMode", typeof(ClickMode), typeof(ButtonBase), new PropertyMetadata(
new PropertyChangedCallback(
ButtonBase.OnClickModePropertyChanged))); //removed } public ClickMode ClickMode { get { return (ClickMode)base.GetValue(ClickModeProperty); } set { base.SetValue(ClickModeProperty, (Enum)value); } } private static void OnClickModePropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e) { ClickMode newValue = (ClickMode)e.NewValue; if (((newValue != ClickMode.Release) &&
(newValue != ClickMode.Press)) &&
(newValue != ClickMode.Hover)) { throw new ArgumentException(…); } } }
ClickMode is a dependency property. The ClickModeProperty is the real dependency property which is wrapped through the ClickMode property. By convention,all dependency properties are stored through public static fields and their names ends with the Property suffix. Another conclusion which can be taken from the previous snippet is that dependency properties are always created through the DependencyProperty.Register method. This method expects the following parameters:
- name: sets the name of the dependency property. This name is the same as the one that is used for the CLR property which wraps the dependency property field;
- type: identifies the type of the dependency property that is registered;
- owner: identifies the type of the object that “owns” the current dependency property;
- metadata: object of type PropertyMetadata which lets you set the default value and/or a notification callback method.
After introducing the dependency property field and creating the dependency property through the register method, convention (and easy of use) makes us add a new property which wraps the dependency property field. As you can see from the previous snippet, the ClickMode property is a read/write property which uses the GetValue/SetValue methods inherited from the DependencyObject base class.
Do notice that unlike WPF, where everything is managed, in Silverlight dependency properties values depend on unmanaged code. Besides that, you should also keep in mind that Silverlight’s dependency properties don’t expose the same amount of functionality you have in WPF. And I guess this is more than enough for getting started with dependency properties. We’ll keep looking at them in the next posts. Stay tuned!
Object trees in Silverlight
Whenever you use XAML to build an interface, you’ll end up generating Silverlight objects (obtained from the XAML parsing at runtime). In practice, you’ll end up with an object tree (this is really obvious when you look at the XAML – and yes, I’m assuming you’re using indentation in you XAML files) based on the relationships established between those objects (after all, objects have properties which can hold other objects or collection of objects). In Silverlight, most of this object tree structure is treated as an implementation detail, though you can still interact with it from code (ex.: many elements inherit from FrameworkElement which exposes the Parent property that lets you navigate from the “current” element to its parent).
WPF has two interesting concepts: logical and visual trees. Both views apply “filters” to the object tree and will only return specific elements (which depend on the filter). The best way to understand these concepts is to look at a simple example. Take a look at the following XAML:
<UserControl x:Class="Tests.MainPage" xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <StackPanel> <TextBlock>This is the title</TextBlock> <ListBox> <ListBoxItem Content="Item 1" /> <ListBoxItem Content="Item 2" /> </ListBox> <Button Content="Click me!" /> </StackPanel> </UserControl>
The logical tree associated with the previous snippet would look like this:
* UserControl
* StackPanel
* TextBlock
* This is the title
* ListBox
* ListBoxItem
* Item 1
…
As you can see, the logical tree will have all the objects (and their properties/events) which have been set up in the code (XAML or procedural code). In WPF, you can effectively access this logical tree and navigate through it (though the LogicalTreeHelper class). In Silverlight, that is not possible (since there is no LogicalTreeHelper class). You might be wondering why it’s important to care about logical trees since it’s only used internally by Siverlight. It happens that several important behaviors available are tied to this logical tree. For instance, property values are (sometimes) propagated from parent to children (more about this in future posts) and this only happens because Silverlight is able to build a logical tree. Unfortunately, the logical tree used by Silverlight only supports a subset of the WPF available behaviors (but that should be enough for most scenarios).
The visual tree is another tree which is built from the original object tree. In practice,the visual tree breaks down the objects maintained in the object tree into their core *visual* components. For instance,here’s the visual tree for the previous XAML:
*START* 0—Tests.MainPage
*START* 1—System.Windows.Controls.StackPanel
*START* 2—System.Windows.Controls.TextBlock
*END* System.Windows.Controls.TextBlock
*START* 2—System.Windows.Controls.ListBox
*START* 3—System.Windows.Controls.Grid
*START* 4—System.Windows.Controls.Border
*START* 5—System.Windows.Controls.ScrollViewer
*START* 6—System.Windows.Controls.Border
*START* 7—System.Windows.Controls.Grid
*START* 8—System.Windows.Controls.ScrollContentPresenter
*START* 9—System.Windows.Controls.ItemsPresenter
*START* 10—System.Windows.Controls.VirtualizingStackPanel
*START* 11—System.Windows.Controls.ListBoxItem
*START* 12—System.Windows.Controls.Grid
*START* 13—System.Windows.Shapes.Rectangle
*END* System.Windows.Shapes.Rectangle
*START* 13—System.Windows.Shapes.Rectangle
*END* System.Windows.Shapes.Rectangle
*START* 13—System.Windows.Controls.ContentPresenter
*START* 14—System.Windows.Controls.Grid
*START* 15—System.Windows.Controls.TextBlock
*END* System.Windows.Controls.TextBlock
*END* System.Windows.Controls.Grid
*END* System.Windows.Controls.ContentPresenter
*START* 13—System.Windows.Shapes.Rectangle
*END* System.Windows.Shapes.Rectangle
*END* System.Windows.Controls.Grid
*END* System.Windows.Controls.ListBoxItem
*START* 11—System.Windows.Controls.ListBoxItem
*START* 12—System.Windows.Controls.Grid
*START* 13—System.Windows.Shapes.Rectangle
*END* System.Windows.Shapes.Rectangle
*START* 13—System.Windows.Shapes.Rectangle
*END* System.Windows.Shapes.Rectangle
*START* 13—System.Windows.Controls.ContentPresenter
*START* 14—System.Windows.Controls.Grid
*START* 15—System.Windows.Controls.TextBlock
*END* System.Windows.Controls.TextBlock
*END* System.Windows.Controls.Grid
*END* System.Windows.Controls.ContentPresenter
*START* 13—System.Windows.Shapes.Rectangle
*END* System.Windows.Shapes.Rectangle
*END* System.Windows.Controls.Grid
*END* System.Windows.Controls.ListBoxItem
*END* System.Windows.Controls.VirtualizingStackPanel
*END* System.Windows.Controls.ItemsPresenter
*END* System.Windows.Controls.ScrollContentPresenter
*START* 8—System.Windows.Shapes.Rectangle
*END* System.Windows.Shapes.Rectangle
*START* 8—System.Windows.Controls.Primitives.ScrollBar Minimum:0 Maximum:0 Value:0
*END* System.Windows.Controls.Primitives.ScrollBar Minimum:0 Maximum:0 Value:0
*START* 8—System.Windows.Controls.Primitives.ScrollBar Minimum:0 Maximum:0 Value:0
*END* System.Windows.Controls.Primitives.ScrollBar Minimum:0 Maximum:0 Value:0
*END* System.Windows.Controls.Grid
*END* System.Windows.Controls.Border
*END* System.Windows.Controls.ScrollViewer
*END* System.Windows.Controls.Border
*START* 4—System.Windows.Controls.Border
*START* 5—System.Windows.Controls.Grid
*START* 6—System.Windows.Shapes.Path
*END* System.Windows.Shapes.Path
*START* 6—System.Windows.Shapes.Path
*END* System.Windows.Shapes.Path
*END* System.Windows.Controls.Grid
*END* System.Windows.Controls.Border
*END* System.Windows.Controls.Grid
*END* System.Windows.Controls.ListBox
*START* 2—System.Windows.Controls.Button
*START* 3—System.Windows.Controls.Grid
*START* 4—System.Windows.Controls.Border
*START* 5—System.Windows.Controls.Grid
*START* 6—System.Windows.Controls.Border
*END* System.Windows.Controls.Border
*START* 6—System.Windows.Shapes.Rectangle
*END* System.Windows.Shapes.Rectangle
*END* System.Windows.Controls.Grid
*END* System.Windows.Controls.Border
*START* 4—System.Windows.Controls.ContentPresenter
*START* 5—System.Windows.Controls.Grid
*START* 6—System.Windows.Controls.TextBlock
*END* System.Windows.Controls.TextBlock
*END* System.Windows.Controls.Grid
*END* System.Windows.Controls.ContentPresenter
*START* 4—System.Windows.Shapes.Rectangle
*END* System.Windows.Shapes.Rectangle
*START* 4—System.Windows.Shapes.Rectangle
*END* System.Windows.Shapes.Rectangle
*END* System.Windows.Controls.Grid
*END* System.Windows.Controls.Button
*END* System.Windows.Controls.StackPanel
*END* Tests.MainPage
As you can see, several of the controls used in the previous XAML end up using other elements for generating its appearance (in future posts, we’ll see how and why this works like this and how we can customize the looks of a control). Btw, here’s the code I’ve used for getting the visual tree:
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); bt.Click += (sender, e) => { PrintVisualTree(this, 0); }; } void PrintVisualTree(DependencyObject obj, Int32 depth) { Debug.WriteLine(
String.Format("*START* {0}---{1}",depth, obj) ); var totalCount = VisualTreeHelper.GetChildrenCount(obj); for (var i = 0; i < totalCount; i++) { PrintVisualTree(
VisualTreeHelper.GetChild(obj, i), depth+1); } Debug.WriteLine(String.Format("*END* {0}", obj)); } }
So, now you know that the object tree we have can be “filtered” into two important trees: logical and visual trees. On the one hand, logical trees end up supporting several of the behaviors we’ve got in Silverlight. On the other hand, visual trees are used for rendering the controls at runtime. And that’s it for now. Stay tuned for more in Silverlight.
More on XAML and content properties
In a previous post, I’ve introduced the concept of content properties. The idea behind a content property is simple: you use the ContentPropertyAttribute to specify the property which will be set with the contents declared inside that element when the property element syntax is not used. Here’s a quick example that should make this concept perfectly clear:
<Button x:Name="info"> <TextBlock Text="Say hi!" /> </Button>
In the previous snippet, the info Button’s Content property will be set to the TextBlock specified inside the <Button> element (btw, that happens because Button ends up inheriting from ContentControl which is annotated with the ContentPropertyAttribute to indicate that inner XAML contents are supposed to be passed to the Content property).
I’m only mentioning this topic again because there’s (another) small problem you might encounter if you’re coming into Silverlight from the WPF world. Take a look at the following snippet:
<Button x:Name="info"> Say hi </Button>
Loading that XAML means getting this error:
Ok, so what’s going on here? Once again all boils down to the XAML parser which is used by Silverlight. The following doc says this:
With the exceptions of TextBlock and Run, object elements in Silverlight cannot contain XML text nodes as an implicit way to set their text-type content properties. For example, <Button> hello world </Button> is not allowed in Silverlight XAML, you would have to specify <Button Content="hello world"…/>. Again, note that there are some syntaxes (such as for Color) that might resemble object element with inner text syntax, but they are technically an initialization text syntax, which supplies the string to type-convert for initialization as inner text.
Not something I enjoy, but that’s the way it works. And that’s it for now. Stay tuned for more.
Markup extensions
Markup extensions allows you to extend the expressibility of XAML. You use markup extensions to escape the general treatment that attribute values get (by default, we’ve seen that they are treated as strings or that a type converter is used to convert them to the adequate type). Markup extension expressions are always delimited by the pair { }.
Currently, the Silverlight’s XAML parser understands only four markup extensions:
- Binding: used in data bound scenarios for getting the value of an object at run time. This extension is implemented by the Binding class and you can set several of its property from XAML (ie, from the markup extension expression itself). We’ll return to this class in future posts, when we talk about data binding operations;
- StaticResource: used for setting the value of a property to a resource already defined in a resource dictionary (resource dictionaries are used for saving objects by key and it can be used in both XAML and code). The current release of Silverlight does not have any managed code class for supporting this type of markup extension (in other words, this is implemented in unmanaged code);
- TemplateBinding: another binding which is implemented in unmanaged code only. You’ll use this binding in your templates when you want to link the value of a control’s property to the value of another object’s property of the templated control (once again, this is only intro stuff and we’ll come back to this topic in future posts);
- Null: used for setting the value of a property to null. You might find this markup extension odd at first, but the truth is that there’s no other way to set a property to null in XAML (don’t forget that passing string would probably result in using a type converter). Another interesting thing you should keep in mind is that not all properties have a default value of null (to understand this, we’ll need to go into dependency properties – and yes, that will be the topic of a future post).
If you’ve been doing some WPF development, you’ll probably be thinking that Silverlight is not as extensible as WPF. For starters, there is no MarkupExtension base class (which is extended by all markup extensions). In practice,this means that you cannot create your own markup extensions. Finally,you should also notice that unlike WPF, you can only use markup extensions with the attribute value syntax. Again, this is happening due to the limitations I’ve mentioned before (Silverlight must be small and we can’t forget that it runs across several platforms/browsers)
I guess that it’s time to see an example. We’ll get started with the StaticResource markup extension:
<Canvas> <Canvas.Resources> <SolidColorBrush x:Key="brush" Color="Green" /> </Canvas.Resources> <Button Content="Say hi" Background="{StaticResource brush}" /> </Canvas>
In the previous snippet, I’ve started by creating a new Canvas resource brush and I’ve identified it with the name brush. This is all you need to be able to reuse that resource in all the Canvas’ children objects’ properties that expect a brush (in the previous example, I’ve used that resource to fill the background color of a button). Resource dictionary usage has some gotchas, but I’ll leave that for a future post (after all, the main objective of this post is to look at markup extensions).
StaticResource and Binding markup extensions expect only a single value. However, Binding is implemented through a managed class and if you check its definition, you’ll see that it has several properties which you can also set from XAML. In this case, the syntax is simple: you can specify a value for the “default” property (which is Path, in the case of the Binding markup extension) and you should indicate all the other properties through the key=value pair entries (separated by comma). For instance, here’s an example of how you can set a binding:
<TextBlock Text="{Binding Content, ElementName=origin}" />
In the previous snippet, I’m binding the value of the Text property to another element defined through XAML which is named origin (I guess it could be a button since it has a Content property). There’s lot of things to say about bindings but for now I’m only worried in showing you how to use them from XAML (through the markup extension syntax).
Before ending up, there’s still time for one more topic: escaping the { } in attributes. By default, whenever you pass the pair { } to an attribute value, the XAML parser will interpret it as a markup extension. If you need to set the value of an attribute to a value which contains that { } pair, you’ll need to escape it. Here’s how:
<TextBlock Text="{}{Binding Content, ElementName=origin}" />
As you can see, using the {} pair at the beginning of the attribute’s value is all that it takes to escape the rest of the expression. If you put the previous XAML in a user control, you’ll see the {Binding….} text on the browser when you load that control.
I’ve only been playing with Silverlight for a few days (and I really haven’t done any real work with it). Even though it has lots of potentials, I must confess that I’m a little disappointed with the gotchas I’ve already found. I guess that they won’t matter much if you’re using a tool like Blend for creating the interface, but I must say that all these little things which don’t always work as expected are starting to make me think that I should probably be working with WPF instead where everything makes sense and works as expected…
And that’s it for now. Stay tuned for more on Silverlight.
XAML: what about events?
A friend of mine asked me about events and XAML: can we setup event handlers in XAML? And the answer is, yes, you can. Here’s a quick example of how you can handle the click event of a button:
<Button Click="Button_Click"></Button>
And yes, you must define the Button_Click method in your code-behind file (note that you could do it inline – ie, in the XAML file – if you’re using WPF). I must confess that I’m not really a fan of this approach since I prefer to put all my code in the code-behind file. For making it work, I’ll need to change the previous code slightly by adding a name to the button:
<Button x:Name="bt"></Button>
And now, from within the constructor, I can setup my event handler like this:
bt.Click += Button_Click;
Final note: in the real world, I’ll probably end up with a Lambda expression for simple handlers. As you can see, setting up handlers from the XAML is possible (the syntax is the same as you’ve got for props) but I don’t really recommend it. And that’s it for now. In the next post, we’ll talk about Silverlight’s markup extension support. Stay tuned.
Protected: How to build types that can be consumed from XAML
Associating XAML namespaces to CLR namespaces
Take a look at the following (simple) XAML:
<UserControl x:Class="SilverlightApplication1.MainPage" xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Canvas x:Name="myCanvas"> </Canvas> </UserControl>
When I started talking about XAML, I said that the default XAML namespace is associated to several controls. You might be a little curious on how this is done. By using Reflector, you’ll see that many of the Silverlight assemblies associate CLR namespaces to XAML namespaces through the XmlnsDefinitionAttribute:
You’ll typically find this attribute in most assemblies that have been thought with Silverlight and WPF in mind. Notice, though, that its use isn’t mandatory to map a CLR namespace to XAML namespace because Silverlight (and WPF) supports a special mechanism for doing that. For instance, suppose you’ve got a type called BeautifulGrid, defined in the CLR Test namespace, in a Dumb assembly. Now, when you build the assembly, you didn’t knew anything about the XmlnDefinitionAttribute. How can you use the BeautifulGrid in your XAML file? Here’s the answer:
<UserControl x:Class="SilverlightApplication1.MainPage" xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:my="clr-namespace:Test;assembly=Dumb"> <Canvas x:Name="myCanvas"> <my:BeautifulGrid> </my:BeautifulGrid> </Canvas> </UserControl>
There are some interesting gotchas you should keep in mind when using this syntax:
- the clr-namespace key is separated from its associated value by a semi-colon (:) while the assembly part of the expression uses an equal sign (=)
- this is one of those places where you *can’t* use white spaces for improved readability;
- you can omit the assembly part if the namespace you want to use is in the same assembly as the “current” XAML file.
Even though Silverlight supports the XmlnsDefinitionAttribute, the truth is that it doesn’t really play an important role for using custom types in Silverlight. The recommended approach for using custom types in XAML is to use the clr-namespace approach I’ve showed above.
And that’s it for now. Stay tuned for more in Silverlight.
XAML languages features
As I’ve said before, Silverlight supports only a subset of the existing XAML keywords you can use in WPF. Here’s the list of keywords you can use in your Silverlight:
- x:Class: you can apply this attribute to the root element of the XAML file (or object tree) that is going to be “compiled”. When you apply this attribute, you’ll end up creating a partial class (named after the value you’ve passed to the attribute) which is joined with the associated code-behind file. Even though you don’t really have to use this attribute, the truth is that you’ll probably use them in 99% of your XAML files;
- x:Key: as you’ve seen in the previous post, you can use this attribute to set the key of a dictionary’s entry of a resource dictionary;
- x:Name: used for identifying an object so that it can be easily recovered from the code-behind file. The “practical effect” of using this attribute is that you’ll end up having a field in the code-behind file which references the element you’ve defined on the XAML file. As you can see on the docs, you’re limited in the values you can pass to this attribute. It goes without saying that you must ensure uniqueness through the names you give to the elements;
- x:Null: this *extension* is used for setting the value of a property to null. You can use this extension with the property element or attribute syntax.
The best way to understand these attributes is to build a demo user control and see what happens after everything is compiled. For instance, lets assume that we’re adding a new Silverlight User Control to an existing Silverlight application (this will let me show what happens when you use the x:Class and x:Name attributes). By doing that, we end up with two files: a XAML and its corresponding code-behind CS file (shown in the next figure).
Here’s the default generated XAML (I’ve removed the unnecessary namespaces):
<UserControl x:Class="SilverlightApplication1.SilverlightControl1" xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> </Grid> </UserControl>
If you look at the properties of the XAML file, you’ll see that it looks like this:
The default configuration ends up embedding the XAML file in the assembly (check the next image):
You’ll also get a new C# file (.g.cs) from the XAML “compilation” (onde again, I’ve edited the code before pasting it here):
namespace SilverlightApplication1 { public partial class SilverlightControl1 :
System.Windows.Controls.UserControl { internal System.Windows.Controls.Grid LayoutRoot; private bool _contentLoaded; [System.Diagnostics.DebuggerNonUserCodeAttribute()] public void InitializeComponent() { if (_contentLoaded) { return; } _contentLoaded = true; System.Windows.Application.LoadComponent(
this, new System.Uri(
"/SilverlightApplication1;” +
“component/SilverlightControl1.xaml",
System.UriKind.Relative)); this.LayoutRoot = ((System.Windows.Controls.Grid)
(this.FindName("LayoutRoot"))); } } }
There are several interesting things going on here:
- the x:Class attribute is responsible for the creation of the partial class defined in the .g.cs file;
- all the named elements (ie,all the elements that use the x:Name attribute) get added to this partial class as fields. Notice that the FindName method is used for grabbing a reference to an element that is defined through the XAML file;
- the LoadComponent method is used for loading the XAML defined in the XAML file. In this case,the generated code is getting the embedded XAML file from the SiverlightApplication 1 assembly.
by now, you should be able to understand why you can use the same name you’ve used for the x:Name attribute to access that element from a code-behind file.
As you’ve seen, you can access the XAML elements from your code behind because building a Silverlight project ends up generating a partial class which introduces fields with the same name as the ones you used for the elements defined through XAML. THis is only possible due to the use of the x:Class and x:Name attributes.
And that’s it for now. Stay tuned for more on Silverlight.
XAML and collections
We’ve already talked about several features related to XAML. In this post, we’ll keep going and we’ll see how to specify collections in XAML. There are two basic types of collections you can use in XAML: lists and dictionaries. Before going on, it’s important to understand that you’re not really creating new collections in XAML; instead, we’re adding items to existing collections (in other words, if you’re building an object which has a collection like property and you want it to be set from XAML, then don’t forget to make sure that the getter returns a valid reference to a collection object).
“List collections” are collections which expose an Add method (generally, we’re speaking about objects which implement the IList interface). In these cases, you’ll typically put the elements within the collection property and the XAML parser will create an object that represents each item before adding them to that collection through the Add method:
<Rectangle Width="300" Height="150"> <Rectangle.Fill> <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> <LinearGradientBrush.GradientStops> <GradientStop Color="White" Offset="0" /> <GradientStop Color="Black" Offset="1" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </Rectangle.Fill> </Rectangle>
Btw, we could have simplified the XAML because GradientStops is the content property for the LinearGradientBrush object:
<Rectangle Width="300" Height="150"> <Rectangle.Fill> <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> <GradientStop Color="White" Offset="0" /> <GradientStop Color="Black" Offset="1" /> </LinearGradientBrush> </Rectangle.Fill> </Rectangle>
You can always write the previous code in C# (assume rect is a reference to the rectangle):
rect.Fill = new LinearGradientBrush() { StartPoint = new Point(0,0), EndPoint = new Point(1, 1), GradientStops = { new GradientStop() { Color = Colors.White, Offset = 0 } , new GradientStop() { Color = Colors.Black, Offset = 1 } } };
Dictionaries are a different kind of collection: in these cases, each entry is a pair composed by a key and a value. The important thing here is understanding that you specify the key through the x:key attribute:
<UserControl.Resources> <Color x:Key="Black" A="0" B="0" G="0" /> </UserControl.Resources>
For now, lets forget that we’re specifying resources and we’ll only concentrate on the syntax. As you can see, we added a tag which identifies the resource as a color and we’re identifying it with the word Black (ie, Black is the key that identifies this entry). Once again, you could translate the previous code into C# (Resources is an object of type ResourceDictionary), but I’ll leave it to you (if you don’t have anything better to do, that is 🙂 )
Notice x:Key is one of the few XAML keywords Silverlight supports. Besides it, there’s also the x:Class, the x:Name and x:Null attributes (we’ll come back to them in a future post). If you’re coming from WPF, then this might seem limited at first, but it’s all we have in Silverlight.
And I guess this sums it up for now. Stay tuned for more on Silverlight.
Type converter on Silverlight
Today we’ll talk a little bit about the role played by type converters in “transforming” XAML into C# objects. Here’s a quick example:
<Button xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="bt" Click="bt_Click" Width="100" Content="Say Hi" Background="Red" />
If you look carefully, you’ll see that Background expects a Brush object. All XAML attribute are strings by default. In other words, you’d need the following C# code to set the background of the button:
bt.Background = new SolidColorBrush(Colors.Yellow);
So, what’s going on here? Well, it’s simple: the parser uses a type converter to convert the string into the correct object. In practice, type converters are objects which inherit from TypeConverter class. You can associate a type converter to a type or to a property by using the TypeConverterAttribute. The parser will respect that option and will use the indicated type converter to translate the string into the expected object type.
Now, unlike WPF, where everything is really based on managed type converters, in Silverlight, there is an *unmanaged* type converter which is used for performing most of the common conversions you’d expect to happen (take a look at the internal SilverlightTypeConverter class and you’ll notice that you’ll end up using the “unmanaged” XcpImports type).
So, don’t expect to find many type converters by firing up .NET Reflector. Btw, you should keep in mind that you can still build and use your own type converters for your types. The XAML parser will always check the current property and/or type and if it’s associated with a managed type converter,it will honor that relationship and your converter will be used.
And I guess it’s all for now. Stay tuned for more on Silverlight.
XAML: using content properties
In the previous post, we’ve seen that we can use one of two approaches for setting the value of a property: we can use the property element or the attribute syntax (and, as we’ve seen in the previous post, you can’t use them both interchangeably). In this post, we’ll keep going and we’ll see how content properties simplify even more the markup we need to write to setup the value of a property.
For instance, here’s how I’d set the Content of a button to an image:
<Button xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="bt" Click="bt_Click" Width="100"> <Image Source="/p52.jpg" Stretch="UniformToFill" /> </Button>
If you compare this snippet with the one we had before, you’ll notice that we’re not using the <Button.Content> markup element to specify that we’re setting the Content property. Why?
To understand what’s going on, we need to talk a little bit about content properties. Any class can designate a property that should be set to whatever content is inside the XML element. As you’ve probably guessed, these properties are called content properties.
In the case of the Button class, its content property is the Content property. Specifying a content property is done through the ContentPropertyAttribute. For instance, in the case of the Button element, we need to look at the ContentControl class (used as base) to see how the content property is defined:
[ContentProperty("Content",true)] public class ContentControl : Control {
Whenever you see this attribute,you know that the content of element is directly “transformed” and copied to the indicated property. And that’s it for now. Stay tuned for more on Silverlight.
XAML and property elements
In the previous post, we’ve started looking at same basic XAML. At the time, we’ve defined a simple button by using the following syntax:
<Button xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="bt" Content="Say hi" Click="bt_Click" />
In the previous snippet, we’re setting the Content property and the Click event. Btw, and in case you’re wondering, events are set up before the properties. This is the only thing you can take for granted (you can’t really depend on the order of the attributes in your XAML to influence the order by which properties are set). This makes sense because it means that eventual handlers will be called if an event is generated by setting a property to a specific value.
If you look at Content’s definition, you’ll see that it expects an object. That means we can, for instance, pass it an image instead of setting it to text:
<Button xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="bt" Click="bt_Click" Width="100"> <Button.Content> <Image Source="/p52.jpg" Stretch="UniformToFill" /> </Button.Content> </Button>
The previous snippet is showing the property element syntax. You should use it whenever you can’t use a simple string to define the value of a property. Property element syntax is really simple: you define a property by combining the name of the element with the name of the property. Property element syntax and attribute syntax are the two options you’ve got for setting the value of a property in XAML (sort of: we’ll leave content properties and collection properties to a future post).
In case you’re wondering, you can’t use something like this in Silverlight:
<Button xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="bt" Click="bt_Click" Width="100"> <Button.Content> Say Hi </Button.Content> </Button>
If you try loading the previous XAML, you should get an exception which says something like “Say Hi isn’t allowed as the button’s content”. In case you’re wondering, this does work in WPF. Unfortunately,in Silverlight you’ll have to use the attribute syntax for setting the value of the Content to a string.
In this cases,you do need to use another element. Here’s the code you can use for setting the Content’s property to text through the property element syntax:
<Button xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="bt" Click="bt_Click" Width="100"> <Button.Content> <TextBlock>Say Hi</TextBlock> </Button.Content> </Button>
Fair enough: this isn’t really similar to what we had before, but it’s really the only way to set the button’s Content property to something that looks like text (notice that in this case, the Content is set to another FrameworkElement and not to a simple string).
Understanding why something works in WPF and not in Silverlight is not complicated: you just need to keep in mind that all the features considered not essential were removed in order to control the size of the Silverlight framework. And it looks like this was one of them…
You must be wondering which syntax you should use when you want to set the value of a property. Sometimes, the answer is simple since we’ve seen a case where you can’t use both syntaxes for setting a specific value. When both approaches are supported, I’ll tend to use the one which is more compact (typically, this means going with the attribute syntax whenever possible).
And I guess this wraps it up for now. Stay tuned for more on Silverlight.
Introducing XAML
You can’t really do it any other way: we must understand XAML before going on (at least, its basic features). In this post, we’ll start looking at XAML and at how we can use it to define the UI of our Silverlight user controls. So, the big question: what is XAML? To me, XAML (which, btw, means Extensible Application Markup Language) is a declarative language which you can use to define and initialize objects. Notice that XAML isn’t Silverlight specific. If my memory is correct, it was introduced with .NET 3.0 and its new frameworks (WPF and WF). In Silverlight, we’ll be using it to define the looks of our UIs. As we’ll see, it really saves us lots of code.
Ok, since this is a an intro post, we’ll start simple. In this post,we’ll talk about how we can create objects and set its properties. Here’s a simple XAML snippet:
<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="bt" Content="Say hi" Click="bt_Click" />
XAML is an XML language. That also means that XAML is case sensitive. Notice that we’re talking about element and attribute names here. Values are a special case: sometimes they are case sensitive; others,they aren’t (more about this in future posts). The previous example already introduces two important concepts: it shows us how to declare an element in XAML and how to set its one of its properties.
Btw, the previous code is equivalent to the following C# code:
var bt = new Button(); bt.Content = "Say hi"; bt.Click += (s, args) => { };
Ok, there’s a slight difference between both snippets: in the XAML snippet, we’re saying that the Click event will be handled by a method named bt_Click, while on the C# example, we’re using a Lambda expression.
I’m not sure if you’ve noticed, but we had to use a couple of namespaces when we wrote the XAML. The default namespace (http://schemas.microsoft.com/winfx/2006/xaml/presentation) is hardcoded to several CLR namespaces (notice that I haven’t found the list, but I assumed this behavior because that was what happened with WPF 1.0). The other namespace (the XAML one that is associated to prefix x) is used for defining some directives which are interpreted by the XAML parser (notice that the directives really look like attributes, but they are, in fact, directives). In the previous XAML snippet, the x:Name directive ends up creating a new Button object named bt (in a future post, we’ll see how this is done).
The x:class directive is another XAML directive that is used often when you need to associate a XAML file to a class defined in a code-behind file (oh yes, Silverlight does support code-behind files too 🙂 ).
We’ve just started scratching XAML. As we’ll see in future posts, there are several interesting things we can do. For now, the main thing to keep in mind is that all that you can do through XAML, you can also do from C# code (though, as I’ve discovered recently, XAML code might be more performant than writing C# code – at least, when you think about rendering). And that’s it for now. In the next post, we’ll talk about the options we have for setting the properties of an object. Stay tuned for more on Silverlight.