Peter McGrattan’s Weblog

Silverlight, WCF, ASP.NET, AJAX, Graphics, RIA

Posts Tagged ‘Silverlight 2’

Filtering Silverlight DataGrid Rows with ApplyMutateFilter<T>

Posted by petermcg on January 29, 2009

(Code download)

This post presents a solution to a question on Stack Overflow which I found interesting, this is a question I’ve seen crop up a few times now in one form or another:

"I have an ObservableCollection feeding a DataGrid that is updating nicely.  The point: I want to filter (collapse) the rows without removing them from the collection.  Is there a way to do this?"

You can remove rows from a DataGrid by removing items from the ObservableCollection<T> that the grid’s ItemsSource property is bound to, but the question asks is there a way to avoid this.  The way I see it a solution to this question will firstly offer a way to filter the rows displayed in a DataGrid without affecting the Count of the original ObservableCollection<T> and secondly provide a way to easily discern which rows are currently filtered and which are displayed after the filter has been applied.  The intent is also to provide a solution general enough to be reused with any type T in an ObservableCollection<T>.

The solution structure of the simple demo solution available for download above looks as follows:

Solution Structure

The demo application running looks as follows:

App Running Pre-Filter

This UI is produced from the contents of Page.xaml:

<UserControl x:Class="DataGridRowFiltering.Page"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  
             xmlns:input="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls.Input">

    <StackPanel Margin="5,5,5,5" x:Name="LayoutRoot" Background="White">

        <StackPanel Orientation="Horizontal" Margin="0,15,0,15">
            <TextBlock Text="Age Filter" FontSize="16" VerticalAlignment="Center" TextAlignment="Center" Margin="0,0,10,0" />

            <input:NumericUpDown Width="40" x:Name="FilterValue" DecimalPlaces="0" Minimum="20.0" Maximum="25.0" Margin="0,0,10,0" />

            <Button x:Name="FilterButton" Content="Apply Filter" Click="FilterButton_Click" />
        </StackPanel>

        <StackPanel Margin="0,15,0,15">
            <TextBlock Text="Filtered People" FontSize="16" />
            <data:DataGrid x:Name="FilteredPeople"  AutoGenerateColumns="True" IsReadOnly="True" />
        </StackPanel>

        <StackPanel Margin="0,15,0,15">
            <TextBlock Text="All People" FontSize="16" />
            <data:DataGrid x:Name="AllPeople"  AutoGenerateColumns="True" IsReadOnly="True" />
        </StackPanel>

    </StackPanel>
</UserControl>

The Xaml contains two DataGrids, a NumericUpDown control from the Silverlight Toolkit and a standard Button control.  When the ‘Apply Filter’ button is clicked the people (or rows) shown in the FilteredPeople grid are filtered, the row count in the AllPeople grid remains unchanged.  The filter excludes people whose Age property does not equal the current value of the NumericUpDown control.

The events for the UI are in Page.xaml.cs:

using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

namespace DataGridRowFiltering
{
    public partial class Page : UserControl
    {
        ObservableCollection<Person> people = new ObservableCollection<Person>()
        {
            new Person("Peter", 20),
            new Person("Bill", 21),
            new Person("Joe", 21),
            new Person("David", 23),
            new Person("Steve", 24),
            new Person("Jeff", 25),
        };

        public Page()
        {
            InitializeComponent();

            Loaded += Page_Loaded;
        }

        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
            FilteredPeople.ItemsSource = people;
            AllPeople.ItemsSource = people;
        }

        private void FilterButton_Click(object sender, RoutedEventArgs e)
        {
            int selectedAge = Convert.ToInt32(FilterValue.Value);

            FilteredPeople.ItemsSource = people.ApplyMutateFilter(p => p.Age == selectedAge,
                                                                  p => p.IsVisible = true,
                                                                  p => p.IsVisible = false);
        }
    }
}

The Page class has an ObservableCollection<Person> called ‘people’ containing 6 instances of the Person class.  The Person class is a simple class that implements the INotifyPropertyChanged interface and has properties called FirstName, Age and IsVisible.

When an instance of the Page UserControl is loaded the ItemsSource property of both DataGrids is bound to the people collection resulting in the screenshot shown earlier.

When the ‘Apply Filter’ button is clicked we store the current value of the NumericUpDown control in the selectedAge variable and set the ItemsSource of the FilteredPeople grid to the result of calling the ApplyMutateFilter<T> extension method:

using System;
using System.Collections.Generic;
using System.Linq;

namespace DataGridRowFiltering
{
    public static class Extensions
    {
        /// <summary>
        /// Applies an action to each item in the sequence, which action depends on the evaluation of the predicate.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements of source.</typeparam>
        /// <param name="source">A sequence to filter.</param>
        /// <param name="predicate">A function to test each element for a condition.</param>
        /// <param name="posAction">An action used to mutate elements that match the predicate's condition.</param>
        /// <param name="negAction">An action used to mutate elements that do not match the predicate's condition.</param>
        /// <returns>The elements in the sequence that matched the predicate's condition and were transformed by posAction.</returns>
        public static IEnumerable<TSource> ApplyMutateFilter<TSource>(this IEnumerable<TSource> source,
                                                                      Func<TSource, bool> predicate,
                                                                      Action<TSource> posAction,
                                                                      Action<TSource> negAction)
        {
            if (source != null)
            {
                foreach (TSource item in source)
                {
                    if (predicate(item))
                    {
                        posAction(item);
                    }
                    else
                    {
                        negAction(item);
                    }
                }
            }

            return source.Where(predicate);
        }
    }
}

This method takes one predicate and two actions.  A ‘predicate’ in this case just means a function that takes a parameter of type TSource and returns true or false.  Similarly an ‘action’ is just a function that takes a parameter of type TSource and returns void.

In the call to ApplyMutateFilter<T> in the event handler for the button’s Click event above, the predicate function is designed to return the result of the comparison between a Person object’s Age property and the value of selectedAge.  The two action functions are designed to set the value of the IsVisible property on a Person object to either true or false.

The ApplyMutateFilter<T> extension method body applies one of these actions to every item in the sequence, which action depends on the evaluation of the predicate.  If the predicate returns true the positive action is executed otherwise the negative action is executed resulting in the value of the IsVisible property changing.

Finally only the elements in the sequence that matched the predicate are returned with the call to the Where<T> extension method, thus the filter is applied.

It’s important to remember that setting the IsVisible property does not make the row disappear from the DataGrid; it’s the call to Where<T> that filters the sequence.  The IsVisible property is merely a convenient way of later finding which elements have been affected by the current filter in code, for example if you wanted to know what rows are currently being shown in the DataGrid after a filter has been applied.

Here is a screen shot after clicking the ‘Apply Filter’ button with a selected age of 21:

App Running Post-Filter

The FilteredPeople DataGrid now only displays people aged 21.  The grid is now bound to the filtered sequence returned from the call to ApplyMutateFilter<T> with a predicate comparing each Person object’s Age property to the selectedAge of 21.

The screenshot shows the rows have been filtered in the first DataGrid without affecting the Count of the original ObservableCollection<T> which the second DataGrid’s is still bound to, thus satisfying the first task we set out to achieve.

Finally it’s clear to see the second requirement has been fulfilled from the state of the IsVisible properties. The value of this property makes it easy to discern which rows in the original ObservableCollection<T> are currently filtered and which are displayed after the filter has been applied.

Altering the predicate is all that’s required to apply a filter to a different property/column or a combination of several properties/columns.

Posted in DataGrid, Extension Method, Silverlight | Tagged: , , , | 3 Comments »

Configuring Silverlight 2 Polling Duplex Endpoints in .config file only

Posted by petermcg on October 23, 2008

(Sample Application Code) | (PollingDuplexConfig.cs only)

I got an interesting question recently asking if it was possible to specify a Silverlight 2 Polling Duplex endpoint entirely within an application’s configuration file instead of defining the endpoint in code as show below in the excerpt taken from my Polling Duplex Stock List demo:

using System;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace StockServer
{
    public class StockServiceHost : ServiceHost
    {
        public StockServiceHost(object singletonInstance, params Uri[] baseAddresses)
            : base(singletonInstance, baseAddresses)
        {
        }

        public StockServiceHost(Type serviceType, params Uri[] baseAddresses)
            : base(serviceType, baseAddresses)
        {
        }

        protected override void InitializeRuntime()
        {
            // Policy Requirements Endpoint
            this.AddServiceEndpoint(
                typeof(IPolicyProvider),
                new WebHttpBinding(),
                new Uri("http://localhost:10201/")).Behaviors.Add(new WebHttpBehavior());
            
            // Polling Duplex Endpoint
            this.AddServiceEndpoint(
                typeof(IStockService),
                new PollingDuplexHttpBinding(),
                new Uri("http://localhost:10201/StockService"));

            base.InitializeRuntime();
        }
    }
}

Surprisingly this is not supported by default in the release version of Silverlight 2 due to the absence of the required configuration-related classes needed to expose the Polling Duplex binding and binding element to the WCF configuration system.  However, thanks to the great extensibility model of WCF it is possible to enable this scenario and bridge the gap by registering a custom binding extension.

The aim is to render the StockServiceHost class (defined in code above) redundant and instead replace it’s functionality entirely in a configuration file, in this case App.config.  As you can see in the InitializeRuntime method the StockServiceHost class actually registers two endpoints: in addition to the PollingDuplexHttpBinding endpoint there is the WebHttpBinding endpoint to account for the Silverlight 2 cross-domain policy requirements.  It would defeat the aim to succeed in defining one of these endpoints in the configuration file without the other, so the measure of success is to be able to define both in App.config.  How this aim can be achieved is shown below:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <diagnostics performanceCounters="All" />

    <behaviors>
      <endpointBehaviors>
        <behavior name="webHttpBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>

    <bindings>
      <pollingDuplexHttpBinding>
        <binding name="pollingDuplexHttpBindingConfiguration"
                 inactivityTimeout="00:09:59"
                 serverPollTimeout="00:14:59" />
      </pollingDuplexHttpBinding>
    </bindings>

    <extensions>
      <bindingExtensions>
        <add name="pollingDuplexHttpBinding"
             type="StockServer.PollingDuplexHttpBindingCollectionElement, StockServer" />
      </bindingExtensions>
    </extensions>

    <services>
      <service name="StockServer.StockService">

        <!-- Policy Requirements Endpoint -->
        <endpoint address="http://localhost:10201/"
                  binding="webHttpBinding"
                  behaviorConfiguration="webHttpBehavior"
                  contract="StockServer.IPolicyProvider" />

        <!-- Polling Duplex Endpoint -->
        <endpoint address="http://localhost:10201/StockService"
                  binding="pollingDuplexHttpBinding"
                  bindingConfiguration="pollingDuplexHttpBindingConfiguration"
                  contract="StockServer.IStockService" />

      </service>
    </services>
  </system.serviceModel>
</configuration>

Notice under the <bindingExtensions> element that the pollingDuplexHttpBinding item relies on the following two configuration-related classes (demonstrated in use as part of the sample application or available separately for download above) in the PollingDuplexConfig.cs file:

using System;
using System.Configuration;
using System.Globalization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;

namespace StockServer
{
    public class PollingDuplexHttpBindingCollectionElement : 
        StandardBindingCollectionElement<PollingDuplexHttpBinding, PollingDuplexHttpBindingElement>
    {
    }

    public class PollingDuplexHttpBindingElement : StandardBindingElement
    {
        private const string InactivityTimeoutPropertyName = "inactivityTimeout";
        private const string DefaultInactivityTimeout = "00:10:00";

        private const string ServerPollTimeoutPropertyName = "serverPollTimeout";
        private const string DefaultServerPollTimeout = "00:15:00";

        public PollingDuplexHttpBindingElement(string configurationName) :
            base(configurationName)
        {
        }

        public PollingDuplexHttpBindingElement() :
            this(null)
        {
        }

        protected override Type BindingElementType
        {
            get
            {
                return typeof(PollingDuplexHttpBinding);
            }
        }

        [ConfigurationProperty(InactivityTimeoutPropertyName, DefaultValue = DefaultInactivityTimeout)]
        public TimeSpan InactivityTimeout
        {
            get
            {
                return ((TimeSpan)(base[InactivityTimeoutPropertyName]));
            }
            set
            {
                base[InactivityTimeoutPropertyName] = value;
            }
        }

        [ConfigurationProperty(ServerPollTimeoutPropertyName, DefaultValue = DefaultServerPollTimeout)]
        public TimeSpan ServerPollTimeout
        {
            get
            {
                return ((TimeSpan)(base[ServerPollTimeoutPropertyName]));
            }
            set
            {
                base[ServerPollTimeoutPropertyName] = value;
            }
        }

        protected override ConfigurationPropertyCollection Properties
        {
            get
            {
                ConfigurationPropertyCollection properties = base.Properties;
                properties.Add(new ConfigurationProperty(InactivityTimeoutPropertyName, 
                                                         typeof(TimeSpan), DefaultInactivityTimeout));
                properties.Add(new ConfigurationProperty(ServerPollTimeoutPropertyName, 
                                                         typeof(TimeSpan), DefaultServerPollTimeout));
                return properties;
            }
        }

        protected override void InitializeFrom(Binding binding)
        {
            base.InitializeFrom(binding);

            PollingDuplexHttpBinding pollingDuplexHttpBinding = ((PollingDuplexHttpBinding)(binding));
            this.InactivityTimeout = pollingDuplexHttpBinding.InactivityTimeout;
            this.ServerPollTimeout = pollingDuplexHttpBinding.ServerPollTimeout;
        }

        protected override void OnApplyConfiguration(Binding binding)
        {
            if ((binding == null))
            {
                throw new ArgumentNullException("binding");
            }
            if ((binding.GetType() != typeof(PollingDuplexHttpBinding)))
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, 
                                                          "Invalid type for binding. Expected type: {0}. Type passed in: {1}.", 
                                                          typeof(PollingDuplexHttpBinding).AssemblyQualifiedName, 
                                                          binding.GetType().AssemblyQualifiedName));
            }

            PollingDuplexHttpBinding pollingDuplexHttpBinding = ((PollingDuplexHttpBinding)(binding));
            pollingDuplexHttpBinding.InactivityTimeout = this.InactivityTimeout;
            pollingDuplexHttpBinding.ServerPollTimeout = this.ServerPollTimeout;
        }
    }
}

To configure Polling Duplex in Silverlight 2 solely via the .config file the PollingDuplexHttpBindingCollectionElement class including the relevant namespace and assembly, need to be referenced in the type attribute of the pollingDuplexHttpBinding item under the <bindingExtensions> element as shown in the configuration markup above.

As this is a standard way to create and register a custom binding extension, once the configuration classes and markup are in place as shown and the project successfully builds, you can edit the binding in the same way as the built-in WCF bindings by opening the produced .config file (StockServer.exe.config in this case) in SvcConfigEditor.exe while the service is running:

Binding Extension Binding Properties

For more detail on configuring WCF bindings in general I recommend reading WCF Bindings In Depth by Aaron Skonnard

Posted in PollingDuplex, Silverlight, WCF | Tagged: , , , | 4 Comments »

Silverlight 2 Samples Updated

Posted by petermcg on October 21, 2008

The samples and links to demos on this blog have been updated to be compatible with the release of Silverlight 2.  These projects are typically the result of my curiosity or a desire to unearth benefit from a newly available feature in Silverlight 2.  If they are useful for others so much the better, if not there are certainly lots of other Silverlight 2 samples available elsewhere.

It has always been my intention to make these demos available without any restriction with the release of Silverlight 2, feel free to make use of them however it may benefit you:

Silverlight 2 Pie/Doughnut Chart Demo

Silverlight 2 Polling Duplex Demo – Part 1 : Architecture

Silverlight 2 Polling Duplex Demo – Part 2 : The Server

Silverlight 2 Polling Duplex Demo – Part 3 : The Client

Silverlight 2 Initialization Parameters Demo

Silverlight 2 Stock List Demo – Part 1 : XML file to DataGrid via LINQ to XML

Silverlight 2 Stock List Demo – Part 2 : XML file to DataGrid via WCF

Silverlight 2 Stock List Demo – Part 3 : Making the Grid Tick with Server Deltas via Sockets

The upgrade process was largely painless for me, the main change that sticks in my mind is accounting for the change in case of the GridLinesVisibility property on the DataGrid.  The pie chart live-demos have been updated but are hosted on Silverlight Streaming which does not yet fully support the released version of Silverlight 2, I expect this to change in the near future.

Changes of interest with regard to the Polling Duplex sample include that the server System.ServiceModel.PollingDuplex.dll assembly installed as part of the Silverlight 2 SDK is no longer contained in a folder titled ‘Evaluation’ but instead in the same folder as System.Web.Silverlight.dll.  This corresponds with the summary note here that this technology is no longer in evaluation and can now be used and deployed as part of Silverlight 2 production applications.  Finally, the previously mentioned DuplexReceiver functionality is now manifest as described here and demonstrated here as part of the Silverlight 2 RTW Web Services samples.

Posted in Silverlight | Tagged: , | 4 Comments »

Silverlight 2 Pie Chart (Beta) Updated

Posted by petermcg on August 10, 2008

Edited on 20/October/2008 : Code download updated to support Silverlight 2 RTW

(Code download)

I recently returned from a break and had some time to add a few minor features to the pie chart beta.  If you have any ideas for features not included in this update, now would be a good time to let me know.

IsDoughnut Property and GapScale

One comment recently requested the ability to create a doughnut chart in Silverlight Beta 2.  This functionality has now been added and can be switched on or off via the IsDoughnut property.  The size of the hole in relation to the size of the pie-chart can also be controlled via the GapScale property:

<charts:PieChart x:Name="basicPie" Center="150.0, 150.0" Radius="100.0" IsDoughnut="True" GapScale="0.25"
                 Stroke="LightGray" StrokeThickness="2.0" FontSize="10">
    <charts:PieSegment Percentage="35" Foreground="Orange" />
    <charts:PieSegment Degrees="38" Foreground="Blue" />
    <charts:PieSegment Degrees="72" Foreground="Green" />
    <charts:PieSegment Degrees="101" Foreground="Red" />
    <charts:PieSegment Degrees="23" Foreground="Purple" />
</charts:PieChart>

This produces a chart as follows :

Basic Doughnut Pie Chart

When the IsDoughnut property is set to true, each segment is now comprised of four Points and two ArcSegments:

// Segment Geometry
double pieRadius = this.pieChart.Radius;
double gapRadius = pieRadius * ((this.pieChart.GapScale == 0.0) ? 0.35 : this.pieChart.GapScale);

Point A = GetCircumferencePoint(startAngle, pieRadius);
Point B = (this.pieChart.IsDoughnut) ? GetCircumferencePoint(startAngle, gapRadius) : this.pieChart.Center;
Point C = GetCircumferencePoint(endAngle, gapRadius);
Point D = GetCircumferencePoint(endAngle, pieRadius);

bool isReflexAngle = Math.Abs(endAngle - startAngle) > 180.0;

PathSegmentCollection segments = new PathSegmentCollection();
segments.Add(new LineSegment() { Point = B });

if (this.pieChart.IsDoughnut)
{
    segments.Add(new ArcSegment()
    {
        Size = new Size(gapRadius, gapRadius),
        Point = C,
        SweepDirection = SweepDirection.Clockwise,
        IsLargeArc = isReflexAngle
    });
}

segments.Add(new LineSegment() { Point = D });
segments.Add(new ArcSegment()
{
    Size = new Size(pieRadius, pieRadius),
    Point = A,
    SweepDirection = SweepDirection.Counterclockwise,
    IsLargeArc = isReflexAngle
});

Path segmentPath = new Path()
{
    StrokeLineJoin = PenLineJoin.Round,
    Stroke = this.pieChart.Stroke,
    StrokeThickness = this.pieChart.StrokeThickness,
    Data = new PathGeometry()
    {
        Figures = new PathFigureCollection()
        {
            new PathFigure()
            {
                IsClosed = true,
                StartPoint = A,
                Segments = segments
            }
        }
    }
};

The code above shows how a 2D Path (segmentPath) object is assembled for either a single pie-chart segment or a single doughnut segment.  A close look reveals four Point objects named A,B,C,D and two ArcSegment objects, one drawn in a Clockwise direction and the other in the default CounterClockwise direction.  The following image illustrates the location of these Points and the two ArcSegment objects when the IsDoughnut property is set to true.

Doughnut Arc Points

For a normal pie-chart segment (the default or when IsDoughnut is false) examination of the code above reveals that the Clockwise ArcSegment ending in point C is not required and that Point B becomes the center of the pie-chart.

Label Location, Color and Visibility

The labels can now be displayed inside or outside of the segments and their color and visibility can be controlled via the LabelLocation, LabelStroke and LabelVisibility properties respectively :

<charts:PieChart x:Name="linearPie" Center="150.0,150.0" Radius="100.0" Grid.Row="1"
                 Stroke="LightGray" StrokeThickness="2.0" FontSize="10" LabelLocation="Inside">
    <charts:PieSegment Degrees="45" Foreground="{StaticResource TwoColorLinearBrush}" />
    <charts:PieSegment Percentage="20" Foreground="{StaticResource TwoColorLinearBrush}" />
    <charts:PieSegment Degrees="225.0" Foreground="{StaticResource TwoColorLinearBrush}" />
    <charts:PieSegment Percentage="5" Foreground="{StaticResource TwoColorLinearBrush}" />
</charts:PieChart>

This produces the following chart :

Labels Inside

There have also been a few smaller updates in areas such as the MouseEnter animation and the addition of extra buttons to the demo to demonstrate changing values at runtime.  If you have an idea you would like to see in a future beta of this control, please let me know.

Posted in Pie Chart, Silverlight | Tagged: , , , , , , , | 6 Comments »

Beta 2 Xaml Namespaces

Posted by petermcg on June 16, 2008

The default XML namespace used by XAML in Silverlight 2 has changed in the transition from Beta 1 to Beta 2.  The two namespaces defined by default in Beta 1 were as follows :

<UserControl xmlns="http://schemas.microsoft.com/client/2007"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

In Beta 2 the default namespace has changed :

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

The change has more than likely occurred as part of the work to make the Silverlight 2 API more compatible with WPF, although WPF 3.5 does define a new XML namespace :

xmlns="http://schemas.microsoft.com/netfx/2007/xaml/presentation"

Compatibility should still be maintained however as this namespace or the namespace defined in WPF 3.0 can be used when building WPF 3.5 applications.

XML Namespaces

An XML namespace must be a valid Uniform Resource Identifier (URI), a URI can either be a Uniform Resource Locator (URL) as in the above examples or a Uniform Resource Name (URN) as in the example below :

xmlns:charts="clr-namespace:Charts;assembly=Charts"

These URI’s do not resolve to any useful resource if you put them in the address bar in Internet Explorer for example, their only job is to be unique.  A common way to guarantee that uniqueness throughout the XAML’s travels is to start by using a domain name previously registered with an Internet Naming Authority such as schemas.microsoft.com and add a custom suffix such as netfx/2007/xaml/presentation.

The Default Namespace

There can be only one default XML namespace for an element, any additional namespaces must use a prefix.  In the default XAML markup below, the URI specified by the xmlns identifier without any prefix is the default namespace for the UserControl element and it’s descendant elements (the namespace’s scope) but default namespaces have no affect on attributes.  This means that all unqualified element names within the default namespace’s scope (UserControl and Grid) are implicitly associated with that namespace’s URI.

<UserControl x:Class="SilverlightApplication1.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">

    </Grid>
</UserControl>

This is important because it is this implicit namespace URI that the XAML processor uses to search referenced assemblies to find the matching CLR Type for these unqualified elements.  The image below shows the default references for a standard Silverlight Application containing the above markup :

Default References

These referenced assemblies are searched by the XAML processor for a predefined, hardcoded attribute (the XmlnsDefinition attribute) defining this implicit URI as it’s ‘key’ :

System.Windows Assembly Attributes

When found, as many are in the System.Windows.dll assembly only, the name of a CLR namespace is retrieved from the ‘value’ of the same attribute.  This CLR namespace is then returned as a scope for the XAML processor to search within to find the matching CLR Type for the XAML element.  Both the UserControl and the Grid types are found in the System.Windows.Controls CLR namespace in this way :

UserControl Grid

You can see from the illustration above that twelve CLR namespaces in the System.Windows.dll assembly are mapped to the Silverlight Beta 2 default XAML namespace and that the Beta 1 namespace is currently still supported.  Note that this process is also the method by which the CLR Application type, instantiated by the the Silverlight plug-in control, is mapped :

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
             x:Class="SilverlightApplication1.App"
             >

</Application>

Using the default XML namespace on the Application element in App.xaml, this fundamental CLR type is found in the System.Windows namespace again in the System.Windows.dll assembly :

Application

Prefixed Namespaces

To recap, there can be only one default XML namespace for an element, any additional namespaces must use a prefix and default namespaces have no affect on attributes.  In order to affect an attribute with a namespace a prefix must be used, the prefix then becomes an abbreviation for that namespace.  In this way the x prefix is used by convention with it’s corresponding pre-defined URI to fulfil Silverlight’s contract as an implementation of the XAML language :

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

The XAML language expects implementers of it’s syntax to expose certain fundamental attributes such as x:Class and x:Name (as show in the examples above) so the processor can perform duties such as joining a code-behind file to a XAML file through a partial class and creating members of that class with meaningful names.  This functionality is manifest in the System.Windows.Markup namespace also in the System.Windows.dll assembly.

For more information on XML namespaces in general and how they affect the family of XML technologies, have a look here and here.

Posted in Silverlight, WPF, XAML | Tagged: , , , , | Comments Off on Beta 2 Xaml Namespaces