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 condensedDockPaneCondencedDockPanel– Condensed form ofDockPaneDockPaneState– 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–DocumentContainerdoes not contain anyDockPaneContainsDocuments–DocumentContainercontains one or moreDockPane(s) as documentsSplitHorizontally–DocumentContaineris split horizontallySplitVertically-DocumentContaineris 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 theDocumentContainerDocuments– Contains documents represented inTabControlDocumentsTab–TabControlcontaining documentsDockIllustrationPanel– This is a panel which contains docking illustration points indicating to the user where a content should be docked. If user drags aDockPaneto 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 aDockPaneas a docked windowAddDocumentContainers(IEnumerable<DocumentContainer>, bool)– Splits and add childDocumentContainersAddDocument(DockPane)– Adds aDockPaneas a tabbed documentRemoveDocument(DockPane)– Removes aDockPaneas a tabbed document
The template of
DocumentContainer contains the following visuals in layers (bottom visuals are in increasing Z-Order):TabControl (PART_DOCUMENTS)– Bound toDocumentsproperty ofDocumentContainerContentPresenter– This is where split children are addedGrid (PART_DOCK_POINTS)– Panel for hosting dock illustration pointsGrid (PART_DOCK_ILLUSTRATION)–DockIllustrationPanelfor 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 withinWindowsManagerorDocumentsContainerDockIllustrationContentStyle– Illustration for merging documents while dragging aDockPaneinTabControlActiveWindowsManager–Staticproperty indicating aWindowsManagerundergoing the drag operationDraggedPane–DockPanethat is being dragged<Orientation>WindowHeaders–StackPanelcontaining condensed auto-hiddenDockPane(s)<Orientation>PinnedWindows–DockPanelcontaining pinnedDockPane(s)DocumentContainer– Root document containerDockingIllustrationPanel– Docking illustration panel for future pinnedDockPanel(s)PopupArea–DockPanelwhere auto-hiddenDockPane(s) slide out when mouse hovers upon the condensed headersFloatingPanel–Canvasthat contains floatingDockPane(s)DockingPanel–DockPanelthat contains dock points for pinned windows as shown in image below:
WindowsManager has the following methods:AddPinnedWindow(DockPane, Dock)– Adds a pinnedDockPaneAddAutoHideWindow(DockPane, Dock)– Adds an auto-hiddenDockPaneAddFloatingWindow(DockPane)– Adds a floatingDockPaneRemoveDockPane(DockPane)– Removes aDockPanefrom (pinned, auto-hidden or floating portion of )WindowsManagerClear– Clears theWindowManagerof allDockPane(s)StartDockPaneStateChangeDetection– Starts state monitoring forDraggedPaneStopDockPaneStateChangeDetection– 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 FloatingPanelcanvas 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
WindowsManagerin the XAML:
<visualFx:WindowsManager x:Name="WindowsManager"/> - Start creating
DockPaneand 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 WindowsManagerSerializerand WindowsManagerDeserializer respectively.XML serialization of
WindowsManager using XmlWindowsManagerSerializer requires two pieces of information during construction:DockPanewriter – AnAction<XmlElement, DockPane>instance that can write additional metadata about aDockPaneto theXmlElement.- Document writer – A
Func<DocumentContent, string>instance that takes in aDocumentContentand returns astringrepresentation of the content.
Note:DocumentContent.DockPaneproperty returns the associatedDockPane, however theHeaderandContentproperties ofDockPaneare set tonull. To accessHeaderandContentproperty, use theHeaderandContentproperties ofDocumentContentinstance 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