Anatomy of Synergy Toolkit
MixModes Synergy toolkit consists of the following top level projects:
MixModes.Synergy.Resources
– Contains image and language resourcesMixModes.Synergy.Themes
– Defines default themes for user controls, custom windows, colors, brushes and text themesMixModes.Synergy.Utilities
– Common utilitiesMixModes.Synergy.VisualFramework
– Contains behaviors, adorners, commands, user controls, docking framework and other WPF specific functionalitySynergy
– Sample project highlighting features of the toolkit
Anatomy of a Dockable Window
To understand window docking solution, it is necessary to understand the very primitive control that drives it all – the dockable window. A dockable window is a special window that in addition to content and title can be in following several states:
- Pinned state – Dockable window can be pinned to the side of parent window to have consistent visibility. Usually frequently used content is pinned for easier and constant access.
- Auto hidden state – Less frequently used windows can be auto hidden so when mouse is not hovering over them, they collapse into a condensed form (which I refer to as header). When mouse hovers over the headers, full window slides out from the docked side.
- Document state – When used as a document, dockable windows can merge as tab items within a tab control.
- Floating – Usual floating windows
Docking window support is provided by
DockPane
control that is a derivative of HeaderedContentControl
. In addition to Header and Content properties that it inherits from HeaderedContentControl
, it also contains the following properties:Icon
– Icon for the docked windowCondencedDockPanelTemplate
– Template for condensedDockPane
CondencedDockPanel
– Condensed form ofDockPane
DockPaneState
– State of the dock pane
DockPane
also contains the following events:Close
– Close eventTogglePin
– Toggling of pin / auto-hide buttonHeaderDrag
– Notification that user has started to drag header (title) of theDockPane
Default theme for
DockPane
is defined in the DockPane.xaml resource dictionary within MixModes.Synergy.Themes
project.Document Containers
DockPane
(s) are contained within document containers. Document container is modeled via DocumentContainer
class which is derivative ofContentControl
. DocumentContainer
can be in one of the following (mutually exclusive) states:Empty
–DocumentContainer
does not contain anyDockPane
ContainsDocuments
–DocumentContainer
contains one or moreDockPane
(s) as documentsSplitHorizontally
–DocumentContainer
is split horizontallySplitVertically
-DocumentContainer
is split vertically
DocumentContainer
is complex in terms of its template since it is required to represent either a split view or a tabbed view. I have used a persistent TabControl
within the template that is hidden if Content
property is ever non-null
. Content of-course is used exclusively to contain split views via Grid
with two children DocumentContainer
.DocumentContainer
contains the following properties:State
– State of theDocumentContainer
Documents
– Contains documents represented inTabControl
DocumentsTab
–TabControl
containing documentsDockIllustrationPanel
– This is a panel which contains docking illustration points indicating to the user where a content should be docked. If user drags aDockPane
to any one of these points, it gets docked at the respective position. The image below shows content of theDockIllustrationPanel
:
DocumentContainer
contains the following methods:AddDockPane(DockPane, ContentDockPoint)
– Adds aDockPane
as a docked windowAddDocumentContainers(IEnumerable<DocumentContainer>, bool)
– Splits and add childDocumentContainers
AddDocument(DockPane)
– Adds aDockPane
as a tabbed documentRemoveDocument(DockPane)
– Removes aDockPane
as a tabbed document
The template of
DocumentContainer
contains the following visuals in layers (bottom visuals are in increasing Z-Order):TabControl (PART_DOCUMENTS)
– Bound toDocuments
property ofDocumentContainer
ContentPresenter
– This is where split children are addedGrid (PART_DOCK_POINTS)
– Panel for hosting dock illustration pointsGrid (PART_DOCK_ILLUSTRATION)
–DockIllustrationPanel
for illustrating future docking via cues
Windows Manager
Windows manager is the component that binds
DockPanel
(s) and DocumentContainer
(s) together to provide window management functionality in applications. In addition, window manager contains auto-hide and pinned dock points on all four window sides so DockPane
(s) can be pinned or auto hidden outside of the DocumentContainer
(s). WindowsManager
also contains the root DocumentContainer
that can host documents in tab control or nested-split DocumentContainer
instances hosting documents.WindowsManager
has the following properties:DockPaneIllustrationStyle
– Illustration for docking a window withinWindowsManager
orDocumentsContainer
DockIllustrationContentStyle
– Illustration for merging documents while dragging aDockPane
inTabControl
ActiveWindowsManager
–Static
property indicating aWindowsManager
undergoing the drag operationDraggedPane
–DockPane
that is being dragged<Orientation>WindowHeaders
–StackPanel
containing condensed auto-hiddenDockPane
(s)<Orientation>PinnedWindows
–DockPanel
containing pinnedDockPane
(s)DocumentContainer
– Root document containerDockingIllustrationPanel
– Docking illustration panel for future pinnedDockPanel
(s)PopupArea
–DockPanel
where auto-hiddenDockPane
(s) slide out when mouse hovers upon the condensed headersFloatingPanel
–Canvas
that contains floatingDockPane
(s)DockingPanel
–DockPanel
that contains dock points for pinned windows as shown in image below:
WindowsManager
has the following methods:AddPinnedWindow(DockPane, Dock)
– Adds a pinnedDockPane
AddAutoHideWindow(DockPane, Dock)
– Adds an auto-hiddenDockPane
AddFloatingWindow(DockPane)
– Adds a floatingDockPane
RemoveDockPane(DockPane)
– Removes aDockPane
from (pinned, auto-hidden or floating portion of )WindowsManager
Clear
– Clears theWindowManager
of allDockPane
(s)StartDockPaneStateChangeDetection
– Starts state monitoring forDraggedPane
StopDockPaneStateChangeDetection
– Stops state monitoring forDraggedPane
How It All Works Together
WindowsManager
constantly monitors the state change of DockPane
. When a DockPane
drag is detected, it is placed on the FloatingPanel
canvas of WindowsManager
as a floating window that can be dragged around. During a drag of a DockPane
hit testing is turned off on theDockPane
so mouse events can flow down to controls below it such as WindowsManager
and DocumentContainer
.For orchestrating drag and drop and docking functionality, I have used a behavior driven approach. The idea is to expose functional end-points (such as methods and properties) on visual entities such as
DockPane
, DocumentContainer
and WindowsManager
and use behaviors to orchestrate and call these functional end-points. This approach also resulted in manageable-encapsulated components that were easier to trace and test.Both
WindowsManager
and DocumentContainer
have dock illustration grid containing the docking behavior. DockPointBehavior
behavior illustrates pinned docking illustration on WindowsManager
whereas ContentDockBehavior
illustrates splitting and tab merging illustration onDocumentContainer
.Using the Code
Using
WindowsManager
is extremely simple:- Import the namespace in the XAML:
xmlns:visualFx="http://mixmodes.com/visualFx" - Drop the
WindowsManager
in the XAML:
<visualFx:WindowsManager x:Name="WindowsManager"/>
- Start creating
DockPane
and insert them withinWindowsManager
/DocumentContainer
:CollapseDockPane pane = new DockPane(); pane.Header = … pane.Content = …. WindowsManager.AddPinnedWindow(pane, Dock.Top); // OR WindowsManager.AddAutoHideWindow(pane, Dock.Left); // OR // Assuming DocumentContainer is either in Empty or ContainsDocuments state WindowsManager.DocumentContainer.AddDocument(pane);
Serializing Window State
Out of the box, Synergy provides XML serialization of window states through
XmlWindowsManagerSerializer
andXmlWindowsManagerDeserializer
classes. Custom serialization is supported via specialization of base classes WindowsManagerSerializer
and WindowsManagerDeserializer
respectively.XML serialization of
WindowsManager
using XmlWindowsManagerSerializer
requires two pieces of information during construction:DockPane
writer – AnAction<XmlElement, DockPane>
instance that can write additional metadata about aDockPane
to theXmlElement
.- Document writer – A
Func<DocumentContent, string>
instance that takes in aDocumentContent
and returns astring
representation of the content.
Note:DocumentContent.DockPane
property returns the associatedDockPane
, however theHeader
andContent
properties ofDockPane
are set tonull
. To accessHeader
andContent
property, use theHeader
andContent
properties ofDocumentContent
instance directly.
Once
XmlWindowsManagerSerializer
instance is created, a call to Serialize(Stream, WindowsManager)
method serializesWindowsManager
to the stream
.Similar to serialization process, deserialization process requires an instance of
Action<DockPane, string>
within the constructor ofXmlWindowsManagerDeserializer
to de-serialize a DockPane
from previously saved string
representation. Deserialization does not require additional Action to realize DocumentContent
since DocumentContent
is inherently a serialization wrapper for DockPane
.Once
XmlWindowsManagerDeserializer
instance is created, a call to Deserialize(Stream, WindowsManager)
deserializes theWindowsManager
to previously saved state.All the docking functionality can be exercised by using the sample app (Synergy project) with the source code. Any comments or suggestions or bug-reports are as usual always welcome. Happy coding!
No comments:
Post a Comment