In the Quick start there were shown some mechanisms that allow you to build your own simple application. This page will introduce more advanced tools and ways for using WPF RCP platform. For the purpose of understanding the whole material, you should know concepts of IoC (DI), MVVM pattern and basically WPF .Net. It will be helpful also to be familiar with Caliburn library.

Concepts show in this page are using mechanisms of the modules shown in Quick start page. Most of those implementations take place in specific implementations of mehods inherited from ModuleBase (ex. RegisterViews(), GetModuleInfo()).

Information page

In Quick start there are some information about customizing information page to adjust it to your specific application. Information page is shown after choosing 'About Program' where there are presented details of specific application.
To display actual form, there should be proper control and presenter created.

First there should be created IAboutView interface in Views solution folder.

public interface IAboutView
{
}

To display proper information there should be created class inheriting from WpfRcp.Core.Views.Presenters.PresenterBase<IAboutView> (in Views/Presenters folder).

Contructor should take IRcpSettings as parameter and implement Initialize() method.

Example implementation is presented below.

public class AboutViewPresentationModel : PresenterBase<IAboutView>
    {
        private readonly IRcpSettings m_RcpSettings;
        private string m_VersionString;
 
        public AboutViewPresentationModel(IRcpSettings rcpSettings)
        {
            m_RcpSettings = rcpSettings;
        }
 
        protected override void Initialize()
        {
            DataBind();
        }
 
        public IRcpSettings RcpSettings
        {
            get { return m_RcpSettings; }
        }
 
        public string VersionString
        {
            get { return m_VersionString; }
            private set
            {
                m_VersionString = value;
                OnPropertyChanged("VersionString");
            }
        }
 
        private void DataBind()
        {
#if (DEBUG)
            VersionString =
                string.Format(
                    (IntPtr.Size == 4
                         ? Properties.Resources.VersionString32
                         : Properties.Resources.VersionString64) + " (Debug)",
                    Assembly.GetEntryAssembly().GetName().Version);
#else
            if (IntPtr.Size == 4)
                VersionString = string.Format(Properties.Resources.VersionString32,
                    Assembly.GetEntryAssembly().GetName().Version);
            else
                VersionString = string.Format(Properties.Resources.VersionString64,
                    Assembly.GetEntryAssembly().GetName().Version);
#endif
        }
    }

Actual control should be created as AboutView.xaml in Views/Controls folder.
.xaml part is displaing actual information and as example is presented below.

<UserControl x:Class="RCPApplication.UI.Views.Controls.AboutView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Loc="clr-namespace:WpfRcp.Core.Common.Localization;assembly=WpfRcp.Core"
    Loc:ResxExtension.GlobalResxName="RCPApplication.UI.Properties.Resources">

    <StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Loc:Resx Key=Authors}" />
            <TextBlock Margin="20,0,0,0" Text="{Loc:Resx Key=AuthorsList}" />
        </StackPanel>

        <TextBlock Margin="0,15,0,5" Text="{Loc:Resx Key=TaskBarAppName}" />
        <TextBlock Margin="0,0,0,5" Text="{Binding VersionString, Mode=OneWay}"></TextBlock>
        <TextBlock Margin="0,0,0,5" Text="{Loc:Resx Key=Copyright}" />
        <TextBlock Margin="0,0,0,0" Text="{Loc:Resx Key=AllRightsReserved}"></TextBlock>
        <Rectangle Height="1" Stroke="DarkGray" VerticalAlignment="Stretch" Margin="0,10,0,10" />
    </StackPanel>

</UserControl>

Class is implementing IAboutView and using previously created AboutViewPresentationModel presenter.

public partial class AboutView : IAboutView
{
        public AboutView(AboutViewPresentationModel presentationModel)
        {
            PresentationModel = presentationModel;
            PresentationModel.View = this;

            InitializeComponent();
        }

        public AboutViewPresentationModel PresentationModel
        {
            get { return (AboutViewPresentationModel)DataContext; }
            set { DataContext = value; }
        }
}

Adding controls to the panels

Application is build based on template:
  • Menu at the top
  • Tab panels at the right
  • Bottom panel
  • Left options
  • Main window
This template uses IRegionManager to put controls in a proper place. RegionNames may be seen in WpfRcp.Core.Globals.RegionNames static class.

Customizing panels described below uses objects of types IRegionManager (object _regionManager) and IWorkbenchService (object _workbenchService) that should be taken from the IoC container (ex. passed in the constructor).

Adding tabs to the side panel

To add some specific behaviour and controls showing in the right module panel, there should be:
  • specific module registered,
  • specific controls and controllers created,
  • specific behaviour implemented.
Some of the code (like registering the module and control creation) is shown in Quick start page.
Basic code that adds control as atba to the right panel is:

var viewItem = new ViewItem();
viewItem.Visual = myTabPresentationModel.View;
viewItem.Name = tabName;
_workbenchService.Add(viewItem, DockStyle.RightPanel)

Right panel will have as many controls added as there will be registered. Each will be show as separate tab.

Adding icons to the tool panel

In the example applicatio delivered with WPF RCP platform there are some icons in the left panel. This is why it's called tool panel - it looks like a toolbar, but of course when implementing proper interfaces and creating another type of controls, almost every view may be shown here.

To display controls on the left panel first there should be appropriate model and view created, second they should be linked to each other.

You can use existing implementations existing in example application:
  • IToolbarView - interface for the view
  • ToolbarView - view implementation
  • ToolbarPresentationModel - presentation model.
But if you want to display there your own content, you should build your own control.

To display view in the left panel in the module there should be the following code used:

_regionManager.RegisterViewWithRegion(GlobalRegionNames.ToolbarRegion,() => Container.Resolve<MyToolbarPresentationModel>().View);

Displaying controls in the main panel

When you want to display some content (ex. picture or file content), the best way is to use main panel.
First thing you need is presentation content control (which means .xaml view and ViewModel) that will show the content. Then you should use the following code:

var workbenchItem = new DocumentItem(tabDisplayName, contentPresentationViewModel.View);
_workbenchService.Add(workbenchItem);

Which will use the presentation control, attach to it tab (by using DocumentItem constructor) and display on main panel (by using Add method).

Customizing the menu

Without menu customization standard items are:
  • File (Exit)
  • View (Header Visibility, Fullscreen, Application Options, Log Window, Status Window)
  • Help (About Program)

Menu structure has three main structures: tabs, groups and menu items and is restricted to one level. Currently there exist two types of the menu: standard and ribbon menu. Their configuration may be found in Frameworks configuration

Menu items, groups and tabs names may be found in MamoothRcp.Core.Globals.ApplicationConstants class. Customizing menu described below uses objects of types IActionRegistry (object _actionRegistry) and IMenuRegistry (object _menuRegistry_) that should be taken from the IoC container (ex. passed in the constructor).

Adding menu to the group

For menu to appear on existing group there should be command used.
Example of creating the command:

DelegateCommand<object> someCommand = new DelegateCommand<object>(SomeMethod);

Constructor of generic DelegateCommand<T> specifies Action<T> argument so that SomeMethod should take one argument of type T.

Registering the command and command category:

var commandCategoryName = "MyCommandCategory";
var commandName = "MyCommandName";
_actionRegistry.RegisterCommandCategory(commandCategoryName);
_actionRegistry.RegisterCommand(commandName, commandCategoryName, someCommand);

Using the registered command Item may be registered for existing menu group or to the new one. Group below the main level will appear separated by the line.

var menuItemName = "MenuItemName";
var menuItemText = "Menu item 1";
m_menuRegistry.RegisterMenuItem(menuItemName, menuGroupName, commandName)
    .SetPosition(10).SetText(menuItemText);

This will show new menu item with text "Menu item 1" in the category of name menuGroupName on the position 10, which means that every item with lower number of position in the group will be show at the top from this item.

Adding a group

Adding new group to the existing tab of name tabName is as simple as:

var group = _menuRegistry.RegisterMenuItemGroup("MyGroupName", tabName);

Group may also have text (show for example in ribbon kind of menu) and position set.
In a regular menu grouping items means adding separator between them on user interface.

Adding a tab

To add a tab to the menu you should use the following code:

var tab = m_menuRegistry.RegisterMenuTab("MyTabName")

Tab also should have position and text set.

Job management

Jobs in WPF RCP are the concept of operations run in separate threads. Platform provides several additional tools (like logging) when user decide to implement behavior using jobs instead of regular operations.

Creating a job

To create a job there is constructor needed. The same as thread every Job constructor gets actual operation that will be performed when Job starts. Additionally there can be passed information about job name (that can be displayed to follow Job performance), fact if it's cancelable or may be run in the background.

There is also oportunity to show progress bar and monitor job.

Code below is showing main concepts:

// Creating job object that runs SomeMethod is cancelable and backgroundable
var job = new Job(SomeMethod, jobName, new JobOptions(true, true));
 
// atatching progress view
var progressView = m_Container.Resolve<IWindowedProgressView>();
IShell shell = m_Container.Resolve<IShell>();
progressView.OwnerView = shell;
var statusManager = m_Container.Resolve<IStatusManager>();
 
// creating job monitor
var monitor = statusManager.CreateSimpleStatusMonitor(Resources.WaitJobName, job, progressView);
 
job.Error += (s, e) =>
{
    //...
};
job.Completed += (s, e) =>
{
    //...
}; 
job.Cancelled += (s, e) => 
{
    //...
};
 
// runing job asynchronously
job.RunAsync();
 
// showing progress view
progressView.ShowDialog();

If a Job is cancelable, proper button will be shown that uses Cancelled operation implemented for it. If job is backgroundable it should be run by using RunAsynch() method not Run(). When using Run() in code above, progressView will start showing after the operation is already ended.

Operation status

When job is started, completed or canceled - information is stored in logs and may be retrieved by using Log window menu.

While job is still working and put to backround its status and also possibbility to cancel is retrievable from Status window menu.

Last edited Jul 12, 2013 at 11:35 AM by coldfusion, version 20

Comments

No comments yet.