Welcome to MSDN Blogs Sign in | Join | Help

David Hill's WebLog

Iblogyoublogweblog
Acropolis Floating Layout Pane Sample

At my TechEd session in Orlando over the summer, I showed a version of the Acropolis Notepad sample where I plugged in an MDI-like floating layout pane and added support for viewing XPS documents. I’ve had many requests for this sample code and I am happy to report that I have finally managed to get some time this week to tidy up the code, package it up and write this short summary.

The Floating Layout Pane In Action

You can download the code from here, and some sample XPS documents to play with here.

The sample runs on the August CTP of Acropolis, which in turn requires Visual Studio 2008 Beta 2. There are three projects within the sample solution – the Application itself, the XPS document part & view, and the floating layout pane and its support classes. The following descriptions assume that you are starting from the Notepad sample that ships alongside the Acropolis CTP here.

Let’s walk through some of the more important parts of the code, starting with the XPS document part…

XPS Document Part & View

The XPS document part is actually very simple, thanks in part to the excellent XPS support provided by WPF. In our sample we have a document part class that’s responsible for loading the XPS document from disk, and a document part view class which is responsible for displaying the XPS document to the user.

The XPSDocumentPart class looks like this:

[DefaultView( typeof( XPSDocumentPartView ) )]
public partial class XPSDocumentPart : DocumentPartBase
{
    private XpsDocument _xpsDocument;

    public XPSDocumentPart()
    {
        InitializeComponent();

        // The document is readonly so disable the Save
        // and the SaveAs commands.
        base.SaveCommandInternal.Enabled = false;
        base.SaveAsCommandInternal.Enabled = false;
    }

    protected override void OnLoad( System.IO.Stream input )
    {
        _xpsDocument = new XpsDocument( base.FileName,
                              
System.IO.FileAccess.Read );
        Document.Value = _xpsDocument.GetFixedDocumentSequence();
    }
   
}

The XPSDocumentPart class represents an XPS document within the application and so derives from DocumentPartBase. In this sample, the XPS documents are read-only so we disable the Save and SaveAs command provided by the base class. The only other thing we need to do then is to read the XPS document contents and get the fixed document sequence to expose to the view.

The XPSDocumentPartView class is responsible for displaying the document to the user. In this sample, the view class simply uses the WPF DocumentViewer control which provides a lot of functionality out of the box, allowing the user to zoom, scroll, pan and search through the XPS document. The XAML for the view class is very simple:

<Border BorderThickness="6" BorderBrush="Gray">
 
<DocumentViewer Document="{Binding Path=Document.Value, Mode=OneWay}"/>
</Border>

The WPF DocumentViewer control does all of the hard work of course, we only have to bind its Document property to the underlying XPS document provided by the Document connection point. You could imagine providing a custom rendering of the XPS document if you needed one, say to enable read-write creation of XPS documents using a custom editor.

The last thing we need to do is to register the XPS Document Part with the app’s document manager so it knows to associate XPS documents with it. We register the part, along with a file extension in Application.xaml like this:

<Afx:DocumentManager x:Name="DocumentManager">
  <Afx:DocumentManager.Templates>

    <Afx:DocumentTemplate x:Name="DocumentTemplate"
                        
Type="{x:Type xps:XPSDocumentPart}" FileExtension=".xps" />

  </Afx:DocumentManager.Templates>
</Afx:DocumentManager>

The Acropolis Notepad sample demonstrates how you can build document centric applications and extend them by registering new document types. Of course not all applications are document style applications, but the power of Acropolis lies in the ability of its modular approach to support these kinds of common patterns.

So that’s the XPS part of the sample. Let’s take a look at the (much more interesting) floating layout pane.

Floating Layout Pane

The Acropolis architecture is aimed at supporting the notion of ‘separation of concerns’. It provides a modular framework that lets you plug in or swap out different strategies for different parts of the application, like layout, navigation, authentication, etc. The floating layout pane class is an example of how to implement a custom layout strategy.

In this sample, we’re going to replace the Notepad’s default tab layout strategy with one that provides free-floating windows that we can drag around (similar to the MDI layouts of ye olde MFC). It also provides a fly-out ‘docking area’ where minimized windows are displayed along with a pre-view thumbnail.

Basic Behavior

There are a couple of additional classes in the sample that provide support for resizing, dragging and for managing the pre-view thumbnail, but the main class is the FloatingLayoutPane class. This class implements the core layout strategy and defines how our custom layout pane control interacts with the rest of the Acropolis architecture.

public partial class FloatingLayoutPane :
                  Microsoft.Acropolis.Windows.LayoutPane
{
    …
}

The UI for the FloatingLayoutPane class essentially consists of a WPF Canvas control embedded in a grid:

<Canvas x:Name="_canvas" Grid.Row="0" Grid.Column="0"
   
AllowDrop="False"
   
PreviewMouseLeftButtonDown="CanvasPreviewMouseLeftButtonDown"
    PreviewMouseMove="CanvasPreviewMouseMove"
    PreviewMouseLeftButtonUp="CanvasPreviewMouseLeftButtonUp">
</Canvas>

Notice that the FloatingLayoutPane class derives from the Acropolis LayoutPane base class. This base class implements the basic behavior of all of Acropolis’ layout panes (including the SplitLayoutPane and the TabLayoutPane classes that ship with the Acropolis CTP). It provides a number of virtual methods that we will need to override in order to implement our floating pane layout strategy.

The two most important virtual methods are OnChildPaneInsertRequest and OnChildPaneRemoveRequest. These methods are called whenever the application’s navigation manager adds a new part to the current scope and wants a view for it to be added to the UI, or when a part is closed and its view is to be removed from the UI. A custom layout pane overrides these methods so that it can arrange the new child pane, using whatever strategy it implements.

In our case, when a new child pane is added to the floating layout pane, we need to add it the Canvas control, set its position and make sure that the child pane displays a chrome with a collapse button. So the first part of our OnChildPaneInsertRequest implementation looks like this:

protected override void OnChildPaneInsertRequest( object sender,
                  
PaneCollectionItemCancelableActionEventArgs e )
{
    base.OnChildPaneInsertRequest( sender, e );
    Pane pane = e.Item;

    Canvas.SetLeft( pane, newPanePosition.X );
    Canvas.SetTop( pane, newPanePosition.Y );

    pane.ShowChrome   = true;
    pane.ShowCollapse = true;
    pane.Width  = newPaneSize.Width;
    pane.Height = newPaneSize.Height; 

    this._canvas.Children.Add( pane );

To support resizing of child panes within the floating layout pane, we also create a ResizingAdorner and attach it to the child pane. The ResizingAdorner class is an adorner that allows the user to resize the element that’s being adorned, in our case the child pane:

    AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer( pane );
    adornerLayer.Add( new ResizingAdorner( pane ) );

The ResizingAdorner adds a Thumb control to the bottom right hand corner of the child pane so that the user can resize it using the mouse.

Finally, to support the animated minimize effect, we subscribe to the PaneStateChanged and PaneStateChanging events and register a name with the layout pane so we can animate it:

    pane.PaneStateChanged += new RoutedEventHandler( OnPaneStateChanged );
    pane.PaneStateChanging += new EventHandler<PaneStateChangingCancelEventArgs>
                                          ( OnPaneStateChanging );

    // Assign a unique name to the child pane.
    pane.Name = String.Format( "ChildPane{0}", paneCounter++ );
    this.RegisterName( pane.Name, pane );
}

Note that the LayoutPane base class includes virtual methods that are called when the user minimizes or maximizes a child pane that it is managing. Unfortunately, the current implementation does not pass a reference to the actual child pane that the event relates to. Doh! This is a bug :-). We can work around it though by subscribing directly to the events above.

The OnChildPaneRemoveRequest method is called when the user closes a child pane. We need to unsubscribe from the child pane’s events, remove the adorner, unregister its name, and finally remove it from the canvas control:

protected override void OnChildPaneRemoveRequest( object sender,
                  
PaneCollectionItemCancelableActionEventArgs e )
{
    base.OnChildPaneRemoveRequest( sender, e );

    Pane pane = e.Item;
    pane.Visibility = Visibility.Collapsed;

    pane.PaneStateChanged  -= new RoutedEventHandler( OnPaneStateChanged );
    pane.PaneStateChanging -= new EventHandler<PaneStateChangingCancelEventArgs>
                                                                                 ( OnPaneStateChanging );

    AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer( pane );
    adornerLayer.Remove( new ResizingAdorner( pane ) );

    this.UnregisterName( pane.Name );

    this._canvas.Children.Remove( pane );
}

That pretty much completes the core behavior of the floating layout pane. You can implement any number of different layout strategies by overriding the two methods described above and specifying exactly how the child panes are laid out. Of course, the actual details of the layout strategy can be quite complex, but the architecture allows you to encapsulate this complexity in a re-usable pane control that you can very likely re-use in many different types of applications.

The sample FloatingLayoutPane class implements a couple of other features that enhance the user experience – the ability for the user to drag and drop panes around the canvas, and a fly-out docking area for minimized windows. Let’s take a quick look at how these are implemented.

Child Pane Drag & Drop

The FloatingLayoutPane control allows the user to drag child panes around its canvas by clicking and dragging the child pane via its chrome area. Essentially this works by subscribing to the mouse left button up/down and mouse move events and updating the child pane’s position on the canvas control.

In the left mouse button down event handler, we first check to see if the user clicked on the child pane’s chrome area (and not any of the collapse, view or command buttons). The Pane class conveniently provides an IsDragArea method for this. Once we determined that the user has clicked on the chrome area, we just need to keep track of the mouse position and capture the mouse:

if ( pane.IsDragArea( (FrameworkElement)e.OriginalSource ) )
{
    isDown = true;
    startPoint = e.GetPosition( _canvas );
    originalElement = e.Source as PartPane;
    _canvas.CaptureMouse();
    e.Handled = true;
}

In the mouse move event handler, we make sure that the mouse has moved more than the minimum amount and then start the drag operation proper by calling the DragStarted method. This method creates a DropPreviewAdorner for the child pane – in this implementation, it’s actually this adorner that we are dragging around and not the child pane itself. The DropPreviewAdorner provides a visual of the child pane that it represents (using a VisualBrush), but otherwise is just a simple adorner.

As the user continues to drag the mouse around, we update the adorner’s position:

Point currentPosition =
             System.Windows.Input.Mouse.GetPosition( _canvas );
overlayElement.LeftOffset = currentPosition.X - startPoint.X;
overlayElement.TopOffset  = currentPosition.Y - startPoint.Y;

When the user releases the left mouse button, we tidy up the adorner and update the position of the original child pane:

AdornerLayer.GetAdornerLayer( overlayElement.AdornedElement )
                                   .Remove(
overlayElement );

_canvas.Children.Remove( overlayElement );

if ( !canceled )
{
    Canvas.SetLeft( originalElement, originalLeft + overlayElement.LeftOffset );
    Canvas.SetTop( originalElement, originalTop + overlayElement.TopOffset );
}

NOTE: This implementation may not be the best way to implement drag behavior for child panes! Performance can be slow if the pane being dragged is large or complex. I am not sure why this is so yet – it needs more investigation and/or a WPF expert :-). I suspect it's something to do with using the Visual Brush...

That’s pretty much it for the dragging functionality – take a look at the code for the fine details, but it’s pretty simple thanks to WPF’s canvas control and event bubbling and tunneling.

Fly-Out Docking Area

The FloatingLayoutPane has a fly-out docking area where minimized windows are displayed. This is kind of similar to the Windows Taskbar. Essentially, it just consists of a ListBox arranged in a DockPanel that is animated when the user mouses over it:

<DockPanel Grid.Column="1" Width="17" LastChildFill="True"
              Style="{StaticResource flyOutPanelStyle}">

The flyOutPanelStyle defines animation storyboards that are triggered on mouse enter and leave:

<Style x:Key="flyOutPanelStyle" TargetType="{x:Type DockPanel}">
  <Style.Triggers>
    <EventTrigger RoutedEvent="DockPanel.MouseEnter" >
      <EventTrigger.Actions>
        <BeginStoryboard>
          <Storyboard TargetProperty="Width">
            <DoubleAnimation To="150" Duration="0:0:0.5"
                AccelerationRatio="0.33" DecelerationRatio="0.33"
                AutoReverse="False"/>
          </Storyboard>
        </BeginStoryboard>
      </EventTrigger.Actions>
    </EventTrigger>
    <EventTrigger RoutedEvent="DockPanel.MouseLeave" >
      <EventTrigger.Actions>
        <BeginStoryboard>
          <Storyboard TargetProperty="Width">
            <DoubleAnimation To="17" Duration="0:0:0.5"
                AccelerationRatio="0.33" DecelerationRatio="0.33"
                AutoReverse="False"/>
          </Storyboard>
        </BeginStoryboard>
      </EventTrigger.Actions>
    </EventTrigger>
  </Style.Triggers>
</Style>

A ListBox is used to display information about the minimized windows. Data binding is used to bind the ListBox to the list of minimized windows, which is actually a list of PaneThumbnail objects. The PaneThumbnail class is used to store a preview image of the child pane and its title. The ListBox uses a data template to define how this information is displayed.

<ListBox x:Name="_tray" SelectionMode="Single"
    ItemsSource="{Binding Path=MinimizedPanes}"
    MouseDoubleClick="OnTrayItemDoubleClick"
    SelectionChanged="OnTraySelectionChanged"
    ScrollViewer.HorizontalScrollBarVisibility="Disabled"
    ScrollViewer.VerticalScrollBarVisibility="Auto"
    >
  <ListBox.ItemTemplate>
    <DataTemplate>
    <StackPanel Orientation="Horizontal">
      <Image Height="16" Width="16" Source="{Binding
                 Path=Thumbnail}" />
      <TextBlock Margin="4,4,4,4" Foreground="White"
                 Text="{Binding Path=Title}" >
        <TextBlock.ToolTip>
          <StackPanel Orientation="Vertical" Margin="4,4,4,4">
            <Image Height="120" Width="120"
                 Source="{Binding Path=Thumbnail}" />
            <TextBlock HorizontalAlignment="Center"
                 Foreground="Black" Text="{Binding Path=Title}"
                 TextTrimming="CharacterEllipsis" />
          </StackPanel>
        </TextBlock.ToolTip>
      </TextBlock>
    </StackPanel>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

The data template uses a tooltip to display a preview image for the minimized window. This image is generated just before the child pane is minimized using the RenderTargetBitmap class within the OnPaneStateChaning event handler:

RenderTargetBitmap rtb = RenderPaneThumbnail( childPane );
PaneThumbnail thumbNail = new PaneThumbnail( childPane, rtb );
thumbnailCache.Add( childPane, thumbNail );

Once the PaneThumbnail is created, it is added to the minimized window list so it automatically shows up in the ListBox because of the data binding. When the user double clicks on a minimized window in the ListBox, the original child pane is added back to the canvas control and the pane’s thumbnail is removed from the list.

NOTE: There is a known bug in the Pane base class that prevent the child pane from being maximized programmatically when it is reinstated on the canvas. The child pane’s chrome shows up ok, but the user has to manually maximize the child pane to see its contents. Ho hum, it is a preview release after all…

Fin

There are another couple of minor features in the sample, like the animation of the child panes as they are minimized. You can take a look at the code and step through it to see how this works. The sample is not fully implemented yet though – the animation for minimize is there but not for maximize, and there is no z-order handling of the child windows. Hopefully I will get some time soon to complete these features and post an update...

I hope you find this sample interesting and useful. I wrote this to highlight how you can plug in different (and rich) layout strategies very easily without having to change the core implementation of the application. The modular separation of concerns that Acropolis supports is the magic behind this.

Thanks for your continued evaluation of Acropolis. Your feedback is very valuable to us.

Acropolis on .NET Rocks!

While we were at TechEd, we were interviewed by Carl and Richard from .NET Rocks! about Acropolis. They've just posted the interview here:

http://www.dotnetrocks.com/default.aspx?showNum=248

Listen to me, Kathy (our PM leading the UI features of Acropolis) and Nate (one of our QA leads on Acropolis) talk about Acropolis, what it is, where it came from, and where it's going, and let us know what you think...

We also recorded a 'Fish Bowl' video interview that should be posted in the next week or so - I'll post a link as soon as it's published.

Watch This Space: Acropolis July CTP Coming Soon!

We are just putting the finishing touches to the next CTP release of Acropolis - I'll post details of the release when it happens sometime next week but all of the existing links from www.WindowsClient.net/Acropolis should continue to work OK. Apart from the new features and bug fixes (more details in my next post) you'll notice a couple of minor changes in how we're going to manage our CTP release from now on.

First, we decided to change the naming of the CTP releases to include the name of the month in which they are released. This is to bring the naming in line with other CTP released from Microsoft. We are aiming to have a release approximately every month over the summer. Releasing two CTP's in the same month is a nice problem for us to have and we'll cross that bridge when we get to it :-).

Second, we decided to split out the samples from the core release. This frees us up to update or add more samples independently of the core release. We'll be posting updated samples a couple of days after each of the core releases.

So nothing earth shattering really, just trying to make it easier for us to be more agile and to ship CTP's faster...

July CTP will still be based on Visual Studio 'Orcas' Beta 1, since it will be released before Beta 2 is available, so unfortunately there will still be a couple of designer issues (happily these have been fixed in the Beta 2 release of Visual Studio). We'll have an updated CTP very soon after Beta 2 is released.

Meanwhile, Kevin Hoffman continues to provide very valuable feedback and keep us on our toes!

First of all, Kevin rightly points out that part to part communication is currently something you have to do manually - i.e. there is no automatic 'composition' by the framework; something that hooks parts together for you at run-time. Kevin is right that this is the cornerstone of composite application building. Rest assured that we have not neglected this scenario. In fact it has been central in our minds as we designed Acropolis. We have some of the basic plumbing in place in CTP 1 (connection points, part-view contract, etc) but we don't yet have full support for composability. We actually have a very nice composition engine working (well I think it's very nice, but you are the ultimate judges) and will be integrating it into a CTP release very soon (unfortunately, not in the July CTP though :-().

Secondly, Kevin points out that Acropolis doesn't currently support multiple top-level windows very well. This is an excellent point and we've had this feedback from a number of customers. We've put some thought into this and come up with a significantly improved design. It'll be integrated around the same time that we integrate the composition engine noted above and will be released soon.

As always, we love getting feedback like this - as painful as it might be sometimes :-) - so thanks Kevin and and keep it coming.

Acropolis Team Blog

Be sure to check out the Acropolis Team Blog too. We'll be posting regularly to this blog to keep you up to date with our progress but it also provides a venue where you can direct questions right to the whole Acropolis team.

The other nice thing about the team blog is that it lets all of the Acropolis team interact directly with the community, and lets you see firsthand some of the extremely cool work they are doing.

Take this post by Ricky Tan, a SDET on the Acropolis team, for example. In this post Ricky shows how you can very easily extend the Notepad sample (that ships with the Acropolis CTP 1 release) to provide a web browser view for HTML files. This also shows how you can integrate Windows Forms controls into your WPF Acropolis application using the Windows Forms Integration features of .NET 3.0. Nice work Ricky.

Three New Acropolis Videos Available!

We've just posted three new videos to the Acropolis community site:

  • Using Acropolis PartPanes - In this video, David Poll shows you how the Acropolis PartPane control provides basic management & support services for part views. David shows you how you can use a PartPane to control placement of your part views, and how to configure the various features of the PartPane, such as the part command menu. Finally, David shows you how to create an additional view for your part and how you can use the PartPane's view switching features to let the user switch between them.
  • Using the Acropolis Designer - In this video, David introduces the Acropolis component designer. This designer provides a visual representation of the non-visual components in your application. It allows you to define and configure a lot of the behavior of your application without having to write a lot of code. David runs through the various elements of the designer and shows you how to use it to configure the navigational behavior of your application's parts, and how to configure its commands, properties, and service dependencies.
  • Using Transitions in Acropolis - And finally, in this video, Kathy Kam shows you one of the cooler UI features of Acropolis: Transitions. Transitions are canned animations that the PartPane control can use when switching between views. These provide support for a richer user experience by giving the user a contextual, animated re-arrangement of the UI, rather than a sudden visibility change. Kathy shows you how to add a transition effect to the PartPane control and demonstrates some of the pre-built transitions that comes in the Acropolis CTP 1 release.

As you've probably noticed, the quality of these videos is much better than the introductory video that I did. We had some production problems in the first video (which we've since overcome thanks to David Poll) so we'll be reposting that video soon with better video and sound quality.

Acropolis @ TechEd: Q2 – Cool applications with little or no code? Really? Are you sure?

Continuing the series of posts on the top 5 Acropolis questions at TechEd 2007...

Now this is a really good question and usually led to a great discussion!

It usually followed in response to one of three things - the demos that we gave, the template and wizard features in Acropolis, or our adoption of XAML as a declarative format for components.

Simple Apps vs Real-World Apps

This question is usually asked in response to some of the demos that we've been showing here at TechEd. Since Acropolis is meant to provide the plumbing for an application (leaving you to focus on your business logic) we took the decision to emphasize the Acropolis plumbing in the demos that we gave. This would allow developers, so our reasoning went, to see more clearly exactly what functionality Acropolis is providing.

For example, in my break-out session I built a simple text editing application and demonstrated how you can swap in and swap out various components to support different patterns for navigation, layout, etc. I show the beginnings of this in the Getting Started video on the Acropolis home page on WindowsClient.net. I chose this example specifically because this application is pretty much all plumbing and does not have much business logic at all - in fact the whole application only has about 20 lines of code (including the pluggable spell check service) - so that I could focus on how the app model fits together and how the visual designers allow you to specify a large part of the behavior of the application without the need for plumbing code.

It seems, though, that some of the attendees that saw this demo got the impression that we were claiming that you could build all applications, at any level of complexity, using just the visual designers. Unfortunately, this isn't the case, as I'll describe below. In hindsight we maybe should have demonstrated building a more real-world application, something that contains non-trivial business logic, but then, no doubt, we'd have spent most of our demo time on business logic code rather than showing off the Acropolis application model. Ho hum...

Templates and Wizards

One of the goals of Acropolis is to let you focus more on your business logic code, and this notion extends to the situation when you first create the project too. One of my pet peeves is when you select File/New Project in Visual Studio and are invariably presented with a blank page or form and are left to go write all of the plumbing yourself from scratch, again.

So we set out to beef up the template system in Visual Studio so that we could provide richer templates for common application types. These templates will define enough of the application's structure so that you can start to focus on business logic immediately after your project is created. When we demo this feature, some developers saw this as an attempt to ‘pigeon-hole' applications into two or three restrictive types, or to just generate the code that we would have had to write before.

But our intention here is not to provide templates for all conceivable types of applications. - we'll probably only ship, say, templates for the 5 most application types - but to give you a much quicker turnaround time between project creation and getting stuck into writing your business logic code. And of course you'll be able to create your own templates, to support, for example, your corporate standard application types, as a way to speed up development.

Acropolis templates will also be configurable via an ‘Application Designer' which will let you choose between the various options provided by the template and give you a visual representation of the overall structure of your application. Again, this lets you start with a application that is as close as possible to the type of application you want to build.

In CTP 1 the Application Designer takes the form of a wizard. At present, the wizard lets you choose between a few simple options but it is not re-entrant - i.e. you can't go back and change your decisions after the initial code is generated, so what we have now is very similar to the old MFC one-shot application wizard. But we know that this isn't a good long term solution. In upcoming CTPs we'll be allowing you to go back and change the options for your application again and again without having to generate a new project and copy all of the code over.

This allows for a more iterative development process. You might start with a default application, implement your business logic code, get it into the hands of some users for feedback, make changes to your applications configurable settings, and then go round again for another round of feedback.

Why XAML?

If you've downloaded and checked out the CTP 1 bits, you'll have noticed that we're using a declarative approach to define both the business logic components as well as the visual components of an application. Specifically, we're using XAML (Extensible Application Markup Language) to define business logic components, and to define the WPF user interface for those components.

When we demo this feature to developers, they are often initially surprised because they thought that XAML was exclusively a WPF technology (which we point out is not the case), and then they immediately ask us why we took this declarative approach. One part of the answer is that we wanted to more cleanly separate out the definition, or ‘logical structure', of a component from its implementation. Another part is that we wanted to provide a graphical way for you to define or visualize the logical structure of your component without necessarily having to write or read code.

We are finding from many discussions that this typically leads to a misconception about our intention here. Sometimes, people take this approach to mean that we are trying to obviate the need for code (or maybe even developers) altogether, which they point out is the ‘Impossible Dream' or ‘Holy Grail' of application development. We of course agree that this is unrealistic (at least for now J) - see an interesting discussion on these points here and here.

In reality, we expect that you will need to write lots and lots of code to build a real-world client application, even with Acropolis. Our goal is to allow you to focus your coding efforts on your business logic or business problem and not have to code up your applications plumbing. And of course, technically you could say that XAML is code of a sort...

Using a declarative approach like this, though, provides a number of benefits:

  • Using XAML gives you a very concise way to express the structural aspects of your component - not just the external ‘class interface', but how it is structured internally. For example, it allows you to cleanly define how any child components or services that your component uses are configured or interact with each other.
  • It allows you to concentrate more on the code that defines the actual implementation of your component. In other words, we want to make it so that 99%+ of the code that you do write is the actual code that will solve your business problem and not plumbing or glue code.
  • It is much easier for us (or you) to build visual designers or other tools (including test tools) for your component since its structure is more easily ‘machine-parsable'. It also allows for a looser coupling between the application model and the tools allowing each of them to evolve more quickly.

The last point probably deserves some more detail.

Some visual tools read and write code directly without having an intermediate declarative step. But this is actually difficult and time-consuming thing to get right, since the tool and the model for the code that it reads and writes always have to be in lock-step. Why? Well this approach means that as a developer you can only express your intent in ‘raw' code which in turn implies a specific application model of some sort (i.e. a specific API or structure for the code). If the application model changes, the designer breaks; if the designer changes, it doesn't generate the right code. Having an intermediate and concise way for you to express your intent gives us more freedom to change the designer or the application model independently.

Of course the declarative format defines the ‘contract' between the tool and the application model, and you have to handle changes to the declarative format carefully (there is no such thing as a free lunch) but having this loose coupling allows us to quickly try different ideas and evolve the application model whilst keeping a high level of tool support at all times.

In fact, we expect that there will be a lot of changes and improvements to the application model in the coming months and we didn't want the tool experience to lag by too much. We have heard loud and clear from developers about the problems and woes that poor or late tool supports causes (<cough>WPF</cough>).

What are Connection Points?

Let me give you a specific example of the kind of application model changes we could make without affecting the designers and tools too much. At the same time, I'll answer another common question we often get asked J

In typical Acropolis fashion, we have tried to provide support for the typical or common ways or patterns that components in an application use to interact with each other. We encapsulate these patterns into distinct entities called ‘Connection Points'. We have connection points that represent component to component data exchange and notification patterns, for component to service interaction patterns, and for command handling patterns (we'll be adding more soon, like the pub-sub data exchange pattern that CAB developers are used to).

By dragging and dropping these connection points onto your component's visual design surface, you are specifying the patterns that the component will use to interact with its environment and with other components.

For example, the ‘Command Handler' connection point represents the fact that the component can handle a specific command when it is invoked. As well as the name or type of the command to be handled, you'd probably like to specify the exact behavior of the way that the command is handled.

For example, you'd probably want to specify some information about the command handler, for example a name or description that an external component might use to, say, automatically generate UI for the command (e.g. via a context menu). Or you might want to specify whether the command