Loading UI From Markup

I’ve got to say that my absolute favorite feature of WPF is that you can create your entire user interface in a string of XAML. There isn’t a whole lot to it:

object obj = System.Windows.Markup.XamlReader.Load(
new System.Xml.XmlTextReader(new System.IO.StringReader(xaml)));

You’ll need some extra plumbing in your application to read the string of XAML from your file system, database, service, or whatever, but you don’t need much more to create an interactive application that binds to data, displays fancy controls, and runs animations. Of course, that means all the complexity is in the XAML, but the great thing is that rather than have to redeploy your application to enhance it or fix UI issues, you just need to deploy new XAML, which is much manageable.

A few caveats to this: first off, you don’t have a code behind file, and can’t use x:class to specify the class that is going to handle your events. But to be honest, with the data binding capabilities in WPF, you don’t need as much event handling as you might think. Instead of creating event handling code all over the application, create some highly reusable classes that implement the System.Windows.Input.ICommand interface, and use data binding to attach instances of those classes to the objects they need to manipulate.

Here’s an example…just need to create an instance of this SortDescriptionController in the Resources, bind the CollectionViewSource property to a CollectionViewSource that you declaratively add to any collection, set the SortField property to the name of the field to use for sorting, and then bind the Command for any ICommandSource (button, hyperlink, or menuitem) to your instance of the SortDescriptionController, with a Path on the binding pointing to the Sort command. Sure, this is some code, but rather than writing dozens of event handlers everywhere you want sorting, once you have a few controllers for what you need, you can reuse them all over your application.

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;

namespace LooseXaml
{
    public class SortDescriptionController : DependencyObject
    {
        public ICommand Sort { get; protected set; }

        public String SortField
        {
            get { return (String)GetValue(SortFieldProperty); }
            set { SetValue(SortFieldProperty, value); }
        }

        public static readonly DependencyProperty SortFieldProperty =
            DependencyProperty.Register("SortField", typeof(String), typeof(SortDescriptionController), new UIPropertyMetadata(null));

        public CollectionViewSource CollectionViewSource
        {
            get { return (CollectionViewSource)GetValue(CollectionViewSourceProperty); }
            set { SetValue(CollectionViewSourceProperty, value); }
        }

        public static readonly DependencyProperty CollectionViewSourceProperty =
            DependencyProperty.Register(";CollectionViewSource", typeof(CollectionViewSource), typeof(SortDescriptionController), new UIPropertyMetadata(null));

        public SortDescriptionController()
        {
            this.Sort = new SortCommand(this);
        }

        private class SortCommand : ICommand
        {
            private SortDescriptionController _parent;

            public SortCommand(SortDescriptionController parent)
            {
                this._parent = parent;
            }

            #region ICommand Members

            /// Do some validation to make sure we are wired up properly.
            public bool CanExecute(object parameter)
            {
                return !String.IsNullOrEmpty(_parent.SortField)
                     && _parent.CollectionViewSource != null;
            }

            public event EventHandler CanExecuteChanged;

            public void Execute(object parameter)
            {
                if (CanExecute(parameter))
                {
                    _parent.CollectionViewSource.SortDescriptions.Add(
                        new SortDescription(_parent.SortField,
                            ListSortDirection.Ascending));
                }
            }

            #endregion
        }
    }
}

Wiring it all up in XAML to get a button you can use to sort any collection without event handlers in code behind:


<Grid>
    <Grid.Resources>
        <ObjectDataProvider x:Key="winDirInfo" ObjectType="{x:Type io:DirectoryInfo}">
            <ObjectDataProvider.ConstructorParameters>C:\Windows</ObjectDataProvider.ConstructorParameters>
        </ObjectDataProvider>
        <ObjectDataProvider x:Key="winDir" ObjectInstance="{StaticResource winDirInfo}">
            <ObjectDataProvider.MethodName>GetFiles</ObjectDataProvider.MethodName>
        </ObjectDataProvider>
        <CollectionViewSource x:Key="cvsFiles" Source="{StaticResource winDir}" />
        <looseXaml:SortDescriptionController x:Key="sortModified" CollectionViewSource="{StaticResource cvsFiles}" SortField="LastWriteTime" />
    </Grid.Resources>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition Height="30" />
    </Grid.RowDefinitions>
    <ListView ItemsSource="{Binding Source={StaticResource cvsFiles}}" Grid.Row="0">
        <ListView.View>
            <GridView>
                <GridView.Columns>
                    <GridViewColumn Header="Filename" DisplayMemberBinding="{Binding Name}" />
                    <GridViewColumn Header="Last Modified" DisplayMemberBinding="{Binding LastWriteTime}" />
                </GridView.Columns>
            </GridView>
        </ListView.View>
    </ListView>
    <Button Command="{Binding Source={StaticResource sortModified}, Path=Sort}" Grid.Row="1">Sort By Date</Button>
</Grid>
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: