Click here to Skip to main content
15,892,674 members
Articles / Desktop Programming / WPF

WPF Docking Library

Rate me:
Please Sign up or sign in to vote.
4.78/5 (85 votes)
17 Jul 2007CPOL3 min read 1.1M   24.4K   317  
A WPF library to easily integrate Windows docking features in applications like VS
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
using System.Xml;

namespace DockingLibrary
{
    /// <summary>
    /// Manages and controls panes layout
    /// </summary>
    /// <remarks>This is the main user control which is usually embedded in a window. DockManager can control
    /// other windows arraging them in panes like VS. Each pane can be docked to a DockManager border, can be shown/hidden or auto-hidden.</remarks>
    public partial class DockManager : System.Windows.Controls.UserControl, IDropSurface
    {
        public DockManager()
        {
            InitializeComponent();
            
            DragPaneServices.Register(this);

            _overlayWindow = new OverlayWindow(this);

            gridDocking.AttachDockManager(this);
            gridDocking.DocumentsPane.Show();// .DockManager = this;
        }

        /// <summary>
        /// List of managed contents (hiddens too)
        /// </summary>
        List<DockableContent> Contents = new List<DockableContent>();

        /// <summary>
        /// Returns a documents list
        /// </summary>
        public DocumentContent[] Documents
        {
            get
            {
                DocumentContent[] docs = new DocumentContent[gridDocking.DocumentsPane.Documents.Count-gridDocking.DocumentsPane.Contents.Count];
                int i = 0;
                foreach (ManagedContent content in gridDocking.DocumentsPane.Documents)
                {
                    if (content is DocumentContent)
                        docs[i++] = content as DocumentContent;
                }

                //gridDocking.DocumentsPane.Documents.CopyTo(docs);
                return docs;
            }
        }

        /// <summary>
        /// Return active document
        /// </summary>
        /// <remarks>If no document is present or a dockable content is active in the Documents pane return null</remarks>
        public DocumentContent ActiveDocument
        {
            get
            {
                return gridDocking.DocumentsPane.ActiveDocument;
            }
        }

        /// <summary>
        /// Add dockable content to layout management
        /// </summary>
        /// <param name="content">Content to add</param>
        /// <returns></returns>
        internal void Add(DockableContent content)
        {
            if (!Contents.Contains(content))
                Contents.Add(content);
        }

        /// <summary>
        /// Add a dockapble to layout management
        /// </summary>
        /// <param name="pane">Pane to manage</param>
        internal void Add(DockablePane pane)
        {
            gridDocking.Add(pane);
            AttachPaneEvents(pane);
        }

        /// <summary>
        /// Remove a dockable pane from layout management
        /// </summary>
        /// <param name="dockablePane">Dockable pane to remove</param>
        /// <remarks>Also pane event handlers are detached</remarks>
        internal void Remove(DockablePane dockablePane)
        { 
             gridDocking.Remove(dockablePane);
             DetachPaneEvents(dockablePane);
        }

        /// <summary>
        /// Remove a dockable content from internal contents list
        /// </summary>
        /// <param name="content"></param>
        internal void Remove(DockableContent content)
        {
            Contents.Remove(content);
        }

        /// <summary>
        /// Add a document content
        /// </summary>
        /// <param name="content">Document content to adde</param>
        /// <returns>Returns DocumentsPane where document is added</returns>
        internal DocumentsPane AddDocument(DocumentContent content)
        {
            System.Diagnostics.Debug.Assert(!gridDocking.DocumentsPane.Documents.Contains(content));
            //gridDocking.DocumentsPane.DockManager = this;
            if (!gridDocking.DocumentsPane.Documents.Contains(content))
            {
                gridDocking.DocumentsPane.Add(content);
                //gridDocking.ArrangeLayout();
            }

            return gridDocking.DocumentsPane;
        }

        /// <summary>
        /// Add a docable content to default documents pane
        /// </summary>
        /// <param name="content">Dockable content to add</param>
        /// <returns>Documents pane where dockable content is added</returns>
        internal DocumentsPane AddDocument(DockableContent content)
        {
            System.Diagnostics.Debug.Assert(!Contents.Contains(content));
            System.Diagnostics.Debug.Assert(!gridDocking.DocumentsPane.Contents.Contains(content));
            
            if (!gridDocking.DocumentsPane.Contents.Contains(content))
            {
                gridDocking.DocumentsPane.Add(content);
                gridDocking.ArrangeLayout();
            }

            return gridDocking.DocumentsPane;
        }

        /// <summary>
        /// Returns currently active documents pane (at the moment this is only one per DockManager control)
        /// </summary>
        /// <returns>The DocumentsPane</returns>
        internal DocumentsPane GetDocumentsPane()
        {
            return gridDocking.DocumentsPane;
        }

        /// <summary>
        /// During unolad process close active contents windows
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnUnloaded(object sender, EventArgs e)
        {
            foreach (DockableContent content in Contents)
                content.Close();
            foreach (DocumentContent docContent in Documents)
                docContent.Close();
            
            _overlayWindow.Close();
        }

        /// <summary>
        /// Attach pane events handler
        /// </summary>
        /// <param name="pane"></param>
        internal void AttachPaneEvents(DockablePane pane)
        {
            pane.OnStateChanged += new EventHandler(pane_OnStateChanged);

            gridDocking.AttachPaneEvents(pane);
        }

        /// <summary>
        /// Detach pane events handler
        /// </summary>
        /// <param name="pane"></param>
        internal void DetachPaneEvents(DockablePane pane)
        {
            pane.OnStateChanged -= new EventHandler(pane_OnStateChanged);

            gridDocking.DetachPaneEvents(pane);
        }

        /// <summary>
        /// List of managed docking button groups currently shown in border stack panels
        /// </summary>
        List<DockingButtonGroup> _dockingBtnGroups = new List<DockingButtonGroup>();

        /// <summary>
        /// Handles pane state changed event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void pane_OnStateChanged(object sender, EventArgs e)
        {
            DockablePane pane = sender as DockablePane;
            if (pane.State == PaneState.AutoHide)
            {
                AddPaneDockingButtons(pane);
                ShowTempPane(false);
                HideTempPane(true);
            }
        }

        /// <summary>
        /// Add a group of docking buttons for a pane docked to a dockingmanager border
        /// </summary>
        /// <param name="pane"></param>
        private void AddPaneDockingButtons(DockablePane pane)
        {
            DockingButtonGroup buttonGroup = new DockingButtonGroup();
            buttonGroup.Dock = pane.Dock;

            foreach (DockableContent content in pane.Contents)
            {
                DockingButton btn = new DockingButton();
                btn.DockableContent = content;
                btn.DockingButtonGroup = buttonGroup;

                if (_currentButton == null)
                    _currentButton = btn;

                buttonGroup.Buttons.Add(btn);
            }

            _dockingBtnGroups.Add(buttonGroup);

            AddDockingButtons(buttonGroup);
        }

        /// <summary>
        /// Add a group of docking buttons to the relative border stack panel
        /// </summary>
        /// <param name="group">Group to add</param>
        private void AddDockingButtons(DockingButtonGroup group)
        {
            foreach (DockingButton btn in group.Buttons)
                btn.MouseEnter += new MouseEventHandler(OnShowAutoHidePane); 
            
            Border br = new Border();
            br.Width = br.Height = 10;
            switch (group.Dock)
            {
                case Dock.Left:
                    foreach (DockingButton btn in group.Buttons)
                    {
                        btn.LayoutTransform = new RotateTransform(90);
                        btnPanelLeft.Children.Add(btn);
                    }
                    btnPanelLeft.Children.Add(br);
                    break;
                case Dock.Right:
                    foreach (DockingButton btn in group.Buttons)
                    {
                        btn.LayoutTransform = new RotateTransform(90);
                        btnPanelRight.Children.Add(btn);
                    }
                    btnPanelRight.Children.Add(br);
                    break;
                case Dock.Top:
                    foreach (DockingButton btn in group.Buttons)
                        btnPanelTop.Children.Add(btn);
                    btnPanelTop.Children.Add(br);
                    break;
                case Dock.Bottom:
                    foreach (DockingButton btn in group.Buttons)
                        btnPanelBottom.Children.Add(btn);
                    btnPanelBottom.Children.Add(br);
                    break;
            }


        }

        /// <summary>
        /// Remove a group of docking buttons from the relative border stack panel
        /// </summary>
        /// <param name="group">Group to remove</param>
        private void RemoveDockingButtons(DockingButtonGroup group)
        {
            foreach (DockingButton btn in group.Buttons)
                btn.MouseEnter -= new MouseEventHandler(OnShowAutoHidePane);

            switch (group.Dock)
            {
                case Dock.Left:
                    btnPanelLeft.Children.RemoveAt(btnPanelLeft.Children.IndexOf(group.Buttons[group.Buttons.Count - 1]) + 1);
                    foreach (DockingButton btn in group.Buttons)
                        btnPanelLeft.Children.Remove(btn);
                    break;
                case Dock.Right:
                    btnPanelRight.Children.RemoveAt(btnPanelRight.Children.IndexOf(group.Buttons[group.Buttons.Count - 1]) + 1);
                    foreach (DockingButton btn in group.Buttons)
                        btnPanelRight.Children.Remove(btn);
                    break;
                case Dock.Top:
                    btnPanelTop.Children.RemoveAt(btnPanelTop.Children.IndexOf(group.Buttons[group.Buttons.Count - 1]) + 1);
                    foreach (DockingButton btn in group.Buttons)
                        btnPanelTop.Children.Remove(btn);
                    break;
                case Dock.Bottom:
                    btnPanelBottom.Children.RemoveAt(btnPanelBottom.Children.IndexOf(group.Buttons[group.Buttons.Count - 1]) + 1);
                    foreach (DockingButton btn in group.Buttons)
                        btnPanelBottom.Children.Remove(btn);
                    break;
            }
        }

        #region Overlay Panel
        /// <summary>
        /// Temporary pane used to host orginal content which is autohidden
        /// </summary>
        OverlayDockablePane _tempPane = null;

        /// <summary>
        /// Current docking button attached to current temporary pane
        /// </summary>
        DockingButton _currentButton;

        /// <summary>
        /// Event handler which show a temporary pane with a single content attached to a docking button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void OnShowAutoHidePane(object sender, MouseEventArgs e)
        {
            if (_currentButton == sender)
                return;

            HideTempPane(true);

            _currentButton = sender as DockingButton;

            ShowTempPane(true);
        }
       
        /// <summary>
        /// Event handler which hide temporary pane
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void OnHideAutoHidePane(object sender, MouseEventArgs e)
        {
            HideTempPane(true);
        }

        /// <summary>
        /// Hide temporay pane and reset current docking button
        /// </summary>
        /// <param name="smooth">True if resize animation is enabled</param>
        private void HideTempPane(bool smooth)
        {
            if (_tempPane != null)
            {
                DockablePane pane = gridDocking.GetPaneFromContent(_tempPane.Contents[0]) as DockablePane;
                bool right_left = false;
                double length = 0.0;

                switch (_currentButton.DockingButtonGroup.Dock)
                {
                    case Dock.Left:
                    case Dock.Right:
                        if (_tempPaneAnimation != null)
                            pane.PaneWidth = _lengthAnimation;
                        else 
                            pane.PaneWidth = _tempPane.Width;
                        length = _tempPane.Width;
                        right_left = true;
                        break;
                    case Dock.Top:
                    case Dock.Bottom:
                        if (_tempPaneAnimation != null)
                            pane.PaneHeight = _lengthAnimation;
                        else
                            pane.PaneHeight = _tempPane.Height;
                        length = _tempPane.Height;
                        right_left = false;
                        break;
                }

                _tempPane.OnStateChanged-=new EventHandler(_tempPane_OnStateChanged);

                if (smooth)
                {
                    HideOverlayPanel(length, right_left);
                }
                else
                {
                    ForceHideOverlayPanel();
                    panelFront.BeginAnimation(DockPanel.OpacityProperty, null);
                    panelFront.Children.Clear();
                    panelFront.Opacity = 0.0;
                    _tempPane.Close();
                }

                _currentButton = null;
                _tempPane = null;
            }

        }

        /// <summary>
        /// Show tampoary pane attached to current docking buttno
        /// </summary>
        /// <param name="smooth">True if resize animation is enabled</param>
        private void ShowTempPane(bool smooth)
        {

            _tempPane = new OverlayDockablePane(this, _currentButton.DockableContent, _currentButton.DockingButtonGroup.Dock);
            _tempPane.OnStateChanged += new EventHandler(_tempPane_OnStateChanged);

            DockablePane pane = gridDocking.GetPaneFromContent(_currentButton.DockableContent) as DockablePane;
            panelFront.Children.Clear();
            _tempPane.SetValue(DockPanel.DockProperty, _currentButton.DockingButtonGroup.Dock);
            panelFront.Children.Add(_tempPane);
            DockPanelSplitter splitter = null;
            bool right_left = false;
            double length = 0.0;

            switch (_currentButton.DockingButtonGroup.Dock)
            {
                case Dock.Left:
                    splitter = new DockPanelSplitter(_tempPane, null, SplitOrientation.Vertical);
                    length = pane.PaneWidth;
                    right_left = true;
                    break;
                case Dock.Right:
                    splitter = new DockPanelSplitter(null, _tempPane, SplitOrientation.Vertical);
                    length = pane.PaneWidth;
                    right_left = true;
                    break;
                case Dock.Top:
                    splitter = new DockPanelSplitter(_tempPane, null, SplitOrientation.Horizontal);
                    length = pane.PaneHeight;
                    right_left = false;
                    break;
                case Dock.Bottom:
                    splitter = new DockPanelSplitter(null, _tempPane, SplitOrientation.Horizontal);
                    length = pane.PaneHeight;
                    right_left = false;
                    break;
            }

            splitter.SetValue(DockPanel.DockProperty, _currentButton.DockingButtonGroup.Dock);
            panelFront.Children.Add(splitter);

            if (smooth)
                ShowOverlayPanel(length, right_left);
            else
            {
                if (right_left)
                    _tempPane.Width = length;
                else
                    _tempPane.Height = length;
                panelFront.Opacity = 1.0;
            }
                
        }

        /// <summary>
        /// Handle AutoHide/Hide commande issued by user on temporary pane
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _tempPane_OnStateChanged(object sender, EventArgs e)
        {
            Pane pane = gridDocking.GetPaneFromContent(_currentButton.DockableContent);

            if (_currentButton != null)
            {
                switch (_currentButton.DockingButtonGroup.Dock)
                {
                    case Dock.Left:
                    case Dock.Right:
                        pane.PaneWidth = _tempPane.PaneWidth;
                        break;
                    case Dock.Top:
                    case Dock.Bottom:
                        pane.PaneHeight = _tempPane.PaneHeight;
                        break;
                }

                RemoveDockingButtons(_currentButton.DockingButtonGroup);
                _dockingBtnGroups.Remove(_currentButton.DockingButtonGroup);
            }



            bool showOriginalPane = (_tempPane.State == PaneState.Docked);

            HideTempPane(false);

            if (showOriginalPane)
                pane.Show();
            else
                pane.Hide();

        }


        #region Temporary pane animation methods
        /// <summary>
        /// Current resize orientation
        /// </summary>
        bool _leftRightAnimation = false;
        /// <summary>
        /// Target size of animation
        /// </summary>
        double _lengthAnimation = 0;

        /// <summary>
        /// Temporary overaly pane used for animation
        /// </summary>
        OverlayDockablePane _tempPaneAnimation;

        /// <summary>
        /// Current animation object itself
        /// </summary>
        DoubleAnimation _animation;

        /// <summary>
        /// Show current overlay pane which hosts current auto-hiding content
        /// </summary>
        /// <param name="length">Target length</param>
        /// <param name="left_right">Resize orientaion</param>
        void ShowOverlayPanel(double length, bool left_right)
        {
            ForceHideOverlayPanel();

            _leftRightAnimation = left_right;
            _tempPaneAnimation = _tempPane;
            _lengthAnimation = length;

            _animation = new DoubleAnimation();
            _animation.From = 0.0;
            _animation.To = length;
            _animation.Duration = new Duration(TimeSpan.FromMilliseconds(200));
            _animation.Completed += new EventHandler(ShowOverlayPanel_Completed);
            if (_leftRightAnimation)
                _tempPaneAnimation.BeginAnimation(FrameworkElement.WidthProperty, _animation);
            else
                _tempPaneAnimation.BeginAnimation(FrameworkElement.HeightProperty, _animation);

            DoubleAnimation anOpacity = new DoubleAnimation();
            anOpacity.From = 0.0;
            anOpacity.To = 1.0;
            anOpacity.Duration = new Duration(TimeSpan.FromMilliseconds(200));
            panelFront.BeginAnimation(DockPanel.OpacityProperty, anOpacity);
        }

        /// <summary>
        /// Showing animation completed event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks>Set final lenght and reset animation object on temp overlay panel</remarks>
        void ShowOverlayPanel_Completed(object sender, EventArgs e)
        {
            _animation.Completed -= new EventHandler(ShowOverlayPanel_Completed);

            if (_tempPaneAnimation != null)
            {
                if (_leftRightAnimation)
                {
                    _tempPaneAnimation.BeginAnimation(FrameworkElement.WidthProperty, null);
                    _tempPaneAnimation.Width = _lengthAnimation;
                }
                else
                {
                    _tempPaneAnimation.BeginAnimation(FrameworkElement.HeightProperty, null);
                    _tempPaneAnimation.Height = _lengthAnimation;
                }
            }

            _tempPaneAnimation = null;
        }
        
        /// <summary>
        /// Hide current overlay panel
        /// </summary>
        /// <param name="length"></param>
        /// <param name="left_right"></param>
        void HideOverlayPanel(double length, bool left_right)
        {
            _leftRightAnimation = left_right;
            _tempPaneAnimation = _tempPane;
            _lengthAnimation = length;

            _animation = new DoubleAnimation();
            _animation.From = length;
            _animation.To = 0.0;
            _animation.Duration = new Duration(TimeSpan.FromMilliseconds(200));
            _animation.Completed += new EventHandler(HideOverlayPanel_Completed);

            if (left_right)
                _tempPaneAnimation.BeginAnimation(FrameworkElement.WidthProperty, _animation);
            else
                _tempPaneAnimation.BeginAnimation(FrameworkElement.HeightProperty, _animation);

            DoubleAnimation anOpacity = new DoubleAnimation();
            anOpacity.From = 1.0;
            anOpacity.To = 0.0;
            anOpacity.Duration = new Duration(TimeSpan.FromMilliseconds(200));
            panelFront.BeginAnimation(DockPanel.OpacityProperty, anOpacity);        
        }

        /// <summary>
        /// Hiding animation completed event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks>Set final lenght to 0 and reset animation object on temp overlay panel</remarks>
        void HideOverlayPanel_Completed(object sender, EventArgs e)
        {
            ForceHideOverlayPanel();
            panelFront.Children.Clear();
        }

        /// <summary>
        /// Forces to hide current overlay panel
        /// </summary>
        /// <remarks>Usually used when a second animation is about to start from a different button</remarks>
        void ForceHideOverlayPanel()
        {
            if (_tempPaneAnimation != null)
            {
                _animation.Completed -= new EventHandler(HideOverlayPanel_Completed);
                _animation.Completed -= new EventHandler(ShowOverlayPanel_Completed);
                if (_leftRightAnimation)
                {
                    _tempPaneAnimation.BeginAnimation(FrameworkElement.WidthProperty, null);
                    //_tempPaneAnimation.Width = 0;
                }
                else
                {
                    _tempPaneAnimation.BeginAnimation(FrameworkElement.HeightProperty, null);
                    //_tempPaneAnimation.Height = 0;
                }

                _tempPaneAnimation.Close();
                _tempPaneAnimation = null;
            }
        }
        #endregion

        #endregion

        /// <summary>
        /// Handle dockable pane layout changing
        /// </summary>
        /// <param name="sourcePane">Source pane to move</param>
        /// <param name="destinationPane">Relative pane</param>
        /// <param name="relativeDock"></param>
        internal void MoveTo(DockablePane sourcePane, Pane destinationPane, Dock relativeDock)
        {
            gridDocking.MoveTo(sourcePane, destinationPane, relativeDock);
        }

        /// <summary>
        /// Called from a pane when it's dropped into an other pane
        /// </summary>
        /// <param name="sourcePane">Source pane which is going to be closed</param>
        /// <param name="destinationPane">Destination pane which is about to host contents from SourcePane</param>
        internal void MoveInto(DockablePane sourcePane, Pane destinationPane)
        {
            gridDocking.MoveInto(sourcePane, destinationPane);
        }

        #region DragDrop Operations
        /// <summary>
        /// Parent window hosting DockManager user control
        /// </summary>
        public Window ParentWindow = null;

        /// <summary>
        /// Begins dragging operations
        /// </summary>
        /// <param name="floatingWindow">Floating window containing pane which is dragged by user</param>
        /// <param name="point">Current mouse position</param>
        /// <param name="offset">Offset to be use to set floating window screen position</param>
        /// <returns>Retruns True is drag is completed, false otherwise</returns>
        public bool Drag(FloatingWindow floatingWindow, Point point, Point offset)
        {
            if (!IsMouseCaptured)
            {
                if (CaptureMouse())
                {
                    floatingWindow.Owner = ParentWindow;
                    DragPaneServices.StartDrag(floatingWindow, point, offset);
                    
                    return true;
                }
            }

            return false;
        }
        /// <summary>
        /// Handles OnMouseDown event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void OnMouseDown(object sender, MouseEventArgs e)
        {

        }

        /// <summary>
        /// Handles mousemove event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (IsMouseCaptured)
                DragPaneServices.MoveDrag(PointToScreen(e.GetPosition(this)));
        }

        /// <summary>
        /// Handles mouseUp event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks>Releases eventually camptured mouse events</remarks>
        void OnMouseUp(object sender, MouseEventArgs e)
        {
            if (IsMouseCaptured)
            {
                DragPaneServices.EndDrag(PointToScreen(e.GetPosition(this)));
                ReleaseMouseCapture();
            }
        }

        DragPaneServices _dragPaneServices;

        internal DragPaneServices DragPaneServices
        {
            get 
            {
                if (_dragPaneServices == null)
                    _dragPaneServices = new DragPaneServices(this);

                return _dragPaneServices;
            }
        }
        #endregion


        #region IDropSurface

        /// <summary>
        /// Returns a rectangle where this surface is active
        /// </summary>
        public Rect SurfaceRectangle
        {
            get 
            { return new Rect(PointToScreen(new Point(0,0)), new Size(ActualWidth, ActualHeight)); }
        }

        /// <summary>
        /// Overlay window which shows docking placeholders
        /// </summary>
        OverlayWindow _overlayWindow;

        /// <summary>
        /// Returns current overlay window
        /// </summary>
        internal OverlayWindow OverlayWindow
        {
            get
            {
                return _overlayWindow; 
            }
        }

        /// <summary>
        /// Handles this sourface mouse entering (show current overlay window)
        /// </summary>
        /// <param name="point">Current mouse position</param>
        public void OnDragEnter(Point point)
        {
            OverlayWindow.Owner = DragPaneServices.FloatingWindow;
            OverlayWindow.Left = PointToScreen(new Point(0, 0)).X;
            OverlayWindow.Top = PointToScreen(new Point(0, 0)).Y;
            OverlayWindow.Width = ActualWidth;
            OverlayWindow.Height = ActualHeight;
            OverlayWindow.Show();       
        }

        /// <summary>
        /// Handles mouse overing this surface
        /// </summary>
        /// <param name="point"></param>
        public void OnDragOver(Point point)
        {

        }

        /// <summary>
        /// Handles mouse leave event during drag (hide overlay window)
        /// </summary>
        /// <param name="point"></param>
        public void OnDragLeave(Point point)
        {
            _overlayWindow.Owner = null;
            _overlayWindow.Hide();
            ParentWindow.Activate();
            
        }

        /// <summary>
        /// Handler drop events
        /// </summary>
        /// <param name="point">Current mouse position</param>
        /// <returns>Returns alwasy false because this surface doesn't support direct drop</returns>
        public bool OnDrop(Point point)
        {
            return false;
        }

        #endregion


        #region Persistence

        /// <summary>
        /// Serialize layout state of panes and contents into a xml string
        /// </summary>
        /// <returns>Xml containing layout state</returns>
        public string GetLayoutAsXml()
        {
            XmlDocument doc = new XmlDocument();
            doc.AppendChild(doc.CreateElement("DockingLibrary_Layout"));
            gridDocking.Serialize(doc, doc.DocumentElement);
            return doc.OuterXml;
        }

        /// <summary>
        /// Restore docking layout reading a xml string which is previously generated by a call to GetLayoutState
        /// </summary>
        /// <param name="xml">Xml containing layout state</param>
        /// <param name="getContentHandler">Delegate used by serializer to get user defined dockable contents</param>
        public void RestoreLayoutFromXml(string xml, GetContentFromTypeString getContentHandler)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);

            gridDocking.Deserialize(this, doc.ChildNodes[0], getContentHandler);

            List<Pane> addedPanes = new List<Pane>();
            foreach (DockableContent content in Contents)
            {
                DockablePane pane = content.ContainerPane as DockablePane;
                if (pane != null && !addedPanes.Contains(pane))
                {
                    if (pane.State == PaneState.AutoHide)
                    {
                        addedPanes.Add(pane);
                        AddPaneDockingButtons(pane);
                    }
                }
            }

            _currentButton = null;
        }
        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Systems Engineer
Italy Italy
I bought my first computer in Nov 1991, 21st and I started programming with QBasic under MSDOS.
Today my main interest is developping applications with .NET and HTML5 stack.

Comments and Discussions