Just some fun with Avalon


Did you know that the text editor in Avalon is currently implemented on the commanding architecture? Most of the keyboard stuff goes through commands - inserting text is a very interesting topic I'll save for another post.


Commands are typically exposed as entries on some class or another. In this case, we have commands on EditingCommand and ApplicationCommand. I built a little sample app that lists these commands and lets you fire them. Along the way, we'll also learn a bit about the cool stuff you can do with data binding (interesting article over here).


First, let's create a new project and add the following XAML to the window. (note: all this code is based on the May bits)


<Window x:Class="VancouverApp.Window1"
 xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
 xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
 Text="My Vancouver App"
 >
<DockPanel>
 <Button DockPanel.Dock="Top"
  Click="DisplayButtonClick">Display Commands</Button>
 <ListBox DockPanel.Dock="Left"
  Name="CommandsListBox" PreviewKeyDown="CommandsKeyDown"/>
 <Button DockPanel.Dock="Bottom"
  Click="RunCommandClick">Run Command</Button>
 <RichTextBox Name="EditingBox" />
</DockPanel>
</Window>


Here we have a couple of Button controls, a ListBox, and a RichTextBox we will fire the commands on.


Now, let's go to the code-behind file and start adding our event handlers.


private void DisplayButtonClick(object sender, RoutedEventArgs e)
{
  // Build a list of commands we'll use.
  List<RoutedCommand> commands = new List<RoutedCommand>();
  AddCommandsFromType(typeof(EditingCommands), commands);
  AddCommandsFromType(typeof(ApplicationCommands), commands);


  // Now, let's decide how we want RoutedCommands to look like...
  FrameworkElementFactory contentFactory = new FrameworkElementFactory(typeof(TextBlock));
  contentFactory.SetBinding(TextBlock.TextContentProperty, new Binding("Name"));


  // ... and make sure that that's the template that's used.
  DataTemplate commandTemplate = new DataTemplate(typeof(RoutedCommand));
  commandTemplate.VisualTree = contentFactory;


  // Wire everything and we're ready to go!
  CommandsListBox.ItemsSource = commands;
  CommandsListBox.ItemTemplate = commandTemplate;
}


This populates the ListBox with a bunch of commands, using a helper AddCommandsFromType. AddCommandsFromType, will add all static properties that are of type RoutedCommand (which is how these commands are exposed). Note how C# generics make the code straightforward and type-safe, by the way.


A little bit of Reflection will come in handy here. If I were writing a real application, I wouldn't blinding go and pick all RoutedCommands, but I'm lazy (which is ocassionally a good trait in developers).


private static void AddCommandsFromType(Type type, List<RoutedCommand> commands)
{
  foreach (PropertyInfo property in type.GetProperties())
  {
    // Skip any non-static properties, as we don't have an instance.
    if (!property.GetGetMethod().IsStatic)
    {
      continue;
    }


    // Get the property and see if it's a valid RoutedCommand.
    RoutedCommand command = property.GetValue(null, null) as RoutedCommand;
    if (command != null)
    {
      commands.Add(command);
    }
  }
}


The handlers for firing the command are super-straightforward.


private void RunCommandClick(object sender, RoutedEventArgs e)
{
  // The selected item will be the underlying command we put
  // in the list, not the generated TextBlock - whee!
  RoutedCommand selectedCommand = CommandsListBox.SelectedItem as RoutedCommand;
  if (selectedCommand != null)
  {
    selectedCommand.Execute(EditingBox);
  }
}


private void CommandsKeyDown(object sender, KeyEventArgs e)
{
  if (e.Key == Key.Enter)
  {
    RunCommandClick(null, null);
  }
}


Now, to play with this, run the sample, write up some content and go about selectin items and pressing Enter. This will trigger the actions on the RichTextBox. Note that the text selection is invisible because the list box takes focus.


As usual, everything is subject to change, no warranties implied, etc. - but it's still fun to play with this, and to see how straightforward it is to put things together in Avalon.


 


This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm.


Comments (3)

  1. Kris says:

    Just wondering if you know of any sample apps or blog entries regarding how Avalon could be used for Intranet apps. Most of the entries I see are 3D- Graphics kind of apps. I want to do a presentation of a Avalon+Indigo based apps to my management and I am desperately looking for samples with regard to Avalon for these scenarios.

  2. Kris, Adam Nathan mentioned that he’d write an Avalon+Indigo version of Internet Hearts, but the timeline wasn’t defined (read about it at http://blogs.msdn.com/adam_nathan/archive/2005/05/02/414174.aspx).

    Now, part of the reason why it might be hard to find good Avalon + Indigo demos right now is that they’re not tightly coupled. If you have an existing app, you can revamp the presentation with Avalon, or you can leverage Indigo to reach out and communicate with other apps/systems, but you don’t necessarily have to do both at the same time – and I think this is goodness.

  3. Kris says:

    Thanks for the info. My main intention is to show the power of Avalon – the power of the Avalon UI and persuade the management to move to ClickOnce and finally Avalon as against ASP.NET. I am more interested in the Avalon pieces. It will be nice if MS could port one of the ASP.NET apps like Duamish or so to Avalon. Just a thought….

Skip to main content