Archive for the 'Caliburn' Category

25
Jan
10

Migration to Caliburn v2

After being held captive by the aliens for the last couple months… ehm… what? it’s hardly credible?

The plain truth is that I’m having a very busy period at work, so I had to cut hobbies to avoid my daughter stopping calling me “papà” (“daddy”, in italian).

Nevertheless, I missed the pleasure of writing something here (I have to exercise my English!) so I’ll report about my effort to port a couple project I’m working on to Caliburn v2. I froze my references to v1.x branch some time ago and deferred the update until today, for the lack of necessary time and because I was afraid to slow down my work with breaking changes.
But all new stuff introduced by Rob in Caliburn trunk was too tempting; plus, I started to be hardly able to follow new Caliburn forum posts about new features, so I finally decided to switch.

It was not hard at all, I have to say.

I still have to refine class and variables names to follow the new “Screens” naming (formerly “Presenters”), but I’ve got the whole thing compiling and passing tests.

For those who are about to start the migration to v2, here is a list of the changes I had to make in my projects. It’s very unlikely an exhaustive list of all changes made to Caliburn, but, since I use a lot of customizations, I think it covers the most frequent issues.

Modules

Modules structure was a bit refactored to simplify (I guess) the addiction of configuration parameters to existing and new framework modules; from the user perspective, it means just to choose the new correct base class and the renaming of a couple methods.
I use modules for two distinct goals:

  • provide a way for independent application parts to load and hook itself into the shell without hard-wiring their reference in the main exe
  • hook some app-specific configuration into the CaliburnFramework static accessor, mimicking other Caliburn’s modules fluent configuration style.

For the first need I inherited from ModuleBase; for the second goal, I started from CaliburnModule<T> and added an extension method to hook into the fluent configuration. In both cases I had to change the name of Initialize and GetComponents methods into InitializeCore and GetComponentsCore.


public class MyAppModule : ModuleBase
{
  protected override void InitializeCore(Microsoft.Practices.ServiceLocation.IServiceLocator locator)
  {
  }

  protected override IEnumerable<IComponentRegistration> GetComponentsCore()
  {
    yield return Singleton(typeof(IMyService), typeof(MyService));
  }
}
 

public class MyFluentModuleConfig : CaliburnModule<MyFluentModuleConfig>
{
  protected override void InitializeCore(Microsoft.Practices.ServiceLocation.IServiceLocator locator)
  {

  }

  protected override IEnumerable<IComponentRegistration> GetComponentsCore()
  {
    yield return Singleton(typeof(IMyOtherService), typeof(MyOtherService));
  }
}

public static class Extenstions
{

  public static MyFluentModuleConfig MyFluentModule(this IModuleHook hook)
  {
    return hook.Module(MyFluentModuleConfig.Instance);
  }
}

Screens

There was a major refactoring in this area:

  • Naming change (“Presenters” are now “Screens”)
  • Strong typing of the screen with regard to their “subject”
  • Strong typing of screen composites based on contained screen
  • Automatic activation of already opened screen based on their subject

In order to accomodate existing code to v2 you have to replace existing class and interfaces following the subsequent scheme:

  • IPresenter –> IScreen
  • IPresenterHost -> IScreenCollection<IScreen>
  • IPresenterManager -> IScreenConductor<IScreen>
  • MultiPresenter -> ScreenConductor<IScreen>.WithCollection.AllScreensActive
  • MultiPresenterManager -> ScreenConductor<IScreen>.WithCollection.OneScreenActive
  • PresenterManager -> ScreenConductor<IScreen>
  • Presenter –> Screen

I closed generic class against IScreen to exactly reproduce the previous behaviour; note that I also chose to use generic version of IScreenCollection and IScreenConductor to match the new signature of screen-related extension functions.

I’m still not getting the benefits of strong typing and subject management, I have to refactor my applications in more depth for this.

Application

I had to fix a trivial signature change in CaliburnApplication.ConfigurePresentationFramework override. In addiction, I changed calls to Presentation Framework module configuration:

module.UsingViewStrategy<NoxaViewStrategy>();

module.UsingWindowManager<NoxaWindowManager>();

changed to

module.Using(c => c.ViewLocator<NoxaViewStrategy>());

module.Using(c => c.WindowManager<NoxaWindowManager>());

Framework classes

Some refactoring was done in the framework internals, so you only have to adjust this classes if you have done customization of the framework behaviour:

  • IWindowManager interface: bool isDialog parameter was added in EnsureWindow signature
  • IResult: signature of Execute method is changed from
    void Execute(IRoutedMessageWithOutcome message, IInteractionNode handlingNode)
    to
    void Execute(ResultExecutionContext context)
  • IResult: signature of Completed event was changed in
    EventHandler<ResultCompletionEventArgs>

Other random member name changes

  • RoutedMessageController -> DefaultRoutedMessageController
  • IBinder -> IViewModelBinder
  • ViewAttribute: namespace change
  • IViewStrategy -> IViewLocator
  • IViewStrategy.GetView –> IViewLocator.Locate
  • CurrentPresenter property -> ActiveScreen
  • Presenters property -> Screens
  • IExtendedPresenter interface -> IScreenEx
  • Open method -> OpenScreen
  • Shutdown method -> ShutdownScreen
Advertisements
26
Oct
09

Stock Trader with Caliburn /4

I began to write this post a couple week ago but since then I couldn’t manage to find some spare time to complete it. I hope to remember all the points for which an explanation is worth.

This time I’ll port the first real feature of StockTrader to the Caliburn implementation. I’m going to transfer the central tab control containing the two main feature of StockTrader and start to restore the first of them.

First of all, I have to restore content areas in the shell, which I initially stripped away. I will replace the custom AnimatedTabControl (that deals with transition animation between the features) with a simple TabControl.

In Prims views are injected at bootstrap time by the various application modules into proper “regions”, that are named areas within the shell view. On the other hand, Caliburn enforce the concept of “Application Model”: a logical representation of the entire application that is aimed to model screen composition and interaction with a non-visual structure.

While leveraging Caliburn’s preferred approach, I want to keep the modular organization of original StockTrader, letting various module to register its features in the shell during bootstrap phase.

Let’s start with “Position” module. I modified PositionModule class, deriving it from CaliburnModule; the class is responsible (both in original and in my version) to register module-specific components and to start its default screen.

public class PositionModule : CaliburnModule
{

    public PositionModule(IConfigurationHook hook) : base(hook) { }

    protected override IEnumerable<ComponentInfo> GetComponents()
    {
        yield return Singleton(typeof(IAccountPositionService), typeof(Services.AccountPositionService));
    }

    protected override void Initialize()
    {
        var posSummary = ServiceLocator.GetInstance<PositionSummary.IPositionSummaryPresentationModel>();
        ServiceLocator.GetInstance<IShellPresenter>().Open(posSummary);
    }
      
}

I chose to explicitly register in the module class body only AccountPositionService (it could be a remote service), while all other client components are registered declaratively (see Auto-Registering Components in Caliburn documentation):

[PerRequest(typeof(IPositionSummaryPresentationModel))]
public class PositionSummaryPresentationModel : Presenter, IPositionSummaryPresentationModel
{
...
}

In the Initialize method of the module, an instance of IPositionSummaryPresentationModel is obtained from the container and “opened” in the shell. IShellPresenter is a PresenterHost, so it is responsible of managing multiple content presenters keeping track of the “current” one.

Here is a point where Caliburn and Prism implementation and “philosophy” differs:

  • Prism requires to register views instance into UI regions; even if regions are loosely referenced with strings and views instance are indirectly obtained by presentation model, this approach still seems too view-centric. In addition, the UI composition behaviour is not enforced in the interface of the region: there is no difference between regions supporting single or multiple views;
  • Caliburn helps to define an application model driving the application parts composition; you don’t have to specify where and the opened presenter is shown: all visualization concerns are taken in account in the views.

Let’s see, for example, how to specify the visualization of the presenters managed by the shell:

in ShellView.xaml

<TabControl SelectedIndex="0"
    VerticalAlignment="Stretch"
    ItemContainerStyle="{StaticResource ShellTabItemStyle}" 
    Background="{StaticResource headerBarBG}"
                            
    ItemsSource="{Binding Presenters}">
</TabControl>

in TabItemResource.xaml

<Style x:Key="ShellTabItemStyle" TargetType="{x:Type TabItem}">
    ...
    <Setter Property="Header"
            Value="{Binding DisplayName}" />
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <ContentControl cal:View.Model="{Binding}" />
            </DataTemplate>
        </Setter.Value>
    </Setter>
    ...
</Style>

Presenters opened by shell view are displayed within a TabControl; the display name is print in the tab header, while the content of the presenter is put in the content area of the tab. cal:View.Model attached property is taking care to peek the correct view to display the presenter.

How is the correct view chosen for each presenter? Caliburn follows “Conventions over Configuration” philosophy, defining the concept of ViewStrategy (represented by IViewStrategy interface). This interface is responsible of selecting the right view based on the type of the presentation model class, following an application-wide convention.

The default implementation is well suited for projects with separated namespaces for views and presentation models; Stock Traders, on the contrary, follows the convention of using the namespace to group features, thus having presentation model in the same namespace of its corresponding view.

To use this convention I subclassed the default convention:

public class StockTraderViewStrategy : DefaultViewStrategy
{
    public StockTraderViewStrategy(IAssemblySource assemblySource, IServiceLocator serviceLocator)
        : base(assemblySource, serviceLocator) { }


    protected override string MakeNamespacePart(string part)
    {
        return part;
    }


    protected override IEnumerable<string> ReplaceWithView(Type modelType, string toReplace)
    {
        // MyNamespace.SomethingPresentationModel -> MyNamespace.SomethingView
        // or MyNamespace.SomethingPresenter -> MyNamespace.SomethingView
        if (!string.IsNullOrEmpty(toReplace))
            yield return modelType.Namespace + "." + modelType.Name.Replace(toReplace, "View");

    }
}

and registered it at application startup:

in App.xaml.cs

protected override void ConfigurePresentationFramework(Caliburn.PresentationFramework.PresentationFrameworkModule module)
{
    module.UsingViewStrategy<Infrastructure.StockTraderViewStrategy>();
}

 

Finally, I have the first module loading and displaying its default screen in the shell:

image

14
Sep
09

Stock Trader with Caliburn /3

It’s time to give the project some love, and put down some code to fix ideas.I created a new solution and started to transfer feature one after one.

I kept the overall structure of the original project  to simplify comparison between the two implementation and because I found it quite neat. The two project created are the exe project, containing the shell, and an Infrastructure library, containing common interfaces and classes (just like the original StockTraderRI):

RI_prj_13092009_234043

The first step I decided to take is to setup the project structure and have the shell starting.

Original application doesn’t have a presenter for the shell, so I created an IShellPresenter interface in Infrastructure proejct (I’ll need to reference it in the modules) and an implementation in the exe project:

RI_shellpres_14092009_14242

The Singleton attibute is used to auto-register the class within the container with a singleton lifestyle; the View attribute indicates Caliburn which view should be used to “visually represent” the presenter.
The markup for the shell view (ShellView.xaml) was only slightly modified to remove reference to CompositeWPF library and to custom controls,  whose features will be implemented later.

To have the first window running, I had to configure Caliburn. I chosen to derive my App class from CaliburnApplication, so I just had to indicate the  root model for the application:

RI_app_14092009_15520

That’s all. I can start the application and the main window shows as well (with no content, for now):

RI_shell_14092009_21739

Next time I’ll add the first real feature of the app; since all feature in original StockTraderRI resides in modules, I also have to deal with module loading and configuration.
I also should setup an online code repository to share the code.

06
Sep
09

Stock Trader with Caliburn /2

Time to put down a plan of the porting work (not a schedule: I wouldn’t even try it; the time I could give to this project is little and, even worse, very uncertain).

Stock Trader is composed of the subsequent parts:

  • an infrastructure library (StockTraderRI.Infrastructure) containing interfaces, classes and conventions shared between the various modules;
  • the application executable (StockTraderRI) containing the shell and all the code needed to glue together the modules;
  • four modules (StockTraderRI.Modules.Market, StockTraderRI.Modules.News, StockTraderRI.Modules.Position, StockTraderRI.Modules.WatchList) implementing the various features of the application.

Here is an architectural overview of the system, from Microsoft’s documentation.

I intend to keep the overall structure unchanged, and focus on technical implementation details regarding module management and UI composition. I would like to emphasize the implementation differences of the same real-world challenges illustrated in the original Stock Trader RI.

04
Sep
09

Prism Stock Trader… with Caliburn

Some months ago, I started using Composite Application Guidance (Prism, for friends) to build a modular composite application in WPF.

I liked the overall architecture, yet I was not very comfortable with it; I hated, mainly, the need of a lot of  plumbing code between the application parts.

After that, I discovered Caliburn. I was scared, at first, to afford the learning curve for another framework, but after little attempts I completely changed my mind: Caliburn is quite easy to start with and has smart solutions to eliminate plumbing code. It encourages the use of conventions and has plenty customization hooks.

I’ve been using Caliburn for a while; now I would like to port the Stock Trader application (the Prism reference implementation) to Caliburn, with the aim of comparing difference in style, complexity and raw line of code.

Stay tuned!




October 2017
S M T W T F S
« Oct    
1234567
891011121314
15161718192021
22232425262728
293031  

%d bloggers like this: