UI Composition
UI Composition
Radical offers a fully flagged UI Composition engine based on the concept of regions.
A
UI Composition
sample is available in the Radical-Samples repository.
Concepts
A region
is a named injectable portion of the UI where other components can inject their on content. A region is attached to a DependencyObject
on the UI, depending on the type of the object the region is attached to the region behavior changes. Radical has 3 different main region types:
IContentRegion<T>
: a content region is thought for aContentPresenter
or aContentControl
UIElement, it can host one single content at a time and each time a new content is set the previous one will be removed;IElementsRegion<T>
: an elements region can host multiple contents at a time, it is thought for aPanel
UIElement, so each WPF control that inherits from panel, such as theStackPanel
, can be used with anIElementsRegion
; Content from anIElementsRegion
can be added or removed and will be available depending on the logic implemented by the underlying UIElement;ISwitchingElementsRegion<T>
: a switching elements region is an element region that, other than being able to host multiple elements at a time, has also the concept of an active element that can change over time; a typical sample is aTabControl
where eachTabItem
can be seen;
Note: each time a content is removed from a region its lifecycle is managed as every View/ViewModel:
View and ViewModel will be released;
If View or ViewModel implements
IDisposable
they will be disposed;If View or ViewModel implements
IExpectViewClosedCallback
they will receive a callback notification;
Each region is characterized by 2 main attributes:
is owned by a Region Manager, an
IRegionManager
implementation;has a unique name in the set of regions owned by the same Region Manager;
A RegionManager
is automatically created by the UI Composition engine as soon as a region is added to a View
, a RegionManager
is bound to a WPF Window
instance.
Nesting
Regions can be nested as preferred, a Window can contain a region that at runtime will contain another region and so on without limitations. For example the following is a valid logical tree
:
In the above sample one single RegionManager will be created at runtime.
Region Setup
Region markup definition
First define a region in the XAML where is needed and attach it to the UIElement
that requires injection:
Remarks
The
rg
namespace declaration pointing to the Radical region namespacehttp://schemas.radicalframework.com/windows/presentation/regions
;A region is attached to a
UIElement
via theRegion
attached property of theRegionService
element;A region is declared as a markup extension whose primary role is to define the region type and the region name;
As soon as we define a region the UI Composition engine, at runtime, will create a RegionManager
to host the region, RegionManager whose lifecycle is bound to the lifecycle of the hosting Window
. If the region is defined in a UserControl
the RegionManager lifecycle will be bound to the lifecycle of the Window
hosting the UserControl.
Region Injection
Once a region is defined in the XAML we need to inject some content, we can inject content in a region in 3 different ways: manually, using partial views or using a declarative approach.
Manual injection
Once a View contains a region each time the View is loaded a ViewLoaded
message is broadcasted to notify that the View has been loaded:
In the above sample we are defining a message handler to handle the ViewLoaded
message, overriding the OnShouldHandle
method to define a rule to handle only the ViewLoaded event related to the View we are interested in.
In the Handle
method we utilize:
the
RegionService
to determine is the View has aRegionManager
;if the View has a region manager
we resolve the content to inject;
retrieve a reference to the region manager and to the region;
inject the content;
Resources:
Automatic (aka Partial regions)
Radical UI Composition engine has a concept called partial view
, a partial view is a View
, and if defined its ViewModel
, that can be automatically picked up and injected based on a set of conventions:
Given a region, as in the previous XAML sample named
MyRegion
;Given a View, and an optional ViewModel, that lives in a namespace that matches
*.Presentation.Partials.*
;Where the last segment of the View/ViewModel namespace is the region name, in our sample MyRegion;
The View will be resolved, as usual, and injected into the expected region. Given the following namespace structure:
The MySampleView and it ViewModel, MySampleViewModel, will be automatically injected into the MyRegion region.
Declarative
The last option, to inject a View
in a specific region
, is to decorate the View
class with the InjectViewInRegionAttribute
:
In the above sample, at runtime, the UI Composition engine will inject an instance of the MyUserControlView
into the region named "MyRegion".
Region implementations
As previously said Radical has 3 different region types: IContentRegion<T>
, IElementsRegion<T>
and ISwitchingElementsRegion<T>
. Each region type has a default implementation.
ContentPresenterRegion
A ContentPresenterRegion
is a IContentRegion<ContentPresenter>
that can be applied to a ContentPresenter UIElement
.
PanelRegion
A PanelRegion
is a IElementsRegion<Panel>
, given that a Panel
is an abstract class, this region can be used with any UIElement
that inherits from Panel
, such as a StackPanel
.
TabControlRegion
A TabControlRegion
is an implementation of the ISwitchingElementsRegion<TabControl>
and can be used with a TabControl
.
Last updated