/// <summary> /// Internal main restore layout method /// </summary> /// <param name="doc">Document Xml from which restore layout</param> void RestoreLayout(XmlDocument doc) { if (!_isControlLoaded) throw new InvalidOperationException("Unable to deserialize a docking layout while DockingManager control is unloaded"); if (doc.DocumentElement == null || doc.DocumentElement.Name != "DockingManager") { Debug.Assert(false, "Layout file hasn't a valid structure!"); throw new InvalidOperationException("Layout file had not a valid structure!"); } if (doc.DocumentElement.GetAttribute("version") != layoutFileVersion) throw new FileFormatException("Unsupported layout file version"); if (doc.DocumentElement.ChildNodes.Count != 3 || (doc.DocumentElement.ChildNodes[0].Name != "ResizingPanel" && doc.DocumentElement.ChildNodes[0].Name != "DocumentPane") || doc.DocumentElement.ChildNodes[1].Name != "Hidden" || doc.DocumentElement.ChildNodes[2].Name != "Windows") { Debug.Assert(false, "Layout file hasn't a valid structure!"); throw new InvalidOperationException("Layout file hasn't a valid structure!"); } //Hide temp windows HideFlyoutWindow(); HideNavigatorWindow(); //HideDocumentNavigatorWindow(); RestoringLayout = true; //show all auto hidden panes var panesAutoHidden = DockableContents.Where(c => c.State == DockableContentState.AutoHide).Select(c => c.ContainerPane).Distinct(); foreach (DockablePane pane in panesAutoHidden) pane.ToggleAutoHide(); DockableContent[] actualContents = DockableContents.ToArray(); DocumentContent[] actualDocuments = Documents.ToArray(); //first detach all my actual contents this.Content = null; this.ActiveContent = null; this.ActiveDocument = null; //restore main panel XmlElement rootElement = doc.DocumentElement.ChildNodes[0] as XmlElement; DocumentPane mainDocumentPane = null; this.Content = RestoreLayout(rootElement, actualContents, actualDocuments, ref mainDocumentPane); MainDocumentPane = mainDocumentPane; //restore hidden contents foreach (XmlElement hiddenContentElement in doc.DocumentElement.ChildNodes[1].ChildNodes) { var hiddenContentName = hiddenContentElement.GetAttribute("Name"); var hiddenContent = actualContents.FirstOrDefault(c => c.Name == hiddenContentName && c.State != DockableContentState.Hidden); if (hiddenContent != null) { Hide(hiddenContent); hiddenContent.RestoreLayout(hiddenContentElement); } } //restore floating windows foreach (XmlElement flWindowElement in doc.DocumentElement.ChildNodes[2].ChildNodes) { if (flWindowElement.ChildNodes.Count != 1) continue;//handles invalid layouts structures bool isDockableWindow = XmlConvert.ToBoolean(flWindowElement.GetAttribute("IsDockableWindow")); Point location = new Point(XmlConvert.ToDouble(flWindowElement.GetAttribute("Left")), XmlConvert.ToDouble(flWindowElement.GetAttribute("Top"))); Size size = new Size(XmlConvert.ToDouble(flWindowElement.GetAttribute("Width")), XmlConvert.ToDouble(flWindowElement.GetAttribute("Height"))); XmlElement paneElement = flWindowElement.ChildNodes[0] as XmlElement; DockablePane paneForFloatingWindow = new DockablePane(); if (paneElement.HasAttribute("ResizingWidth")) ResizingPanel.SetResizeWidth(paneForFloatingWindow, (GridLength)GLConverter.ConvertFromInvariantString(paneElement.GetAttribute("ResizeWidth"))); if (paneElement.HasAttribute("ResizingHeight")) ResizingPanel.SetResizeHeight(paneForFloatingWindow, (GridLength)GLConverter.ConvertFromInvariantString(paneElement.GetAttribute("ResizeHeight"))); paneForFloatingWindow.Anchor = (AnchorStyle)Enum.Parse(typeof(AnchorStyle), paneElement.GetAttribute("Anchor")); DockableContent contentToTransfer = null; foreach (XmlElement contentElement in paneElement.ChildNodes) { #region Find the content to transfer string contentToFindName = contentElement.GetAttribute("Name"); contentToTransfer = actualContents.FirstOrDefault(c => c.Name == contentToFindName); if (contentToTransfer == null && DeserializationCallback != null) { DeserializationCallbackEventArgs e = new DeserializationCallbackEventArgs(contentToFindName); DeserializationCallback(this, e); contentToTransfer = e.Content as DockableContent; } #endregion if (contentToTransfer != null) { DetachContentFromDockingManager(contentToTransfer); paneForFloatingWindow.Items.Add(contentToTransfer); contentToTransfer.RestoreLayout(contentElement); } } if (paneForFloatingWindow.Items.Count > 0) { var flWindow = new DockableFloatingWindow(this); flWindow.Content = paneForFloatingWindow; flWindow.Left = location.X; flWindow.Top = location.Y; flWindow.Width = size.Width; flWindow.Height = size.Height; flWindow.Owner = Window.GetWindow(this); flWindow.IsDockableWindow = isDockableWindow; flWindow.ShowActivated = false; flWindow.ApplyTemplate(); flWindow.Show(); } } ClearEmptyPanels(Content as ResizingPanel); //get documents that are not present in last layout and must be included //in the new one var documentsNotTransferred = actualDocuments.Where(d => d.ContainerPane == null || d.ContainerPane.GetManager() != this).ToArray(); Debug.Assert(MainDocumentPane != null && MainDocumentPane.GetManager() == this); if (MainDocumentPane != null && documentsNotTransferred.Count() > 0) { documentsNotTransferred.ForEach(d => MainDocumentPane.Items.Add(d.DetachFromContainerPane())); } //get contents that are not present in the new layout and hide them var contentsNotTransferred = actualContents.Where(c => c.ContainerPane == null || c.ContainerPane.GetManager() != this).ToArray(); contentsNotTransferred.ForEach(c => { Hide(c); }); RestoringLayout = false; ClearEmptyPanes(); RefreshContents(); if (ActiveDocument != null && (ActiveDocument.ContainerPane == null || ActiveDocument.ContainerPane.GetManager() != this)) { if (Documents.Count > 0) ActiveDocument = Documents[0]; else ActiveDocument = null; } ActiveContent = ActiveDocument; }
/// <summary> /// Show a dockable content in its container with a desidered state /// </summary> /// <param name="content">Content to show</param> /// <param name="desideredState">State desidered</param> /// <param name="desideredAnchor">Border to which anchor the newly created container pane</param> /// <remarks></remarks> internal void Show(DockableContent content, DockableContentState desideredState, AnchorStyle desideredAnchor) { Debug.WriteLine(string.Format("Show Content={0}, desideredState={1}, desideredAnchor={2}", content.Name, desideredState, desideredAnchor)); #region Dockable content if (desideredState == DockableContentState.Hidden)//??!!show hidden? Hide(content); if (content.State == DockableContentState.AutoHide) { //first redock the content (content.ContainerPane as DockablePane).ToggleAutoHide(); //then show it as desidered Show(content, desideredState, desideredAnchor); } else if (content.State == DockableContentState.Docked || content.State == DockableContentState.Document || content.State == DockableContentState.None) { if (content.ContainerPane == null || content.State == DockableContentState.None) { //Problem!? try to rescue if (content.State == DockableContentState.Docked || content.State == DockableContentState.None) { //find the the pane which the desidered anchor style //DockablePane foundPane = this.FindChildDockablePane(desideredAnchor != AnchorStyle.None ? desideredAnchor : AnchorStyle.Right); //first search for a pane with other contents (avoiding empty panes which are containers for hidden contents) ILinqToTree<DependencyObject> itemFound = new LogicalTreeAdapter(this).Descendants().FirstOrDefault(el => el.Item is DockablePane && (el.Item as DockablePane).Anchor == desideredAnchor && (el.Item as DockablePane).IsDocked); if (itemFound == null)//search for all panes (even empty) itemFound = new LogicalTreeAdapter(this).Descendants().FirstOrDefault(el => el.Item is DockablePane && (el.Item as DockablePane).Anchor == desideredAnchor && (el.Item as DockablePane).Items.Count == 0); DockablePane foundPane = itemFound != null ? itemFound.Item as DockablePane : null; if (foundPane != null) { content.SetStateToDock(); foundPane.Items.Add(content); var containerPanel = foundPane.Parent as ResizingPanel; if (containerPanel != null) containerPanel.InvalidateMeasure(); } else { //if no suitable pane was found create e new one on the fly if (content.ContainerPane != null) { content.ContainerPane.RemoveContent(content); } DockablePane pane = new DockablePane(); pane.Items.Add(content); Anchor(pane, desideredAnchor); } } else { //add to main document pane MainDocumentPane.Items.Add(content); } } if (content.ContainerPane.GetManager() == null) { //disconnect the parent pane from previous panel //((Panel)content.ContainerPane.Parent).Children.Remove(content.ContainerPane); if (content.ContainerPane.Parent != null) { ((Panel)content.ContainerPane.Parent).Children.Remove(content.ContainerPane); } Anchor(content.ContainerPane as DockablePane, desideredAnchor); } if (desideredState == DockableContentState.DockableWindow || desideredState == DockableContentState.FloatingWindow) { var floatingWindow = new DockableFloatingWindow(this); floatingWindow.Content = content; var mainWindow = Window.GetWindow(this); if (mainWindow.IsVisible) floatingWindow.Owner = mainWindow; //floatingWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner; //if (content.Content != null) //{ // floatingWindow.Width = Math.Min(((FrameworkElement)content.Content).ActualWidth, ResizingPanel.GetResizeWidth(content.ContainerPane)); // floatingWindow.Height = Math.Min(((FrameworkElement)content.Content).ActualHeight, ResizingPanel.GetResizeHeight(content.ContainerPane)); //} //else ////{ // floatingWindow.Width = 400; // floatingWindow.Height = 400; //} floatingWindow.Show(); } else if (desideredState == DockableContentState.AutoHide) { var paneContainer = content.ContainerPane as DockablePane; Debug.Assert(paneContainer != null); if (paneContainer != null) paneContainer.ToggleAutoHide(); content.Activate(); } else if (desideredState == DockableContentState.Document) { DocumentPane docPane = MainDocumentPane; if (docPane != null) { docPane.Items.Add(content.DetachFromContainerPane()); docPane.SelectedItem = content; content.SetStateToDocument(); } } else { content.ContainerPane.SelectedItem = content; content.Activate(); DockablePane dockParent = content.ContainerPane as DockablePane; if (content.ActualWidth == 0.0 && ( dockParent.Anchor == AnchorStyle.Left || dockParent.Anchor == AnchorStyle.Right)) { ResizingPanel.SetResizeWidth(dockParent, new GridLength(200)); ResizingPanel.SetEffectiveSize(dockParent, new Size(200, 0.0)); } else if (content.ActualWidth == 0.0 && ( dockParent.Anchor == AnchorStyle.Top || dockParent.Anchor == AnchorStyle.Bottom)) { ResizingPanel.SetResizeHeight(dockParent, new GridLength(200)); ResizingPanel.SetEffectiveSize(dockParent, new Size(200, 0.0)); } } } else if (content.State == DockableContentState.Document) { if (content.ContainerPane != null) content.ContainerPane.SelectedItem = this; content.Activate(); } else if (content.State == DockableContentState.Hidden || content.State == DockableContentState.DockableWindow || content.State == DockableContentState.FloatingWindow) { if (content.State == DockableContentState.Hidden) { //Debug.Assert(HiddenContents.Contains(content)); //HiddenContents.Remove(content); } else { FloatingWindow floatingWindow = null; floatingWindow = (content.ContainerPane as FloatingDockablePane).FloatingWindow; content.DetachFromContainerPane(); if (floatingWindow.HostedPane.Items.Count == 0) floatingWindow.Close(); } if (desideredState == DockableContentState.Docked || desideredState == DockableContentState.AutoHide) { if (content.SavedStateAndPosition != null && content.SavedStateAndPosition.ContainerPane != null && content.SavedStateAndPosition.ChildIndex >= 0 && content.SavedStateAndPosition.ContainerPane.GetManager() == this && desideredState == DockableContentState.Docked) { //ok previous container pane is here.. Pane prevPane = content.SavedStateAndPosition.ContainerPane; if (content.SavedStateAndPosition.ChildIndex < prevPane.Items.Count) { prevPane.Items.Insert(content.SavedStateAndPosition.ChildIndex, content); } else { prevPane.Items.Add(content); } if (prevPane.Items.Count == 1) { if (!double.IsNaN(content.SavedStateAndPosition.Width) || !double.IsInfinity(content.SavedStateAndPosition.Width)) { ResizingPanel.SetResizeWidth(content, new GridLength(content.SavedStateAndPosition.Width)); } } DockablePane prevDockablePane = prevPane as DockablePane; if (prevDockablePane != null && prevDockablePane.IsAutoHidden) { prevDockablePane.ToggleAutoHide(); } content.SetStateToDock(); content.Activate(); (prevPane.Parent as UIElement).InvalidateMeasure(); } else { if (desideredAnchor == AnchorStyle.None && content.SavedStateAndPosition != null && content.SavedStateAndPosition.Anchor != AnchorStyle.None) desideredAnchor = content.SavedStateAndPosition.Anchor; if (desideredAnchor == AnchorStyle.None) desideredAnchor = AnchorStyle.Right; DockablePane foundPane = null; if (desideredState == DockableContentState.Docked) { //first not empty panes ILinqToTree<DependencyObject> itemFound = new LogicalTreeAdapter(this).Descendants().FirstOrDefault(el => el.Item is DockablePane && (el.Item as DockablePane).Anchor == desideredAnchor && (el.Item as DockablePane).IsDocked); if (itemFound == null)//look for all panes even empty itemFound = new LogicalTreeAdapter(this).Descendants().FirstOrDefault(el => el.Item is DockablePane && (el.Item as DockablePane).Anchor == desideredAnchor && (el.Item as DockablePane).Items.Count == 0); foundPane = itemFound != null ? itemFound.Item as DockablePane : null; } if (foundPane != null) { content.SetStateToDock(); foundPane.Items.Add(content); if ((foundPane.IsAutoHidden && desideredState == DockableContentState.Docked) || (!foundPane.IsAutoHidden && desideredState == DockableContentState.AutoHide)) foundPane.ToggleAutoHide(); } else { DockablePane newHostpane = new DockablePane(); newHostpane.Items.Add(content); if (desideredAnchor == AnchorStyle.Left || desideredAnchor == AnchorStyle.Right) { double w = 200; if (content.SavedStateAndPosition != null && !double.IsInfinity(content.SavedStateAndPosition.Width) && !double.IsNaN(content.SavedStateAndPosition.Width)) w = content.SavedStateAndPosition.Width; ResizingPanel.SetResizeWidth(newHostpane, new GridLength(w)); ResizingPanel.SetEffectiveSize(newHostpane, new Size(w, 0.0)); } else { double h = 200; if (content.SavedStateAndPosition != null && !double.IsInfinity(content.SavedStateAndPosition.Height) && !double.IsNaN(content.SavedStateAndPosition.Height)) h = content.SavedStateAndPosition.Height; ResizingPanel.SetResizeHeight(newHostpane, new GridLength(h)); ResizingPanel.SetEffectiveSize(newHostpane, new Size(0.0, h)); } Anchor(newHostpane, desideredAnchor); if (desideredState == DockableContentState.AutoHide) { ToggleAutoHide(newHostpane); } } } ActiveContent = content; } else if (desideredState == DockableContentState.DockableWindow || desideredState == DockableContentState.FloatingWindow) { DockablePane newHostpane = null; FloatingDockablePane prevHostpane = null; if (content.SavedStateAndPosition != null && content.SavedStateAndPosition.ContainerPane != null && content.SavedStateAndPosition.ContainerPane is FloatingDockablePane) { prevHostpane = content.SavedStateAndPosition.ContainerPane as FloatingDockablePane; if (!prevHostpane.Items.Contains(content)) prevHostpane.Items.Add(content); } else { newHostpane = new DockablePane(); newHostpane.Items.Add(content); } if (desideredState == DockableContentState.DockableWindow) content.SetStateToDockableWindow(); else if (desideredState == DockableContentState.FloatingWindow) content.SetStateToFloatingWindow(); if (prevHostpane != null) { //check to see if floating window that host prevHostPane is already loaded (hosting other contents) var floatingWindow = prevHostpane.Parent as DockableFloatingWindow; if (floatingWindow != null && floatingWindow.IsLoaded) { floatingWindow.Activate(); } else { floatingWindow = new DockableFloatingWindow(this); floatingWindow.Content = content; floatingWindow.WindowStartupLocation = WindowStartupLocation.Manual; floatingWindow.Top = prevHostpane.FloatingWindow.Top; floatingWindow.Left = prevHostpane.FloatingWindow.Left; floatingWindow.Width = prevHostpane.FloatingWindow.Width; floatingWindow.Height = prevHostpane.FloatingWindow.Height; //floatingWindow.Owner = Window.GetWindow(this); var mainWindow = Window.GetWindow(this); if (mainWindow.IsVisible) floatingWindow.Owner = mainWindow; //now I've created a new pane to host the hidden content //if a an hidden content is shown that has prevHostpane as saved pane //I want that it is relocated in this new pane that I've created right now var hiddenContents = DockableContents.Where(c => c.State == DockableContentState.Hidden).ToArray(); foreach (var hiddenContent in hiddenContents) { if (hiddenContent.SavedStateAndPosition.ContainerPane == prevHostpane) { hiddenContent.SavedStateAndPosition = new DockableContentStateAndPosition( (floatingWindow.Content as Pane), hiddenContent.SavedStateAndPosition.ChildIndex, hiddenContent.SavedStateAndPosition.Width, hiddenContent.SavedStateAndPosition.Height, hiddenContent.SavedStateAndPosition.Anchor, hiddenContent.SavedStateAndPosition.State); } } floatingWindow.Show(); } } else if (newHostpane != null) { var floatingWindow = new DockableFloatingWindow(this); floatingWindow.Content = newHostpane; floatingWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen; floatingWindow.Width = 200; floatingWindow.Height = 500; //floatingWindow.Owner = Window.GetWindow(this); var mainWindow = Window.GetWindow(this); if (mainWindow.IsVisible) floatingWindow.Owner = mainWindow; floatingWindow.Show(); } } else if (desideredState == DockableContentState.Document) { DocumentPane docPane = MainDocumentPane; if (docPane != null) { docPane.Items.Add(content); docPane.SelectedItem = content; content.SetStateToDocument(); } } } #endregion }