From 23482a35b8a487208084b5329d99239f84db56cc Mon Sep 17 00:00:00 2001 From: amolf-se <56731291+amolf-se@users.noreply.github.com> Date: Mon, 28 Oct 2019 12:04:45 +0100 Subject: [PATCH 1/5] Changes from SVN 35121: Added property changed event handler to set the SelectedIndex of the TabControl to the selectedContentIndex of the pane model. This will cause the tabcontrol do switch to the correct panel when IsActive is set. --- .../Controls/LayoutDocumentPaneControl.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneControl.cs b/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneControl.cs index ec687db8..0f99da0b 100644 --- a/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneControl.cs +++ b/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneControl.cs @@ -48,6 +48,14 @@ internal LayoutDocumentPaneControl( LayoutDocumentPane model ) SetBinding( ItemsSourceProperty, new Binding( "Model.Children" ) { Source = this } ); SetBinding( FlowDirectionProperty, new Binding( "Model.Root.Manager.FlowDirection" ) { Source = this } ); + model.PropertyChanged += (o, e) => + { + if (e.PropertyName == nameof(model.SelectedContentIndex)) + { + SelectedIndex = _model.SelectedContentIndex; + } + }; + // Handle SizeChanged event instead of LayoutUpdated. It will exlude fluctuations of Actual size values. // this.LayoutUpdated += new EventHandler( OnLayoutUpdated ); this.SizeChanged += OnSizeChanged; From d2d4467f49787faab6bde04b99867c5a43c16918 Mon Sep 17 00:00:00 2001 From: amolf-se <56731291+amolf-se@users.noreply.github.com> Date: Tue, 29 Oct 2019 09:18:50 +0100 Subject: [PATCH 2/5] Changed to SVN rev 41162. Dock document in floating window. Todo: check undock last document. --- .../Theme.xaml | 6 +- .../Theme.xaml | 6 +- .../Theme.xaml | 6 +- .../Theme.xaml | 6 +- .../Themes/Generic.xaml | 6 +- .../Controls/AnchorablePaneDropTarget.cs | 5 - .../Controls/DocumentPaneDropTarget.cs | 388 +++++++++--------- .../Controls/DocumentPaneGroupDropTarget.cs | 4 +- .../Controls/DragService.cs | 1 + .../LayoutDocumentFloatingWindowControl.cs | 267 ++++++++++-- .../Controls/LayoutDocumentPaneControl.cs | 25 -- .../Xceed.Wpf.AvalonDock/DockingManager.cs | 19 +- .../Layout/LayoutDocumentFloatingWindow.cs | 146 +++++-- .../Layout/LayoutDocumentPane.cs | 132 +++--- .../Xceed.Wpf.AvalonDock/Layout/LayoutRoot.cs | 15 + .../Xceed.Wpf.AvalonDock/Themes/generic.xaml | 25 +- 16 files changed, 688 insertions(+), 369 deletions(-) diff --git a/source/Components/Xceed.Wpf.AvalonDock.Themes.Aero/Theme.xaml b/source/Components/Xceed.Wpf.AvalonDock.Themes.Aero/Theme.xaml index 665ff718..c21193ea 100644 --- a/source/Components/Xceed.Wpf.AvalonDock.Themes.Aero/Theme.xaml +++ b/source/Components/Xceed.Wpf.AvalonDock.Themes.Aero/Theme.xaml @@ -1343,7 +1343,7 @@ - @@ -1358,7 +1358,7 @@ VerticalContentAlignment="Center" HorizontalContentAlignment="Center" DropDownContextMenu="{Binding Model.Root.Manager.DocumentContextMenu, RelativeSource={RelativeSource TemplatedParent}}" - DropDownContextMenuDataContext="{Binding Path=RootDocumentLayoutItem, RelativeSource={RelativeSource TemplatedParent}}" + DropDownContextMenuDataContext="{Binding Path=SingleContentLayoutItem, RelativeSource={RelativeSource TemplatedParent}}" ToolTip="{x:Static avalonDockProperties:Resources.Document_CxMenu_Hint}"> - @@ -914,7 +914,7 @@ VerticalContentAlignment="Center" HorizontalContentAlignment="Center" DropDownContextMenu="{Binding Model.Root.Manager.DocumentContextMenu, RelativeSource={RelativeSource TemplatedParent}}" - DropDownContextMenuDataContext="{Binding Path=RootDocumentLayoutItem, RelativeSource={RelativeSource TemplatedParent}}" + DropDownContextMenuDataContext="{Binding Path=SingleContentLayoutItem, RelativeSource={RelativeSource TemplatedParent}}" ToolTip="{x:Static avalonDockProperties:Resources.Document_CxMenu_Hint}"> @@ -951,7 +951,7 @@ Focusable="False" Style="{StaticResource AvalonDock_Expression_ButtonStyle}" Visibility="{Binding Path=IsEnabled, RelativeSource={RelativeSource Self}, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" - Command="{Binding Path=RootDocumentLayoutItem.CloseCommand, RelativeSource={RelativeSource TemplatedParent}}" + Command="{Binding Path=SingleContentLayoutItem.CloseCommand, RelativeSource={RelativeSource TemplatedParent}}" ToolTip="{x:Static avalonDockProperties:Resources.Document_Close}" Grid.Column="3"> diff --git a/source/Components/Xceed.Wpf.AvalonDock.Themes.Metro/Theme.xaml b/source/Components/Xceed.Wpf.AvalonDock.Themes.Metro/Theme.xaml index ac3a1a05..8321164c 100644 --- a/source/Components/Xceed.Wpf.AvalonDock.Themes.Metro/Theme.xaml +++ b/source/Components/Xceed.Wpf.AvalonDock.Themes.Metro/Theme.xaml @@ -1401,7 +1401,7 @@ - @@ -1416,7 +1416,7 @@ VerticalContentAlignment="Center" HorizontalContentAlignment="Center" DropDownContextMenu="{Binding Model.Root.Manager.DocumentContextMenu, RelativeSource={RelativeSource TemplatedParent}}" - DropDownContextMenuDataContext="{Binding Path=RootDocumentLayoutItem, RelativeSource={RelativeSource TemplatedParent}}" + DropDownContextMenuDataContext="{Binding Path=SingleContentLayoutItem, RelativeSource={RelativeSource TemplatedParent}}" ToolTip="{x:Static avalonDockProperties:Resources.Document_CxMenu_Hint}"> - @@ -1498,7 +1498,7 @@ VerticalContentAlignment="Center" HorizontalContentAlignment="Center" DropDownContextMenu="{Binding Model.Root.Manager.DocumentContextMenu, RelativeSource={RelativeSource TemplatedParent}}" - DropDownContextMenuDataContext="{Binding Path=RootDocumentLayoutItem, RelativeSource={RelativeSource TemplatedParent}}" + DropDownContextMenuDataContext="{Binding Path=SingleContentLayoutItem, RelativeSource={RelativeSource TemplatedParent}}" ToolTip="{x:Static avalonDockProperties:Resources.Document_CxMenu_Hint}"> - ().FirstOrDefault(); + + switch (Type) + { + case DropTargetType.DocumentPaneDockBottom: + #region DropTargetType.DocumentPaneDockBottom + { + var parentModel = targetModel.Parent as ILayoutGroup; + var parentModelOrientable = targetModel.Parent as ILayoutOrientableGroup; + int insertToIndex = parentModel.IndexOfChild(targetModel); + + if (parentModelOrientable.Orientation != System.Windows.Controls.Orientation.Vertical && + parentModel.ChildrenCount == 1) + parentModelOrientable.Orientation = System.Windows.Controls.Orientation.Vertical; + + if (parentModelOrientable.Orientation == System.Windows.Controls.Orientation.Vertical) + { + var layoutDocumentPaneGroup = floatingWindow.RootPanel as LayoutDocumentPaneGroup; + if (layoutDocumentPaneGroup != null && + (layoutDocumentPaneGroup.Children.Count == 1 || + layoutDocumentPaneGroup.Orientation == System.Windows.Controls.Orientation.Vertical)) + { + var documentsToMove = layoutDocumentPaneGroup.Children.ToArray(); + for (int i = 0; i < documentsToMove.Length; i++) + parentModel.InsertChildAt(insertToIndex + 1 + i, documentsToMove[i]); + } + else + parentModel.InsertChildAt(insertToIndex + 1, floatingWindow.RootPanel); + } + else + { + var targetModelAsPositionableElement = targetModel as ILayoutPositionableElement; + var newOrientedPanel = new LayoutDocumentPaneGroup() + { + Orientation = System.Windows.Controls.Orientation.Vertical, + DockWidth = targetModelAsPositionableElement.DockWidth, + DockHeight = targetModelAsPositionableElement.DockHeight, + }; + + parentModel.InsertChildAt(insertToIndex, newOrientedPanel); + newOrientedPanel.Children.Add(targetModel); + newOrientedPanel.Children.Add(floatingWindow.RootPanel); + + } + } + break; + #endregion + case DropTargetType.DocumentPaneDockTop: + #region DropTargetType.DocumentPaneDockTop + { + var parentModel = targetModel.Parent as ILayoutGroup; + var parentModelOrientable = targetModel.Parent as ILayoutOrientableGroup; + int insertToIndex = parentModel.IndexOfChild(targetModel); + + if (parentModelOrientable.Orientation != System.Windows.Controls.Orientation.Vertical && + parentModel.ChildrenCount == 1) + parentModelOrientable.Orientation = System.Windows.Controls.Orientation.Vertical; + + if (parentModelOrientable.Orientation == System.Windows.Controls.Orientation.Vertical) + { + var layoutDocumentPaneGroup = floatingWindow.RootPanel as LayoutDocumentPaneGroup; + if (layoutDocumentPaneGroup != null && + (layoutDocumentPaneGroup.Children.Count == 1 || + layoutDocumentPaneGroup.Orientation == System.Windows.Controls.Orientation.Vertical)) + { + var documentsToMove = layoutDocumentPaneGroup.Children.ToArray(); + for (int i = 0; i < documentsToMove.Length; i++) + parentModel.InsertChildAt(insertToIndex + i, documentsToMove[i]); + } + else + parentModel.InsertChildAt(insertToIndex, floatingWindow.RootPanel); + } + else + { + var targetModelAsPositionableElement = targetModel as ILayoutPositionableElement; + var newOrientedPanel = new LayoutDocumentPaneGroup() + { + Orientation = System.Windows.Controls.Orientation.Vertical, + DockWidth = targetModelAsPositionableElement.DockWidth, + DockHeight = targetModelAsPositionableElement.DockHeight, + }; + + parentModel.InsertChildAt(insertToIndex, newOrientedPanel); + //the floating window must be added after the target modal as it could be raise a CollectGarbage call + newOrientedPanel.Children.Add(targetModel); + newOrientedPanel.Children.Insert(0, floatingWindow.RootPanel); + + } + } + break; + #endregion + case DropTargetType.DocumentPaneDockLeft: + #region DropTargetType.DocumentPaneDockLeft + { + var parentModel = targetModel.Parent as ILayoutGroup; + var parentModelOrientable = targetModel.Parent as ILayoutOrientableGroup; + int insertToIndex = parentModel.IndexOfChild(targetModel); + + if (parentModelOrientable.Orientation != System.Windows.Controls.Orientation.Horizontal && + parentModel.ChildrenCount == 1) + parentModelOrientable.Orientation = System.Windows.Controls.Orientation.Horizontal; + + if (parentModelOrientable.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + var layoutDocumentPaneGroup = floatingWindow.RootPanel as LayoutDocumentPaneGroup; + if (layoutDocumentPaneGroup != null && + (layoutDocumentPaneGroup.Children.Count == 1 || + layoutDocumentPaneGroup.Orientation == System.Windows.Controls.Orientation.Horizontal)) + { + var documentsToMove = layoutDocumentPaneGroup.Children.ToArray(); + for (int i = 0; i < documentsToMove.Length; i++) + parentModel.InsertChildAt(insertToIndex + i, documentsToMove[i]); + } + else + parentModel.InsertChildAt(insertToIndex, floatingWindow.RootPanel); + } + else + { + var targetModelAsPositionableElement = targetModel as ILayoutPositionableElement; + var newOrientedPanel = new LayoutDocumentPaneGroup() + { + Orientation = System.Windows.Controls.Orientation.Horizontal, + DockWidth = targetModelAsPositionableElement.DockWidth, + DockHeight = targetModelAsPositionableElement.DockHeight, + }; + + parentModel.InsertChildAt(insertToIndex, newOrientedPanel); + //the floating window must be added after the target modal as it could be raise a CollectGarbage call + newOrientedPanel.Children.Add(targetModel); + newOrientedPanel.Children.Insert(0, floatingWindow.RootPanel); + + } + } + break; + #endregion + case DropTargetType.DocumentPaneDockRight: + #region DropTargetType.DocumentPaneDockRight + { + var parentModel = targetModel.Parent as ILayoutGroup; + var parentModelOrientable = targetModel.Parent as ILayoutOrientableGroup; + int insertToIndex = parentModel.IndexOfChild(targetModel); + + if (parentModelOrientable.Orientation != System.Windows.Controls.Orientation.Horizontal && + parentModel.ChildrenCount == 1) + parentModelOrientable.Orientation = System.Windows.Controls.Orientation.Horizontal; + + if (parentModelOrientable.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + var layoutDocumentPaneGroup = floatingWindow.RootPanel as LayoutDocumentPaneGroup; + if (layoutDocumentPaneGroup != null && + (layoutDocumentPaneGroup.Children.Count == 1 || + layoutDocumentPaneGroup.Orientation == System.Windows.Controls.Orientation.Horizontal)) + { + var documentToMove = layoutDocumentPaneGroup.Children.ToArray(); + for (int i = 0; i < documentToMove.Length; i++) + parentModel.InsertChildAt(insertToIndex + 1 + i, documentToMove[i]); + } + else + parentModel.InsertChildAt(insertToIndex + 1, floatingWindow.RootPanel); + } + else + { + var targetModelAsPositionableElement = targetModel as ILayoutPositionableElement; + var newOrientedPanel = new LayoutDocumentPaneGroup() + { + Orientation = System.Windows.Controls.Orientation.Horizontal, + DockWidth = targetModelAsPositionableElement.DockWidth, + DockHeight = targetModelAsPositionableElement.DockHeight, + }; + + parentModel.InsertChildAt(insertToIndex, newOrientedPanel); + newOrientedPanel.Children.Add(targetModel); + newOrientedPanel.Children.Add(floatingWindow.RootPanel); + + } + } + break; + #endregion + + case DropTargetType.DocumentPaneDockInside: + #region DropTargetType.DocumentPaneDockInside + { + var paneModel = targetModel as LayoutDocumentPane; + var layoutDocumentPaneGroup = floatingWindow.RootPanel as LayoutDocumentPaneGroup; + + int i = _tabIndex == -1 ? 0 : _tabIndex; + foreach (var anchorableToImport in + layoutDocumentPaneGroup.Descendents().OfType().ToArray()) + { + paneModel.Children.Insert(i, anchorableToImport); + i++; + } + } + break; + #endregion + } + + documentActive.IsActive = true; + + base.Drop(floatingWindow); + } protected override void Drop( LayoutAnchorableFloatingWindow floatingWindow ) { diff --git a/source/Components/Xceed.Wpf.AvalonDock/Controls/DocumentPaneGroupDropTarget.cs b/source/Components/Xceed.Wpf.AvalonDock/Controls/DocumentPaneGroupDropTarget.cs index b9e3c999..97996682 100644 --- a/source/Components/Xceed.Wpf.AvalonDock/Controls/DocumentPaneGroupDropTarget.cs +++ b/source/Components/Xceed.Wpf.AvalonDock/Controls/DocumentPaneGroupDropTarget.cs @@ -51,8 +51,8 @@ protected override void Drop( LayoutDocumentFloatingWindow floatingWindow ) #region DropTargetType.DocumentPaneGroupDockInside { var paneGroupModel = targetModel as LayoutDocumentPaneGroup; - var paneModel = paneGroupModel.Children[ 0 ] as LayoutDocumentPane; - var sourceModel = floatingWindow.RootDocument; + var paneModel = paneGroupModel as LayoutDocumentPaneGroup; + var sourceModel = floatingWindow.RootPanel as LayoutDocumentPaneGroup; paneModel.Children.Insert( 0, sourceModel ); } diff --git a/source/Components/Xceed.Wpf.AvalonDock/Controls/DragService.cs b/source/Components/Xceed.Wpf.AvalonDock/Controls/DragService.cs index 9676deca..e43cce14 100644 --- a/source/Components/Xceed.Wpf.AvalonDock/Controls/DragService.cs +++ b/source/Components/Xceed.Wpf.AvalonDock/Controls/DragService.cs @@ -193,6 +193,7 @@ internal void Abort() private void GetOverlayWindowHosts() { _overlayWindowHosts.AddRange( _manager.GetFloatingWindowsByZOrder().OfType().Where( fw => fw != _floatingWindow && fw.IsVisible ) ); + _overlayWindowHosts.AddRange(_manager.GetFloatingWindowsByZOrder().OfType().Where(fw => fw != _floatingWindow && fw.IsVisible)); _overlayWindowHosts.Add( _manager ); } diff --git a/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs b/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs index dceea960..558cf800 100644 --- a/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs +++ b/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs @@ -15,14 +15,18 @@ This program is provided to you under the terms of the Microsoft Public ***********************************************************************************/ using System; +using System.Collections.Generic; +using System.Linq; using Xceed.Wpf.AvalonDock.Layout; using System.Windows; using System.Windows.Controls.Primitives; +using System.Windows.Input; using Microsoft.Windows.Shell; +using Xceed.Wpf.AvalonDock.Commands; namespace Xceed.Wpf.AvalonDock.Controls { - public class LayoutDocumentFloatingWindowControl : LayoutFloatingWindowControl + public class LayoutDocumentFloatingWindowControl : LayoutFloatingWindowControl, IOverlayWindowHost { #region Members @@ -41,6 +45,7 @@ internal LayoutDocumentFloatingWindowControl( LayoutDocumentFloatingWindow model : base( model, isContentImmutable ) { _model = model; + HideWindowCommand = new RelayCommand((p) => OnExecuteHideWindowCommand(p), (p) => CanExecuteHideWindowCommand(p)); UpdateThemeResources(); } @@ -53,13 +58,13 @@ internal LayoutDocumentFloatingWindowControl( LayoutDocumentFloatingWindow model #region Properties - public LayoutItem RootDocumentLayoutItem - { - get - { - return _model.Root.Manager.GetLayoutItemFromModel( _model.RootDocument ); - } - } + //public LayoutItem RootDocumentLayoutItem + //{ + // get + // { + // return _model.Root.Manager.GetLayoutItemFromModel( _model.RootPanel ); + // } + //} #endregion @@ -73,22 +78,63 @@ public override ILayoutElement Model } } + #region SingleContentLayoutItem + + /// + /// SingleContentLayoutItem Dependency Property + /// + public static readonly DependencyProperty SingleContentLayoutItemProperty = + DependencyProperty.Register("SingleContentLayoutItem", typeof(LayoutItem), typeof(LayoutDocumentFloatingWindowControl), + new FrameworkPropertyMetadata((LayoutItem)null, + new PropertyChangedCallback(OnSingleContentLayoutItemChanged))); + + /// + /// Gets or sets the SingleContentLayoutItem property. This dependency property + /// indicates the layout item of the selected content when is shown a single anchorable pane. + /// + public LayoutItem SingleContentLayoutItem + { + get { return (LayoutItem)GetValue(SingleContentLayoutItemProperty); } + set { SetValue(SingleContentLayoutItemProperty, value); } + } + + /// + /// Handles changes to the SingleContentLayoutItem property. + /// + private static void OnSingleContentLayoutItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutDocumentFloatingWindowControl)d).OnSingleContentLayoutItemChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the SingleContentLayoutItem property. + /// + protected virtual void OnSingleContentLayoutItemChanged(DependencyPropertyChangedEventArgs e) + { + } + + #endregion + protected override void OnInitialized( EventArgs e ) { base.OnInitialized( e ); - if( _model.RootDocument == null ) - { - InternalClose(); - } - else - { - var manager = _model.Root.Manager; + var manager = _model.Root.Manager; - Content = manager.CreateUIElementForModel( _model.RootDocument ); + Content = manager.CreateUIElementForModel(_model.RootPanel); + // TODO IsVisibleChanged + //SetBinding(SingleContentLayoutItemProperty, new Binding("Model.SinglePane.SelectedContent") { Source = this, Converter = new LayoutItemFromLayoutModelConverter() }); - _model.RootDocumentChanged += new EventHandler( _model_RootDocumentChanged ); - } + _model.RootPanel.ChildrenCollectionChanged += RootPanelOnChildrenCollectionChanged; + } + + void _model_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (e.PropertyName == "RootPanel" && + _model.RootPanel == null) + { + InternalClose(); + } } protected override IntPtr FilterMessage( IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled ) @@ -98,8 +144,8 @@ protected override IntPtr FilterMessage( IntPtr hwnd, int msg, IntPtr wParam, In case Win32Helper.WM_NCLBUTTONDOWN: //Left button down on title -> start dragging over docking manager if( wParam.ToInt32() == Win32Helper.HT_CAPTION ) { - if( _model.RootDocument != null ) - _model.RootDocument.IsActive = true; + _model.Descendents().OfType().First(p => p.ChildrenCount > 0 && p.SelectedContent != null).SelectedContent.IsActive = true; + handled = true; } break; case Win32Helper.WM_NCRBUTTONUP: @@ -113,7 +159,6 @@ protected override IntPtr FilterMessage( IntPtr hwnd, int msg, IntPtr wParam, In WindowChrome.GetWindowChrome( this ).ShowSystemMenu = false; } break; - } return base.FilterMessage( hwnd, msg, wParam, lParam, ref handled ); @@ -122,46 +167,196 @@ protected override IntPtr FilterMessage( IntPtr hwnd, int msg, IntPtr wParam, In protected override void OnClosed( EventArgs e ) { var root = Model.Root; - root.Manager.RemoveFloatingWindow( this ); - root.CollectGarbage(); + root?.Manager.RemoveFloatingWindow( this ); + root?.CollectGarbage(); + + if (_overlayWindow != null) + { + _overlayWindow.Close(); + _overlayWindow = null; + } base.OnClosed( e ); if( !CloseInitiatedByUser ) { - root.FloatingWindows.Remove( _model ); + root?.FloatingWindows.Remove( _model ); } - _model.RootDocumentChanged -= new EventHandler( _model_RootDocumentChanged ); + _model.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler(_model_PropertyChanged); } #endregion #region Private Methods - private void _model_RootDocumentChanged( object sender, EventArgs e ) + private void RootPanelOnChildrenCollectionChanged(object sender, EventArgs e) { - if( _model.RootDocument == null ) - { - InternalClose(); - } + if( _model.RootPanel.Children.Count == 0) + { + InternalClose(); + } } private bool OpenContextMenu() { var ctxMenu = _model.Root.Manager.DocumentContextMenu; - if( ctxMenu != null && RootDocumentLayoutItem != null ) + if (ctxMenu != null && SingleContentLayoutItem != null) { - ctxMenu.PlacementTarget = null; - ctxMenu.Placement = PlacementMode.MousePoint; - ctxMenu.DataContext = RootDocumentLayoutItem; - ctxMenu.IsOpen = true; - return true; + ctxMenu.PlacementTarget = null; + ctxMenu.Placement = PlacementMode.MousePoint; + ctxMenu.DataContext = SingleContentLayoutItem; + ctxMenu.IsOpen = true; + return true; } return false; } + protected override void OnClosing(System.ComponentModel.CancelEventArgs e) + { + // TODO + if (CloseInitiatedByUser && !KeepContentVisibleOnClose) + { + e.Cancel = true; + //_model.Descendents().OfType().ToArray().ForEach((a) => a.Hide()); + } + + base.OnClosing(e); + } + + bool IOverlayWindowHost.HitTest(Point dragPoint) + { + Rect detectionRect = new Rect(this.PointToScreenDPIWithoutFlowDirection(new Point()), this.TransformActualSizeToAncestor()); + return detectionRect.Contains(dragPoint); + } + + DockingManager IOverlayWindowHost.Manager + { + get { return _model.Root.Manager; } + } + + OverlayWindow _overlayWindow = null; + + void CreateOverlayWindow() + { + if (_overlayWindow == null) + _overlayWindow = new OverlayWindow(this); + Rect rectWindow = new Rect(this.PointToScreenDPIWithoutFlowDirection(new Point()), this.TransformActualSizeToAncestor()); + _overlayWindow.Left = rectWindow.Left; + _overlayWindow.Top = rectWindow.Top; + _overlayWindow.Width = rectWindow.Width; + _overlayWindow.Height = rectWindow.Height; + } + + IOverlayWindow IOverlayWindowHost.ShowOverlayWindow(LayoutFloatingWindowControl draggingWindow) + { + CreateOverlayWindow(); + _overlayWindow.Owner = draggingWindow; + _overlayWindow.EnableDropTargets(); + _overlayWindow.Show(); + + return _overlayWindow; + } + + public void HideOverlayWindow() + { + _dropAreas = null; + _overlayWindow.Owner = null; + _overlayWindow.HideDropTargets(); + } + + List _dropAreas = null; + public IEnumerable GetDropAreas(LayoutFloatingWindowControl draggingWindow) + { + if (_dropAreas != null) + return _dropAreas; + + _dropAreas = new List(); + + var rootVisual = (Content as FloatingWindowContentHost).RootVisual; + + foreach (var areaHost in rootVisual.FindVisualChildren()) + { + _dropAreas.Add(new DropArea( + areaHost, + DropAreaType.AnchorablePane)); + } + foreach (var areaHost in rootVisual.FindVisualChildren()) + { + _dropAreas.Add(new DropArea( + areaHost, + DropAreaType.DocumentPane)); + } + + return _dropAreas; + } + + #region HideWindowCommand + public ICommand HideWindowCommand + { + get; + private set; + } + + private bool CanExecuteHideWindowCommand(object parameter) + { + if (Model == null) + return false; + + var root = Model.Root; + if (root == null) + return false; + + var manager = root.Manager; + if (manager == null) + return false; + + // TODO check CanHide of anchorables + bool canExecute = false; + foreach (var content in this.Model.Descendents().OfType().ToArray()) + { + if ((content is LayoutAnchorable anchorable && !anchorable.CanHide) || + !content.CanClose) + { + canExecute = false; + break; + } + + //if (!(manager.GetLayoutItemFromModel(content) is LayoutAnchorableItem layoutAnchorableItem) || + // layoutAnchorableItem.HideCommand == null || + // !layoutAnchorableItem.HideCommand.CanExecute(parameter)) + //{ + // canExecute = false; + // break; + //} + if (!(manager.GetLayoutItemFromModel(content) is LayoutItem layoutItem) || + layoutItem.CloseCommand == null || + !layoutItem.CloseCommand.CanExecute(parameter)) + { + canExecute = false; + break; + } + + canExecute = true; + } + + return canExecute; + } + + private void OnExecuteHideWindowCommand(object parameter) + { + var manager = Model.Root.Manager; + foreach (var anchorable in this.Model.Descendents().OfType().ToArray()) + { + //if (manager.GetLayoutItemFromModel(anchorable) is LayoutAnchorableItem layoutAnchorableItem) layoutAnchorableItem.HideCommand.Execute(parameter); + //else + if (manager.GetLayoutItemFromModel(anchorable) is LayoutItem layoutItem) layoutItem.CloseCommand.Execute(parameter); + } + } + #endregion + + #endregion } } diff --git a/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneControl.cs b/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneControl.cs index 0f99da0b..b40213c4 100644 --- a/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneControl.cs +++ b/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneControl.cs @@ -27,7 +27,6 @@ public class LayoutDocumentPaneControl : TabControl, ILayoutControl//, ILogicalC { #region Members - private List _logicalChildren = new List(); private LayoutDocumentPane _model; #endregion @@ -48,14 +47,6 @@ internal LayoutDocumentPaneControl( LayoutDocumentPane model ) SetBinding( ItemsSourceProperty, new Binding( "Model.Children" ) { Source = this } ); SetBinding( FlowDirectionProperty, new Binding( "Model.Root.Manager.FlowDirection" ) { Source = this } ); - model.PropertyChanged += (o, e) => - { - if (e.PropertyName == nameof(model.SelectedContentIndex)) - { - SelectedIndex = _model.SelectedContentIndex; - } - }; - // Handle SizeChanged event instead of LayoutUpdated. It will exlude fluctuations of Actual size values. // this.LayoutUpdated += new EventHandler( OnLayoutUpdated ); this.SizeChanged += OnSizeChanged; @@ -77,22 +68,6 @@ public ILayoutElement Model #region Overrides - protected override System.Collections.IEnumerator LogicalChildren - { - get - { - return _logicalChildren.GetEnumerator(); - } - } - - protected override void OnSelectionChanged( SelectionChangedEventArgs e ) - { - base.OnSelectionChanged( e ); - - if( _model.SelectedContent != null ) - _model.SelectedContent.IsActive = true; - } - protected override void OnMouseLeftButtonDown( System.Windows.Input.MouseButtonEventArgs e ) { base.OnMouseLeftButtonDown( e ); diff --git a/source/Components/Xceed.Wpf.AvalonDock/DockingManager.cs b/source/Components/Xceed.Wpf.AvalonDock/DockingManager.cs index b9350e6c..468f8d93 100644 --- a/source/Components/Xceed.Wpf.AvalonDock/DockingManager.cs +++ b/source/Components/Xceed.Wpf.AvalonDock/DockingManager.cs @@ -2122,7 +2122,7 @@ internal UIElement CreateUIElementForModel( ILayoutElement model ) }; newFW.SetParentToMainWindowOf( this ); - var paneForExtensions = modelFW.RootDocument; + var paneForExtensions = modelFW.RootPanel; if( paneForExtensions != null ) { //ensure that floating window position is inside current (or nearest) monitor @@ -3310,7 +3310,18 @@ private LayoutFloatingWindowControl CreateFloatingWindowCore( LayoutContent cont var anchorableDocument = contentModel as LayoutDocument; fw = new LayoutDocumentFloatingWindow() { - RootDocument = anchorableDocument + RootPanel = new LayoutDocumentPaneGroup( + new LayoutDocumentPane(anchorableDocument) + { + DockWidth = parentPaneAsPositionableElement.DockWidth, + DockHeight = parentPaneAsPositionableElement.DockHeight, + DockMinHeight = parentPaneAsPositionableElement.DockMinHeight, + DockMinWidth = parentPaneAsPositionableElement.DockMinWidth, + FloatingLeft = parentPaneAsPositionableElement.FloatingLeft, + FloatingTop = parentPaneAsPositionableElement.FloatingTop, + FloatingWidth = parentPaneAsPositionableElement.FloatingWidth, + FloatingHeight = parentPaneAsPositionableElement.FloatingHeight, + }) }; Layout.FloatingWindows.Add( fw ); @@ -3325,11 +3336,9 @@ private LayoutFloatingWindowControl CreateFloatingWindowCore( LayoutContent cont }; } - //fwc.Owner = Window.GetWindow(this); //fwc.SetParentToMainWindowOf(this); - - + _fwList.Add( fwc ); Layout.CollectGarbage(); diff --git a/source/Components/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentFloatingWindow.cs b/source/Components/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentFloatingWindow.cs index c6e5892e..9522e94f 100644 --- a/source/Components/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentFloatingWindow.cs +++ b/source/Components/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentFloatingWindow.cs @@ -18,14 +18,15 @@ This program is provided to you under the terms of the Microsoft Public using System.Collections.Generic; using System.Windows.Markup; using System.Diagnostics; +using System.Linq; using System.Xml.Serialization; using System.Xml; namespace Xceed.Wpf.AvalonDock.Layout { - [ContentProperty( "RootDocument" )] + [ContentProperty( "RootPanel" )] [Serializable] - public class LayoutDocumentFloatingWindow : LayoutFloatingWindow + public class LayoutDocumentFloatingWindow : LayoutFloatingWindow, ILayoutElementWithVisibility { #region Constructors @@ -37,73 +38,141 @@ public LayoutDocumentFloatingWindow() #region Properties - #region RootDocument + #region RootPanel - private LayoutDocument _rootDocument = null; - public LayoutDocument RootDocument + private LayoutDocumentPaneGroup _rootPanel = null; + public LayoutDocumentPaneGroup RootPanel { get { - return _rootDocument; + return _rootPanel; } set { - if( _rootDocument != value ) + if( _rootPanel != value ) { - RaisePropertyChanging( "RootDocument" ); - _rootDocument = value; - if( _rootDocument != null ) - _rootDocument.Parent = this; - RaisePropertyChanged( "RootDocument" ); - - if( RootDocumentChanged != null ) - RootDocumentChanged( this, EventArgs.Empty ); + if (_rootPanel != null) + _rootPanel.ChildrenTreeChanged -= new EventHandler(_rootPanel_ChildrenTreeChanged); + + _rootPanel = value; + if (_rootPanel != null) + _rootPanel.Parent = this; + + if (_rootPanel != null) + _rootPanel.ChildrenTreeChanged += new EventHandler(_rootPanel_ChildrenTreeChanged); + + RaisePropertyChanged("RootPanel"); + RaisePropertyChanged("IsSinglePane"); + RaisePropertyChanged("SinglePane"); + RaisePropertyChanged("Children"); + RaisePropertyChanged("ChildrenCount"); + ((ILayoutElementWithVisibility)this).ComputeVisibility(); } } } - #endregion + void _rootPanel_ChildrenTreeChanged(object sender, ChildrenTreeChangedEventArgs e) + { + RaisePropertyChanged("IsSinglePane"); + RaisePropertyChanged("SinglePane"); - #endregion + } - #region Overrides + public bool IsSinglePane + { + get + { + return RootPanel != null && RootPanel.Descendents().OfType().Where(p => p.IsVisible).Count() == 1; + } + } - public override IEnumerable Children + public ILayoutDocumentPane SinglePane { - get - { - if( RootDocument == null ) - yield break; + get + { + if (!IsSinglePane) + return null; + + var singlePane = RootPanel.Descendents().OfType().Single(p => p.IsVisible); + //singlePane.UpdateIsDirectlyHostedInFloatingWindow(); + return singlePane; + } + } + + #endregion + + public override IEnumerable Children + { + get + { + if (ChildrenCount == 1) + yield return RootPanel; - yield return RootDocument; - } + yield break; + } } public override void RemoveChild( ILayoutElement element ) { - Debug.Assert( element == RootDocument && element != null ); - RootDocument = null; + Debug.Assert( element == RootPanel && element != null ); + RootPanel = null; } public override void ReplaceChild( ILayoutElement oldElement, ILayoutElement newElement ) { - Debug.Assert( oldElement == RootDocument && oldElement != null ); - RootDocument = newElement as LayoutDocument; + Debug.Assert( oldElement == RootPanel && oldElement != null ); + RootPanel = newElement as LayoutDocumentPaneGroup; } public override int ChildrenCount { - get - { - return RootDocument != null ? 1 : 0; - } + get + { + if (RootPanel == null) + return 0; + return 1; + } } + #region IsVisible + [NonSerialized] + private bool _isVisible = true; + + [XmlIgnore] + public bool IsVisible + { + get { return _isVisible; } + private set + { + if (_isVisible != value) + { + RaisePropertyChanging("IsVisible"); + _isVisible = value; + RaisePropertyChanged("IsVisible"); + if (IsVisibleChanged != null) + IsVisibleChanged(this, EventArgs.Empty); + } + } + } + + public event EventHandler IsVisibleChanged; + + #endregion + + void ILayoutElementWithVisibility.ComputeVisibility() + { + if (RootPanel != null) + IsVisible = RootPanel.IsVisible; + else + IsVisible = false; + } + + public override bool IsValid { get { - return RootDocument != null; + return RootPanel != null; } } @@ -147,7 +216,7 @@ public override void ReadXml( XmlReader reader ) serializer = new XmlSerializer( type ); } - RootDocument = ( LayoutDocument )serializer.Deserialize( reader ); + RootPanel = ( LayoutDocumentPaneGroup )serializer.Deserialize( reader ); } reader.ReadEndElement(); @@ -159,16 +228,11 @@ public override void ConsoleDump(int tab) System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) ); System.Diagnostics.Trace.WriteLine( "FloatingDocumentWindow()" ); - RootDocument.ConsoleDump(tab + 1); + RootPanel.ConsoleDump(tab + 1); } #endif #endregion - #region Events - - public event EventHandler RootDocumentChanged; - - #endregion } } diff --git a/source/Components/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentPane.cs b/source/Components/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentPane.cs index 29f0aa9a..413c7690 100644 --- a/source/Components/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentPane.cs +++ b/source/Components/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentPane.cs @@ -18,6 +18,7 @@ This program is provided to you under the terms of the Microsoft Public using System.Collections.Generic; using System.Linq; using System.Windows.Markup; +using System.Xml.Serialization; namespace Xceed.Wpf.AvalonDock.Layout { @@ -109,19 +110,6 @@ public LayoutContent SelectedContent #endregion - #region ChildrenSorted - - public IEnumerable ChildrenSorted - { - get - { - var listSorted = this.Children.ToList(); - listSorted.Sort(); - return listSorted; - } - } - - #endregion #endregion @@ -150,41 +138,49 @@ protected override void ChildMoved( int oldIndex, int newIndex ) protected override void OnChildrenCollectionChanged() { - if( this.SelectedContentIndex >= this.ChildrenCount ) - this.SelectedContentIndex = this.Children.Count - 1; - if( this.SelectedContentIndex == -1 ) - { - if( this.ChildrenCount > 0 ) - { - if( this.Root == null ) - { - this.SetNextSelectedIndex(); - } - else - { - var childrenToSelect = this.Children.OrderByDescending( c => c.LastActivationTimeStamp.GetValueOrDefault() ).First(); - this.SelectedContentIndex = this.Children.IndexOf( childrenToSelect ); - childrenToSelect.IsActive = true; - } - } - else - { - if( this.Root != null ) - { - this.Root.ActiveContent = null; - } - } - } - - base.OnChildrenCollectionChanged(); + AutoFixSelectedContent(); + for (int i = 0; i < Children.Count; i++) + { + if (Children[i].IsSelected) + { + SelectedContentIndex = i; + break; + } + } + + RaisePropertyChanged("CanClose"); + RaisePropertyChanged("CanHide"); + RaisePropertyChanged("IsDirectlyHostedInFloatingWindow"); + base.OnChildrenCollectionChanged(); RaisePropertyChanged( "ChildrenSorted" ); } - protected override void OnIsVisibleChanged() + [XmlIgnore] + bool _autoFixSelectedContent = true; + void AutoFixSelectedContent() + { + if (_autoFixSelectedContent) + { + if (SelectedContentIndex >= ChildrenCount) + SelectedContentIndex = Children.Count - 1; + + if (SelectedContentIndex == -1 && ChildrenCount > 0) + SetNextSelectedIndex(); + } + } + + public bool IsDirectlyHostedInFloatingWindow { - this.UpdateParentVisibility(); - base.OnIsVisibleChanged(); + get + { + var parentFloatingWindow = this.FindParent(); + if (parentFloatingWindow != null) + return parentFloatingWindow.IsSinglePane; + + return false; + //return Parent != null && Parent.ChildrenCount == 1 && Parent.Parent is LayoutFloatingWindow; + } } public override void WriteXml( System.Xml.XmlWriter writer ) @@ -226,7 +222,11 @@ public override void ConsoleDump(int tab) public int IndexOf( LayoutContent content ) { - return Children.IndexOf( content ); + var documentChild = content as LayoutDocument; + if (documentChild == null) + return -1; + + return Children.IndexOf(documentChild); } #endregion @@ -250,11 +250,47 @@ internal void SetNextSelectedIndex() #region Private Methods - private void UpdateParentVisibility() + internal void UpdateIsDirectlyHostedInFloatingWindow() + { + RaisePropertyChanged("IsDirectlyHostedInFloatingWindow"); + } + + public bool IsHostedInFloatingWindow + { + get + { + return this.FindParent() != null; + } + } + + public IEnumerable ChildrenSorted + { + get + { + var listSorted = Children.ToList(); + listSorted.Sort(); + return listSorted; + } + } + + protected override void OnParentChanged(ILayoutContainer oldValue, ILayoutContainer newValue) + { + var oldGroup = oldValue as ILayoutGroup; + if (oldGroup != null) + oldGroup.ChildrenCollectionChanged -= new EventHandler(OnParentChildrenCollectionChanged); + + RaisePropertyChanged("IsDirectlyHostedInFloatingWindow"); + + var newGroup = newValue as ILayoutGroup; + if (newGroup != null) + newGroup.ChildrenCollectionChanged += new EventHandler(OnParentChildrenCollectionChanged); + + base.OnParentChanged(oldValue, newValue); + } + + void OnParentChildrenCollectionChanged(object sender, EventArgs e) { - var parentPane = this.Parent as ILayoutElementWithVisibility; - if( parentPane != null ) - parentPane.ComputeVisibility(); + RaisePropertyChanged("IsDirectlyHostedInFloatingWindow"); } #endregion diff --git a/source/Components/Xceed.Wpf.AvalonDock/Layout/LayoutRoot.cs b/source/Components/Xceed.Wpf.AvalonDock/Layout/LayoutRoot.cs index 88d74e86..7b70bfb4 100644 --- a/source/Components/Xceed.Wpf.AvalonDock/Layout/LayoutRoot.cs +++ b/source/Components/Xceed.Wpf.AvalonDock/Layout/LayoutRoot.cs @@ -480,6 +480,21 @@ public void CollectGarbage() exitFlag = false; break; } + foreach (var emptyPaneGroup in this.Descendents().OfType().Where(p => p.ChildrenCount == 0)) + { + var parentGroup = emptyPaneGroup.Parent as ILayoutContainer; + if (!(parentGroup.Parent is LayoutDocumentFloatingWindow)) continue; + var index = RootPanel.IndexOfChild(this.Descendents().OfType().First()); + parentGroup.RemoveChild(emptyPaneGroup); + if (!this.Descendents().OfType().Any()) + { + // Now the last Pane container is deleted, at least one is required for documents to be added. + // We did not want to keep an empty window floating, but add a new one to the main window + RootPanel.Children.Insert(index < 0 ? 0 : index, emptyPaneGroup); + } + exitFlag = false; + break; + } } if( !exitFlag ) diff --git a/source/Components/Xceed.Wpf.AvalonDock/Themes/generic.xaml b/source/Components/Xceed.Wpf.AvalonDock/Themes/generic.xaml index a747cfe8..bbb2b526 100644 --- a/source/Components/Xceed.Wpf.AvalonDock/Themes/generic.xaml +++ b/source/Components/Xceed.Wpf.AvalonDock/Themes/generic.xaml @@ -1028,12 +1028,17 @@ - - - - + @@ -1080,12 +1087,14 @@ Value="3" TargetName="WindowBorder" /> - + --> From b615b5ce12b5d6ecb4d7081db50a3428595bed8e Mon Sep 17 00:00:00 2001 From: amolf-se <56731291+amolf-se@users.noreply.github.com> Date: Tue, 29 Oct 2019 16:31:45 +0100 Subject: [PATCH 3/5] Fixed last floating document docking. --- .../Controls/LayoutFloatingWindowControl.cs | 1417 ++-- .../Xceed.Wpf.AvalonDock/DockingManager.cs | 6996 +++++++++-------- 2 files changed, 4214 insertions(+), 4199 deletions(-) diff --git a/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutFloatingWindowControl.cs b/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutFloatingWindowControl.cs index b2bb064c..bb0dbb71 100644 --- a/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutFloatingWindowControl.cs +++ b/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutFloatingWindowControl.cs @@ -12,8 +12,8 @@ This program is provided to you under the terms of the Microsoft Public Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - ***********************************************************************************/ - + ***********************************************************************************/ + using System; using System.ComponentModel; using System.Linq; @@ -29,711 +29,710 @@ This program is provided to you under the terms of the Microsoft Public using Xceed.Wpf.AvalonDock.Themes; namespace Xceed.Wpf.AvalonDock.Controls -{ - public abstract class LayoutFloatingWindowControl : Window, ILayoutControl - { - #region Members - - private ResourceDictionary currentThemeResourceDictionary; // = null - private bool _isInternalChange; //false - private ILayoutElement _model; - private bool _attachDrag = false; - private HwndSource _hwndSrc; - private HwndSourceHook _hwndSrcHook; - private DragService _dragService = null; - private bool _internalCloseFlag = false; - private bool _isClosing = false; - - #endregion - - #region Constructors - - static LayoutFloatingWindowControl() - { - LayoutFloatingWindowControl.ContentProperty.OverrideMetadata( typeof( LayoutFloatingWindowControl ), new FrameworkPropertyMetadata( null, null, new CoerceValueCallback( CoerceContentValue ) ) ); - AllowsTransparencyProperty.OverrideMetadata( typeof( LayoutFloatingWindowControl ), new FrameworkPropertyMetadata( false ) ); - ShowInTaskbarProperty.OverrideMetadata( typeof( LayoutFloatingWindowControl ), new FrameworkPropertyMetadata( false ) ); - } - - protected LayoutFloatingWindowControl( ILayoutElement model ) - { - this.Loaded += new RoutedEventHandler( OnLoaded ); - this.Unloaded += new RoutedEventHandler( OnUnloaded ); - Closing += OnClosing; - _model = model; - } - - protected LayoutFloatingWindowControl( ILayoutElement model, bool isContentImmutable ) - : this( model ) - { - this.IsContentImmutable = isContentImmutable; - } - - #endregion - - #region Properties - /// - /// Gets/Sets the X,Y delta between the elemnt being dragged and the - /// mouse position. The value of this property is used during the drag - /// cycle to position the dragged item under the mouse pointer. - /// - /// Set this property on intialization to ensure that - /// the delta between mouse and control being dragged - /// remains constant. - /// - internal Point DragDelta { get; set; } - - #region Model - - public abstract ILayoutElement Model - { - get; - } - - #endregion - - #region IsContentImmutable - - /// - /// IsContentImmutable Dependency Property - /// - public static readonly DependencyProperty IsContentImmutableProperty = DependencyProperty.Register( "IsContentImmutable", typeof( bool ), typeof( LayoutFloatingWindowControl ), - new FrameworkPropertyMetadata( (bool)false ) ); - - /// - /// Gets/sets the IsContentImmutable property. This dependency property - /// indicates if the content can be modified. - /// - public bool IsContentImmutable - { - get - { - return (bool)GetValue( IsContentImmutableProperty ); - } - private set - { - SetValue( IsContentImmutableProperty, value ); - } - } - - #endregion - - #region IsDragging - - /// - /// IsDragging Read-Only Dependency Property - /// - private static readonly DependencyPropertyKey IsDraggingPropertyKey = DependencyProperty.RegisterReadOnly( "IsDragging", typeof( bool ), typeof( LayoutFloatingWindowControl ), - new FrameworkPropertyMetadata( ( bool )false, new PropertyChangedCallback( OnIsDraggingChanged ) ) ); - - public static readonly DependencyProperty IsDraggingProperty = IsDraggingPropertyKey.DependencyProperty; - - /// - /// Gets the IsDragging property. This dependency property - /// indicates that this floating window is being dragged. - /// - public bool IsDragging - { - get - { - return ( bool )GetValue( IsDraggingProperty ); - } - } - - /// - /// Provides a secure method for setting the IsDragging property. - /// This dependency property indicates that this floating window is being dragged. - /// - /// The new value for the property. - protected void SetIsDragging( bool value ) - { - SetValue( IsDraggingPropertyKey, value ); - } - - /// - /// Handles changes to the IsDragging property. - /// - private static void OnIsDraggingChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( LayoutFloatingWindowControl )d ).OnIsDraggingChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the IsDragging property. - /// - protected virtual void OnIsDraggingChanged( DependencyPropertyChangedEventArgs e ) - { - if( ( bool )e.NewValue ) - { - CaptureMouse(); - } - else - { - ReleaseMouseCapture(); - } - } - - #endregion - - #region CloseInitiatedByUser - - protected bool CloseInitiatedByUser - { - get - { - return !_internalCloseFlag; - } - } - - #endregion - - #region KeepContentVisibleOnClose - - internal bool KeepContentVisibleOnClose - { - get; - set; - } - - #endregion - - #region IsMaximized - - /// - /// IsMaximized Dependency Property - /// - public static readonly DependencyProperty IsMaximizedProperty = DependencyProperty.Register( "IsMaximized", typeof( bool ), typeof( LayoutFloatingWindowControl ), - new FrameworkPropertyMetadata( ( bool )false ) ); - - /// - /// Gets/sets the IsMaximized property. This dependency property - /// indicates if the window is maximized. - /// - public bool IsMaximized - { - get - { - return ( bool )GetValue( IsMaximizedProperty ); - } - private set - { - SetValue( IsMaximizedProperty, value ); - UpdatePositionAndSizeOfPanes(); - } - } - - /// - /// Provides a secure method for setting the IsMaximized property. - /// This dependency property indicates if the window is maximized. - /// - /// The new value for the property. - - protected override void OnStateChanged( EventArgs e ) - { - if( !_isInternalChange ) - { - if( WindowState == WindowState.Maximized ) - { - UpdateMaximizedState( true ); - } - else - { - WindowState = IsMaximized ? WindowState.Maximized : WindowState.Normal; - } - } - - base.OnStateChanged( e ); - } - - #endregion - - #endregion - - #region Overrides - - protected override void OnClosed( EventArgs e ) - { - if( Content != null ) - { - var host = Content as FloatingWindowContentHost; - host.Dispose(); - - if( _hwndSrc != null ) - { - _hwndSrc.RemoveHook( _hwndSrcHook ); - _hwndSrc.Dispose(); - _hwndSrc = null; - } - } - - base.OnClosed( e ); - } - - protected override void OnInitialized( EventArgs e ) - { - CommandBindings.Add( new CommandBinding( Microsoft.Windows.Shell.SystemCommands.CloseWindowCommand, - new ExecutedRoutedEventHandler( ( s, args ) => Microsoft.Windows.Shell.SystemCommands.CloseWindow( ( Window )args.Parameter ) ) ) ); - CommandBindings.Add( new CommandBinding( Microsoft.Windows.Shell.SystemCommands.MaximizeWindowCommand, - new ExecutedRoutedEventHandler( ( s, args ) => Microsoft.Windows.Shell.SystemCommands.MaximizeWindow( ( Window )args.Parameter ) ) ) ); - CommandBindings.Add( new CommandBinding( Microsoft.Windows.Shell.SystemCommands.MinimizeWindowCommand, - new ExecutedRoutedEventHandler( ( s, args ) => Microsoft.Windows.Shell.SystemCommands.MinimizeWindow( ( Window )args.Parameter ) ) ) ); - CommandBindings.Add( new CommandBinding( Microsoft.Windows.Shell.SystemCommands.RestoreWindowCommand, - new ExecutedRoutedEventHandler( ( s, args ) => Microsoft.Windows.Shell.SystemCommands.RestoreWindow( ( Window )args.Parameter ) ) ) ); - //Debug.Assert(this.Owner != null); - base.OnInitialized( e ); - } - - - #endregion - - #region Internal Methods - - internal virtual void UpdateThemeResources( Theme oldTheme = null ) - { - if( oldTheme != null ) - { - if( oldTheme is DictionaryTheme ) - { - if( currentThemeResourceDictionary != null ) - { - Resources.MergedDictionaries.Remove( currentThemeResourceDictionary ); - currentThemeResourceDictionary = null; - } - } - else - { - var resourceDictionaryToRemove = - Resources.MergedDictionaries.FirstOrDefault( r => r.Source == oldTheme.GetResourceUri() ); - if( resourceDictionaryToRemove != null ) - Resources.MergedDictionaries.Remove( - resourceDictionaryToRemove ); - } - } - - var manager = _model.Root?.Manager; - if( manager?.Theme != null ) - { - if( manager.Theme is DictionaryTheme ) - { - currentThemeResourceDictionary = ( ( DictionaryTheme )manager.Theme ).ThemeResourceDictionary; - Resources.MergedDictionaries.Add( currentThemeResourceDictionary ); - } - else - { - Resources.MergedDictionaries.Add( new ResourceDictionary() { Source = manager.Theme.GetResourceUri() } ); - } - } - } - - internal void AttachDrag( bool onActivated = true ) - { - if( onActivated ) - { - _attachDrag = true; - this.Activated += new EventHandler( OnActivated ); - } - else - { - IntPtr windowHandle = new WindowInteropHelper( this ).Handle; - IntPtr lParam = new IntPtr( ( ( int )Left & ( int )0xFFFF ) | ( ( ( int )Top ) << 16 ) ); - Win32Helper.SendMessage( windowHandle, Win32Helper.WM_NCLBUTTONDOWN, new IntPtr( Win32Helper.HT_CAPTION ), lParam ); - } - } - - protected virtual IntPtr FilterMessage( IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled ) - { - handled = false; - - switch( msg ) - { - case Win32Helper.WM_ACTIVATE: - if( ( (int)wParam & 0xFFFF ) == Win32Helper.WA_INACTIVE ) - { - if( lParam == this.GetParentWindowHandle() ) - { - Win32Helper.SetActiveWindow( _hwndSrc.Handle ); - handled = true; - } - } - break; - case Win32Helper.WM_EXITSIZEMOVE: - UpdatePositionAndSizeOfPanes(); - - if( _dragService != null ) - { - bool dropFlag; - var mousePosition = this.TransformToDeviceDPI( Win32Helper.GetMousePosition() ); - _dragService.Drop( mousePosition, out dropFlag ); - _dragService = null; - SetIsDragging( false ); - - if( dropFlag ) - InternalClose(); - } - - break; - case Win32Helper.WM_MOVING: - { - UpdateDragPosition(); - if( this.IsMaximized ) - { - this.UpdateMaximizedState( false ); - } - } - break; - case Win32Helper.WM_LBUTTONUP: //set as handled right button click on title area (after showing context menu) - if( _dragService != null && Mouse.LeftButton == MouseButtonState.Released ) - { - _dragService.Abort(); - _dragService = null; - SetIsDragging( false ); - } - break; - case Win32Helper.WM_SYSCOMMAND: - int command = (int)wParam & 0xFFF0; - if( command == Win32Helper.SC_MAXIMIZE || command == Win32Helper.SC_RESTORE ) - { - UpdateMaximizedState( command == Win32Helper.SC_MAXIMIZE ); - } - break; - } - - - - return IntPtr.Zero; - } - - internal void InternalClose(bool closeInitiatedByUser = false) - { - _internalCloseFlag = !closeInitiatedByUser; - if( !_isClosing ) - { - _isClosing = true; - this.Close(); - } - } - - #endregion - - #region Private Methods - - private static object CoerceContentValue( DependencyObject sender, object content ) - { - var lfwc = sender as LayoutFloatingWindowControl; - if( lfwc != null ) - { - if( lfwc.IsLoaded && lfwc.IsContentImmutable ) - return lfwc.Content; - return new FloatingWindowContentHost( sender as LayoutFloatingWindowControl ) { Content = content as UIElement }; - } - return null; - } - - private void OnLoaded( object sender, RoutedEventArgs e ) - { - this.Loaded -= new RoutedEventHandler( OnLoaded ); - - this.SetParentToMainWindowOf( Model.Root.Manager ); - - _hwndSrc = HwndSource.FromDependencyObject( this ) as HwndSource; - _hwndSrcHook = new HwndSourceHook( FilterMessage ); - _hwndSrc.AddHook( _hwndSrcHook ); - - // Restore maximize state - var maximized = Model.Descendents().OfType().Any( l => l.IsMaximized ); - UpdateMaximizedState( maximized ); - } - - private void OnUnloaded( object sender, RoutedEventArgs e ) - { - this.Unloaded -= new RoutedEventHandler( OnUnloaded ); - - if( _hwndSrc != null ) - { - _hwndSrc.RemoveHook( _hwndSrcHook ); - InternalClose(); - } - } - - private void OnClosing(object sender, CancelEventArgs e) - { - Closing -= OnClosing; - - // If this window was Closed not from InternalClose method, - // mark it as closing to avoid "InvalidOperationException: : Cannot set Visibility to Visible or call Show, ShowDialog, - // Close, or WindowInteropHelper.EnsureHandle while a Window is closing". - if (!_isClosing) - { - _isClosing = true; - } - } - - private void OnActivated( object sender, EventArgs e ) - { - this.Activated -= new EventHandler( OnActivated ); - - if( _attachDrag && Mouse.LeftButton == MouseButtonState.Pressed ) - { - IntPtr windowHandle = new WindowInteropHelper( this ).Handle; - var mousePosition = this.PointToScreenDPI( Mouse.GetPosition( this ) ); - var clientArea = Win32Helper.GetClientRect( windowHandle ); - var windowArea = Win32Helper.GetWindowRect( windowHandle ); - - // BugFix Issue #6 - // This code is initializes the drag when content (document or toolwindow) is dragged - // A second chance back up plan if DragDelta is not set - if (DragDelta == default(Point)) - DragDelta = new Point(3, 3); - - Left = mousePosition.X - DragDelta.X; // BugFix Issue #6 - Top = mousePosition.Y - DragDelta.Y; - _attachDrag = false; - - IntPtr lParam = new IntPtr( ( ( int )mousePosition.X & ( int )0xFFFF ) | ( ( ( int )mousePosition.Y ) << 16 ) ); - Win32Helper.SendMessage( windowHandle, Win32Helper.WM_NCLBUTTONDOWN, new IntPtr( Win32Helper.HT_CAPTION ), lParam ); - } - } - - private void UpdatePositionAndSizeOfPanes() - { - foreach( var posElement in Model.Descendents().OfType() ) - { - posElement.FloatingLeft = Left; - posElement.FloatingTop = Top; - posElement.FloatingWidth = Width; - posElement.FloatingHeight = Height; - } - } - - private void UpdateMaximizedState( bool isMaximized ) - { - foreach( var posElement in Model.Descendents().OfType() ) - { - posElement.IsMaximized = isMaximized; - } - IsMaximized = isMaximized; - _isInternalChange = true; - WindowState = isMaximized ? WindowState.Maximized : WindowState.Normal; - _isInternalChange = false; - } - - private void UpdateDragPosition() - { - if( _dragService == null ) - { - _dragService = new DragService( this ); - SetIsDragging( true ); - } - - var mousePosition = this.TransformToDeviceDPI( Win32Helper.GetMousePosition() ); - _dragService.UpdateMouseLocation( mousePosition ); - } - - #endregion - - public virtual void EnableBindings() - { - } - - public virtual void DisableBindings() - { - } - - #region Internal Classes - - protected internal class FloatingWindowContentHost : HwndHost - { - #region Members - - private LayoutFloatingWindowControl _owner; - private HwndSource _wpfContentHost = null; - private Border _rootPresenter = null; - private DockingManager _manager = null; - - #endregion - - #region Constructors - - public FloatingWindowContentHost( LayoutFloatingWindowControl owner ) - { - _owner = owner; - var manager = _owner.Model.Root.Manager; - - var binding = new Binding( "SizeToContent" ) { Source = _owner }; - BindingOperations.SetBinding( this, FloatingWindowContentHost.SizeToContentProperty, binding ); - } - - #endregion - - #region Properties - - #region RootVisual - - public Visual RootVisual - { - get - { - return _rootPresenter; - } - } - - #endregion - - #region Content - - /// - /// Content Dependency Property - /// - public static readonly DependencyProperty ContentProperty = DependencyProperty.Register( "Content", typeof( UIElement ), typeof( FloatingWindowContentHost ), - new FrameworkPropertyMetadata( ( UIElement )null, new PropertyChangedCallback( OnContentChanged ) ) ); - - /// - /// Gets or sets the Content property. This dependency property - /// indicates .... - /// - public UIElement Content - { - get - { - return ( UIElement )GetValue( ContentProperty ); - } - set - { - SetValue( ContentProperty, value ); - } - } - - /// - /// Handles changes to the Content property. - /// - private static void OnContentChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( FloatingWindowContentHost )d ).OnContentChanged( (UIElement)e.OldValue, (UIElement)e.NewValue ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the Content property. - /// - protected virtual void OnContentChanged( UIElement oldValue, UIElement newValue ) - { - if( _rootPresenter != null ) - _rootPresenter.Child = Content; - - var oldContent = oldValue as FrameworkElement; - if( oldContent != null ) - { - oldContent.SizeChanged -= this.Content_SizeChanged; - } - - var newContent = newValue as FrameworkElement; - if( newContent != null ) - { - newContent.SizeChanged += this.Content_SizeChanged; - } - } - - #endregion - - #region SizeToContent - - /// - /// SizeToContent Dependency Property - /// - public static readonly DependencyProperty SizeToContentProperty = DependencyProperty.Register( "SizeToContent", typeof( SizeToContent ), typeof( FloatingWindowContentHost ), - new FrameworkPropertyMetadata( SizeToContent.Manual, new PropertyChangedCallback( OnSizeToContentChanged ) ) ); - - /// - /// Gets or sets the SizeToContent property. - /// - public SizeToContent SizeToContent - { - get - { - return (SizeToContent)GetValue( SizeToContentProperty ); - } - set - { - SetValue( SizeToContentProperty, value ); - } - } - - /// - /// Handles changes to the SizeToContent property. - /// - private static void OnSizeToContentChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( (FloatingWindowContentHost)d ).OnSizeToContentChanged( (SizeToContent)e.OldValue, (SizeToContent)e.NewValue ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the SizeToContent property. - /// - protected virtual void OnSizeToContentChanged( SizeToContent oldValue, SizeToContent newValue ) - { - if( _wpfContentHost != null ) - { - _wpfContentHost.SizeToContent = newValue; - } - } - - #endregion - - #endregion - - #region Overrides - - protected override System.Runtime.InteropServices.HandleRef BuildWindowCore( System.Runtime.InteropServices.HandleRef hwndParent ) - { - _wpfContentHost = new HwndSource( new HwndSourceParameters() - { - ParentWindow = hwndParent.Handle, - WindowStyle = Win32Helper.WS_CHILD | Win32Helper.WS_VISIBLE | Win32Helper.WS_CLIPSIBLINGS | Win32Helper.WS_CLIPCHILDREN, - Width = 1, - Height = 1 - } ); - - _rootPresenter = new Border() { Child = new AdornerDecorator() { Child = Content }, Focusable = true }; - _rootPresenter.SetBinding( Border.BackgroundProperty, new Binding( "Background" ) { Source = _owner } ); - _wpfContentHost.RootVisual = _rootPresenter; - - _manager = _owner.Model.Root.Manager; - _manager.InternalAddLogicalChild( _rootPresenter ); - - return new HandleRef( this, _wpfContentHost.Handle ); - } - - protected override void DestroyWindowCore( HandleRef hwnd ) - { - _manager.InternalRemoveLogicalChild( _rootPresenter ); - if( _wpfContentHost != null ) - { - _wpfContentHost.Dispose(); - _wpfContentHost = null; - } - } - - protected override Size MeasureOverride( Size constraint ) - { - if( Content == null ) - return base.MeasureOverride( constraint ); - - Content.Measure( constraint ); - return Content.DesiredSize; - } - - #endregion - - #region Event Handlers - - private void Content_SizeChanged( object sender, SizeChangedEventArgs e ) - { - this.InvalidateMeasure(); - this.InvalidateArrange(); - } - - #endregion - } - - #endregion - } +{ + public abstract class LayoutFloatingWindowControl : Window, ILayoutControl + { + #region Members + + private ResourceDictionary currentThemeResourceDictionary; // = null + private bool _isInternalChange; //false + private ILayoutElement _model; + private bool _attachDrag = false; + private HwndSource _hwndSrc; + private HwndSourceHook _hwndSrcHook; + private DragService _dragService = null; + private bool _internalCloseFlag = false; + private bool _isClosing = false; + + #endregion + + #region Constructors + + static LayoutFloatingWindowControl() + { + LayoutFloatingWindowControl.ContentProperty.OverrideMetadata(typeof(LayoutFloatingWindowControl), new FrameworkPropertyMetadata(null, null, new CoerceValueCallback(CoerceContentValue))); + AllowsTransparencyProperty.OverrideMetadata(typeof(LayoutFloatingWindowControl), new FrameworkPropertyMetadata(false)); + ShowInTaskbarProperty.OverrideMetadata(typeof(LayoutFloatingWindowControl), new FrameworkPropertyMetadata(false)); + } + + protected LayoutFloatingWindowControl(ILayoutElement model) + { + this.Loaded += new RoutedEventHandler(OnLoaded); + this.Unloaded += new RoutedEventHandler(OnUnloaded); + Closing += OnClosing; + _model = model; + } + + protected LayoutFloatingWindowControl(ILayoutElement model, bool isContentImmutable) + : this(model) + { + this.IsContentImmutable = isContentImmutable; + } + + #endregion + + #region Properties + /// + /// Gets/Sets the X,Y delta between the elemnt being dragged and the + /// mouse position. The value of this property is used during the drag + /// cycle to position the dragged item under the mouse pointer. + /// + /// Set this property on intialization to ensure that + /// the delta between mouse and control being dragged + /// remains constant. + /// + internal Point DragDelta { get; set; } + + #region Model + + public abstract ILayoutElement Model + { + get; + } + + #endregion + + #region IsContentImmutable + + /// + /// IsContentImmutable Dependency Property + /// + public static readonly DependencyProperty IsContentImmutableProperty = DependencyProperty.Register("IsContentImmutable", typeof(bool), typeof(LayoutFloatingWindowControl), + new FrameworkPropertyMetadata((bool)false)); + + /// + /// Gets/sets the IsContentImmutable property. This dependency property + /// indicates if the content can be modified. + /// + public bool IsContentImmutable + { + get + { + return (bool)GetValue(IsContentImmutableProperty); + } + private set + { + SetValue(IsContentImmutableProperty, value); + } + } + + #endregion + + #region IsDragging + + /// + /// IsDragging Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey IsDraggingPropertyKey = DependencyProperty.RegisterReadOnly("IsDragging", typeof(bool), typeof(LayoutFloatingWindowControl), + new FrameworkPropertyMetadata((bool)false, new PropertyChangedCallback(OnIsDraggingChanged))); + + public static readonly DependencyProperty IsDraggingProperty = IsDraggingPropertyKey.DependencyProperty; + + /// + /// Gets the IsDragging property. This dependency property + /// indicates that this floating window is being dragged. + /// + public bool IsDragging + { + get + { + return (bool)GetValue(IsDraggingProperty); + } + } + + /// + /// Provides a secure method for setting the IsDragging property. + /// This dependency property indicates that this floating window is being dragged. + /// + /// The new value for the property. + protected void SetIsDragging(bool value) + { + SetValue(IsDraggingPropertyKey, value); + } + + /// + /// Handles changes to the IsDragging property. + /// + private static void OnIsDraggingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutFloatingWindowControl)d).OnIsDraggingChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the IsDragging property. + /// + protected virtual void OnIsDraggingChanged(DependencyPropertyChangedEventArgs e) + { + if ((bool)e.NewValue) + { + CaptureMouse(); + } + else + { + ReleaseMouseCapture(); + } + } + + #endregion + + #region CloseInitiatedByUser + + protected bool CloseInitiatedByUser + { + get + { + return !_internalCloseFlag; + } + } + + #endregion + + #region KeepContentVisibleOnClose + + internal bool KeepContentVisibleOnClose + { + get; + set; + } + + #endregion + + #region IsMaximized + + /// + /// IsMaximized Dependency Property + /// + public static readonly DependencyProperty IsMaximizedProperty = DependencyProperty.Register("IsMaximized", typeof(bool), typeof(LayoutFloatingWindowControl), + new FrameworkPropertyMetadata((bool)false)); + + /// + /// Gets/sets the IsMaximized property. This dependency property + /// indicates if the window is maximized. + /// + public bool IsMaximized + { + get + { + return (bool)GetValue(IsMaximizedProperty); + } + private set + { + SetValue(IsMaximizedProperty, value); + UpdatePositionAndSizeOfPanes(); + } + } + + /// + /// Provides a secure method for setting the IsMaximized property. + /// This dependency property indicates if the window is maximized. + /// + /// The new value for the property. + + protected override void OnStateChanged(EventArgs e) + { + if (!_isInternalChange) + { + if (WindowState == WindowState.Maximized) + { + UpdateMaximizedState(true); + } + else + { + WindowState = IsMaximized ? WindowState.Maximized : WindowState.Normal; + } + } + + base.OnStateChanged(e); + } + + #endregion + + #endregion + + #region Overrides + + protected override void OnClosed(EventArgs e) + { + if (Content != null) + { + var host = Content as FloatingWindowContentHost; + host.Dispose(); + + if (_hwndSrc != null) + { + _hwndSrc.RemoveHook(_hwndSrcHook); + _hwndSrc.Dispose(); + _hwndSrc = null; + } + } + + base.OnClosed(e); + } + + protected override void OnInitialized(EventArgs e) + { + CommandBindings.Add(new CommandBinding(Microsoft.Windows.Shell.SystemCommands.CloseWindowCommand, + new ExecutedRoutedEventHandler((s, args) => Microsoft.Windows.Shell.SystemCommands.CloseWindow((Window)args.Parameter)))); + CommandBindings.Add(new CommandBinding(Microsoft.Windows.Shell.SystemCommands.MaximizeWindowCommand, + new ExecutedRoutedEventHandler((s, args) => Microsoft.Windows.Shell.SystemCommands.MaximizeWindow((Window)args.Parameter)))); + CommandBindings.Add(new CommandBinding(Microsoft.Windows.Shell.SystemCommands.MinimizeWindowCommand, + new ExecutedRoutedEventHandler((s, args) => Microsoft.Windows.Shell.SystemCommands.MinimizeWindow((Window)args.Parameter)))); + CommandBindings.Add(new CommandBinding(Microsoft.Windows.Shell.SystemCommands.RestoreWindowCommand, + new ExecutedRoutedEventHandler((s, args) => Microsoft.Windows.Shell.SystemCommands.RestoreWindow((Window)args.Parameter)))); + //Debug.Assert(this.Owner != null); + base.OnInitialized(e); + } + + + #endregion + + #region Internal Methods + + internal virtual void UpdateThemeResources(Theme oldTheme = null) + { + if (oldTheme != null) + { + if (oldTheme is DictionaryTheme) + { + if (currentThemeResourceDictionary != null) + { + Resources.MergedDictionaries.Remove(currentThemeResourceDictionary); + currentThemeResourceDictionary = null; + } + } + else + { + var resourceDictionaryToRemove = + Resources.MergedDictionaries.FirstOrDefault(r => r.Source == oldTheme.GetResourceUri()); + if (resourceDictionaryToRemove != null) + Resources.MergedDictionaries.Remove( + resourceDictionaryToRemove); + } + } + + var manager = _model.Root?.Manager; + if (manager?.Theme != null) + { + if (manager.Theme is DictionaryTheme) + { + currentThemeResourceDictionary = ((DictionaryTheme)manager.Theme).ThemeResourceDictionary; + Resources.MergedDictionaries.Add(currentThemeResourceDictionary); + } + else + { + Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = manager.Theme.GetResourceUri() }); + } + } + } + + internal void AttachDrag(bool onActivated = true) + { + if (onActivated) + { + _attachDrag = true; + this.Activated += new EventHandler(OnActivated); + } + else + { + IntPtr windowHandle = new WindowInteropHelper(this).Handle; + IntPtr lParam = new IntPtr(((int)Left & (int)0xFFFF) | (((int)Top) << 16)); + Win32Helper.SendMessage(windowHandle, Win32Helper.WM_NCLBUTTONDOWN, new IntPtr(Win32Helper.HT_CAPTION), lParam); + } + } + + protected virtual IntPtr FilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + handled = false; + + switch (msg) + { + case Win32Helper.WM_ACTIVATE: + if (((int)wParam & 0xFFFF) == Win32Helper.WA_INACTIVE) + { + if (lParam == this.GetParentWindowHandle()) + { + Win32Helper.SetActiveWindow(_hwndSrc.Handle); + handled = true; + } + } + break; + case Win32Helper.WM_EXITSIZEMOVE: + UpdatePositionAndSizeOfPanes(); + + if (_dragService != null) + { + bool dropFlag; + var mousePosition = this.TransformToDeviceDPI(Win32Helper.GetMousePosition()); + _dragService.Drop(mousePosition, out dropFlag); + _dragService = null; + SetIsDragging(false); + + if (dropFlag) + InternalClose(); + } + + break; + case Win32Helper.WM_MOVING: + { + UpdateDragPosition(); + if (this.IsMaximized) + { + this.UpdateMaximizedState(false); + } + } + break; + case Win32Helper.WM_LBUTTONUP: //set as handled right button click on title area (after showing context menu) + if (_dragService != null && Mouse.LeftButton == MouseButtonState.Released) + { + _dragService.Abort(); + _dragService = null; + SetIsDragging(false); + } + break; + case Win32Helper.WM_SYSCOMMAND: + int command = (int)wParam & 0xFFF0; + if (command == Win32Helper.SC_MAXIMIZE || command == Win32Helper.SC_RESTORE) + { + UpdateMaximizedState(command == Win32Helper.SC_MAXIMIZE); + } + break; + } + + + + return IntPtr.Zero; + } + + internal void InternalClose(bool closeInitiatedByUser = false) + { + _internalCloseFlag = !closeInitiatedByUser; + if (!_isClosing) + { + _isClosing = true; + this.Close(); + } + } + + #endregion + + #region Private Methods + + private static object CoerceContentValue(DependencyObject sender, object content) + { + var lfwc = sender as LayoutFloatingWindowControl; + if (lfwc != null) + { + if (lfwc.IsLoaded && lfwc.IsContentImmutable) + return lfwc.Content; + return new FloatingWindowContentHost(sender as LayoutFloatingWindowControl) { Content = content as UIElement }; + } + return null; + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + this.Loaded -= new RoutedEventHandler(OnLoaded); + + this.SetParentToMainWindowOf(Model.Root.Manager); + + _hwndSrc = HwndSource.FromDependencyObject(this) as HwndSource; + _hwndSrcHook = new HwndSourceHook(FilterMessage); + _hwndSrc.AddHook(_hwndSrcHook); + + // Restore maximize state + var maximized = Model.Descendents().OfType().Any(l => l.IsMaximized); + UpdateMaximizedState(maximized); + } + + private void OnUnloaded(object sender, RoutedEventArgs e) + { + this.Unloaded -= new RoutedEventHandler(OnUnloaded); + + if (_hwndSrc != null) + { + _hwndSrc.RemoveHook(_hwndSrcHook); + InternalClose(); + } + } + + private void OnClosing(object sender, CancelEventArgs e) + { + Closing -= OnClosing; + + // If this window was Closed not from InternalClose method, + // mark it as closing to avoid "InvalidOperationException: : Cannot set Visibility to Visible or call Show, ShowDialog, + // Close, or WindowInteropHelper.EnsureHandle while a Window is closing". + if (!_isClosing) + { + _isClosing = true; + } + } + + private void OnActivated(object sender, EventArgs e) + { + this.Activated -= new EventHandler(OnActivated); + + if (_attachDrag && Mouse.LeftButton == MouseButtonState.Pressed) + { + IntPtr windowHandle = new WindowInteropHelper(this).Handle; + + var mousePosition = this.PointToScreenDPI(Mouse.GetPosition(this)); + + // BugFix Issue #6 + // This code is initializes the drag when content (document or toolwindow) is dragged + // A second chance back up plan if DragDelta is not set + if (DragDelta == default(Point)) + DragDelta = new Point(3, 3); + + Left = mousePosition.X - DragDelta.X; // BugFix Issue #6 + Top = mousePosition.Y - DragDelta.Y; + _attachDrag = false; + + IntPtr lParam = new IntPtr(((int)mousePosition.X & (int)0xFFFF) | (((int)mousePosition.Y) << 16)); + Win32Helper.SendMessage(windowHandle, Win32Helper.WM_NCLBUTTONDOWN, new IntPtr(Win32Helper.HT_CAPTION), lParam); + } + } + + private void UpdatePositionAndSizeOfPanes() + { + foreach (var posElement in Model.Descendents().OfType()) + { + posElement.FloatingLeft = Left; + posElement.FloatingTop = Top; + posElement.FloatingWidth = Width; + posElement.FloatingHeight = Height; + } + } + + private void UpdateMaximizedState(bool isMaximized) + { + foreach (var posElement in Model.Descendents().OfType()) + { + posElement.IsMaximized = isMaximized; + } + IsMaximized = isMaximized; + _isInternalChange = true; + WindowState = isMaximized ? WindowState.Maximized : WindowState.Normal; + _isInternalChange = false; + } + + private void UpdateDragPosition() + { + if (_dragService == null) + { + _dragService = new DragService(this); + SetIsDragging(true); + } + + var mousePosition = this.TransformToDeviceDPI(Win32Helper.GetMousePosition()); + _dragService.UpdateMouseLocation(mousePosition); + } + + #endregion + + public virtual void EnableBindings() + { + } + + public virtual void DisableBindings() + { + } + + #region Internal Classes + + protected internal class FloatingWindowContentHost : HwndHost + { + #region Members + + private LayoutFloatingWindowControl _owner; + private HwndSource _wpfContentHost = null; + private Border _rootPresenter = null; + private DockingManager _manager = null; + + #endregion + + #region Constructors + + public FloatingWindowContentHost(LayoutFloatingWindowControl owner) + { + _owner = owner; + var manager = _owner.Model.Root.Manager; + + var binding = new Binding("SizeToContent") { Source = _owner }; + BindingOperations.SetBinding(this, FloatingWindowContentHost.SizeToContentProperty, binding); + } + + #endregion + + #region Properties + + #region RootVisual + + public Visual RootVisual + { + get + { + return _rootPresenter; + } + } + + #endregion + + #region Content + + /// + /// Content Dependency Property + /// + public static readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(UIElement), typeof(FloatingWindowContentHost), + new FrameworkPropertyMetadata((UIElement)null, new PropertyChangedCallback(OnContentChanged))); + + /// + /// Gets or sets the Content property. This dependency property + /// indicates .... + /// + public UIElement Content + { + get + { + return (UIElement)GetValue(ContentProperty); + } + set + { + SetValue(ContentProperty, value); + } + } + + /// + /// Handles changes to the Content property. + /// + private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((FloatingWindowContentHost)d).OnContentChanged((UIElement)e.OldValue, (UIElement)e.NewValue); + } + + /// + /// Provides derived classes an opportunity to handle changes to the Content property. + /// + protected virtual void OnContentChanged(UIElement oldValue, UIElement newValue) + { + if (_rootPresenter != null) + _rootPresenter.Child = Content; + + var oldContent = oldValue as FrameworkElement; + if (oldContent != null) + { + oldContent.SizeChanged -= this.Content_SizeChanged; + } + + var newContent = newValue as FrameworkElement; + if (newContent != null) + { + newContent.SizeChanged += this.Content_SizeChanged; + } + } + + #endregion + + #region SizeToContent + + /// + /// SizeToContent Dependency Property + /// + public static readonly DependencyProperty SizeToContentProperty = DependencyProperty.Register("SizeToContent", typeof(SizeToContent), typeof(FloatingWindowContentHost), + new FrameworkPropertyMetadata(SizeToContent.Manual, new PropertyChangedCallback(OnSizeToContentChanged))); + + /// + /// Gets or sets the SizeToContent property. + /// + public SizeToContent SizeToContent + { + get + { + return (SizeToContent)GetValue(SizeToContentProperty); + } + set + { + SetValue(SizeToContentProperty, value); + } + } + + /// + /// Handles changes to the SizeToContent property. + /// + private static void OnSizeToContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((FloatingWindowContentHost)d).OnSizeToContentChanged((SizeToContent)e.OldValue, (SizeToContent)e.NewValue); + } + + /// + /// Provides derived classes an opportunity to handle changes to the SizeToContent property. + /// + protected virtual void OnSizeToContentChanged(SizeToContent oldValue, SizeToContent newValue) + { + if (_wpfContentHost != null) + { + _wpfContentHost.SizeToContent = newValue; + } + } + + #endregion + + #endregion + + #region Overrides + + protected override System.Runtime.InteropServices.HandleRef BuildWindowCore(System.Runtime.InteropServices.HandleRef hwndParent) + { + _wpfContentHost = new HwndSource(new HwndSourceParameters() + { + ParentWindow = hwndParent.Handle, + WindowStyle = Win32Helper.WS_CHILD | Win32Helper.WS_VISIBLE | Win32Helper.WS_CLIPSIBLINGS | Win32Helper.WS_CLIPCHILDREN, + Width = 1, + Height = 1 + }); + + _rootPresenter = new Border() { Child = new AdornerDecorator() { Child = Content }, Focusable = true }; + _rootPresenter.SetBinding(Border.BackgroundProperty, new Binding("Background") { Source = _owner }); + _wpfContentHost.RootVisual = _rootPresenter; + + _manager = _owner.Model.Root.Manager; + _manager.InternalAddLogicalChild(_rootPresenter); + + return new HandleRef(this, _wpfContentHost.Handle); + } + + protected override void DestroyWindowCore(HandleRef hwnd) + { + _manager.InternalRemoveLogicalChild(_rootPresenter); + if (_wpfContentHost != null) + { + _wpfContentHost.Dispose(); + _wpfContentHost = null; + } + } + + protected override Size MeasureOverride(Size constraint) + { + if (Content == null) + return base.MeasureOverride(constraint); + + Content.Measure(constraint); + return Content.DesiredSize; + } + + #endregion + + #region Event Handlers + + private void Content_SizeChanged(object sender, SizeChangedEventArgs e) + { + this.InvalidateMeasure(); + this.InvalidateArrange(); + } + + #endregion + } + + #endregion + } } diff --git a/source/Components/Xceed.Wpf.AvalonDock/DockingManager.cs b/source/Components/Xceed.Wpf.AvalonDock/DockingManager.cs index 468f8d93..ac3c0bb7 100644 --- a/source/Components/Xceed.Wpf.AvalonDock/DockingManager.cs +++ b/source/Components/Xceed.Wpf.AvalonDock/DockingManager.cs @@ -12,8 +12,8 @@ This program is provided to you under the terms of the Microsoft Public Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - ***********************************************************************************/ - + ***********************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; @@ -33,3498 +33,3514 @@ This program is provided to you under the terms of the Microsoft Public using System.Diagnostics; namespace Xceed.Wpf.AvalonDock -{ - [ContentProperty( "Layout" )] - [TemplatePart( Name = "PART_AutoHideArea" )] - public class DockingManager : Control, IOverlayWindowHost//, ILogicalChildrenContainer - { - #region Members - - private ResourceDictionary currentThemeResourceDictionary; // = null - private AutoHideWindowManager _autoHideWindowManager; - private FrameworkElement _autohideArea; - private List _fwList = new List(); - private List _fwHiddenList = new List(); - private OverlayWindow _overlayWindow = null; - private List _areas = null; - private bool _insideInternalSetActiveContent = false; - private List _layoutItems = new List(); - private bool _suspendLayoutItemCreation = false; - private DispatcherOperation _collectLayoutItemsOperations = null; - private NavigatorWindow _navigatorWindow = null; - - internal bool SuspendDocumentsSourceBinding = false; - internal bool SuspendAnchorablesSourceBinding = false; - - #endregion - - #region Constructors - - static DockingManager() - { - DefaultStyleKeyProperty.OverrideMetadata( typeof( DockingManager ), new FrameworkPropertyMetadata( typeof( DockingManager ) ) ); - FocusableProperty.OverrideMetadata( typeof( DockingManager ), new FrameworkPropertyMetadata( false ) ); - HwndSource.DefaultAcquireHwndFocusInMenuMode = false; - } - - - public DockingManager() - { - +{ + [ContentProperty("Layout")] + [TemplatePart(Name = "PART_AutoHideArea")] + public class DockingManager : Control, IOverlayWindowHost//, ILogicalChildrenContainer + { + #region Members + + private ResourceDictionary currentThemeResourceDictionary; // = null + private AutoHideWindowManager _autoHideWindowManager; + private FrameworkElement _autohideArea; + private List _fwList = new List(); + private List _fwHiddenList = new List(); + private OverlayWindow _overlayWindow = null; + private List _areas = null; + private bool _insideInternalSetActiveContent = false; + private List _layoutItems = new List(); + private bool _suspendLayoutItemCreation = false; + private DispatcherOperation _collectLayoutItemsOperations = null; + private NavigatorWindow _navigatorWindow = null; + + internal bool SuspendDocumentsSourceBinding = false; + internal bool SuspendAnchorablesSourceBinding = false; + + #endregion + + #region Constructors + + static DockingManager() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(DockingManager), new FrameworkPropertyMetadata(typeof(DockingManager))); + FocusableProperty.OverrideMetadata(typeof(DockingManager), new FrameworkPropertyMetadata(false)); + HwndSource.DefaultAcquireHwndFocusInMenuMode = false; + } + + + public DockingManager() + { + #if !VS2008 - Layout = new LayoutRoot() { RootPanel = new LayoutPanel( new LayoutDocumentPaneGroup( new LayoutDocumentPane() ) ) }; + Layout = new LayoutRoot() { RootPanel = new LayoutPanel(new LayoutDocumentPaneGroup(new LayoutDocumentPane())) }; #else this.SetCurrentValue( DockingManager.LayoutProperty, new LayoutRoot() { RootPanel = new LayoutPanel(new LayoutDocumentPaneGroup(new LayoutDocumentPane())) } ); #endif - this.Loaded += new RoutedEventHandler( DockingManager_Loaded ); - this.Unloaded += new RoutedEventHandler( DockingManager_Unloaded ); - } - - #endregion - - #region Properties - - #region Layout - - /// - /// Layout Dependency Property - /// - public static readonly DependencyProperty LayoutProperty = DependencyProperty.Register( "Layout", typeof( LayoutRoot ), typeof( DockingManager ), - new FrameworkPropertyMetadata( null, new PropertyChangedCallback( OnLayoutChanged ), new CoerceValueCallback( CoerceLayoutValue ) ) ); - - /// - /// Gets or sets the Layout property. This dependency property - /// indicates layout tree. - /// - public LayoutRoot Layout - { - get - { - return ( LayoutRoot )GetValue( LayoutProperty ); - } - set - { - SetValue( LayoutProperty, value ); - } - } - - /// - /// Coerces the value. - /// - private static object CoerceLayoutValue( DependencyObject d, object value ) - { - if( value == null ) - return new LayoutRoot() { RootPanel = new LayoutPanel( new LayoutDocumentPaneGroup( new LayoutDocumentPane() ) ) }; - - ( ( DockingManager )d ).OnLayoutChanging( value as LayoutRoot ); - - return value; - } - - /// - /// Handles changes to the Layout property. - /// - private static void OnLayoutChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnLayoutChanged( e.OldValue as LayoutRoot, e.NewValue as LayoutRoot ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the property. - /// - protected virtual void OnLayoutChanged( LayoutRoot oldLayout, LayoutRoot newLayout ) - { - if( oldLayout != null ) - { - oldLayout.PropertyChanged -= new PropertyChangedEventHandler( OnLayoutRootPropertyChanged ); - oldLayout.Updated -= new EventHandler( OnLayoutRootUpdated ); - } - - foreach( var fwc in _fwList.ToArray() ) - { - fwc.KeepContentVisibleOnClose = true; - fwc.InternalClose(); - } - - _fwList.Clear(); - - foreach (var fwc in _fwHiddenList.ToArray()) - { - fwc.InternalClose(); - } - - _fwHiddenList.Clear(); - - DetachDocumentsSource( oldLayout, DocumentsSource ); - DetachAnchorablesSource( oldLayout, AnchorablesSource ); - - if( oldLayout != null && - oldLayout.Manager == this ) - oldLayout.Manager = null; - - ClearLogicalChildrenList(); - DetachLayoutItems(); - - Layout.Manager = this; - - AttachLayoutItems(); - AttachDocumentsSource( newLayout, DocumentsSource ); - AttachAnchorablesSource( newLayout, AnchorablesSource ); - - if( IsLoaded ) - { - LayoutRootPanel = CreateUIElementForModel( Layout.RootPanel ) as LayoutPanelControl; - LeftSidePanel = CreateUIElementForModel( Layout.LeftSide ) as LayoutAnchorSideControl; - TopSidePanel = CreateUIElementForModel( Layout.TopSide ) as LayoutAnchorSideControl; - RightSidePanel = CreateUIElementForModel( Layout.RightSide ) as LayoutAnchorSideControl; - BottomSidePanel = CreateUIElementForModel( Layout.BottomSide ) as LayoutAnchorSideControl; - - foreach( var fw in Layout.FloatingWindows.ToArray() ) - { - if( fw.IsValid ) - _fwList.Add( CreateUIElementForModel( fw ) as LayoutFloatingWindowControl ); - } - - foreach( var fw in _fwList.ToArray()) - { - var window = fw.Model as LayoutAnchorableFloatingWindow; - if (window != null && window.RootPanel.IsMaximized) - { - fw.WindowState = WindowState.Normal; - fw.Show(); - fw.WindowState = WindowState.Maximized; - } - else - fw.Show(); - //fw.Owner = Window.GetWindow(this); - //fw.SetParentToMainWindowOf(this); - } - - // In order to prevent resource leaks, unsubscribe from SizeChanged event for case when user call loading of Layout Settigns. - SizeChanged -= OnSizeChanged; - SizeChanged += OnSizeChanged; - } - - if( newLayout != null ) - { - newLayout.PropertyChanged += new PropertyChangedEventHandler( OnLayoutRootPropertyChanged ); - newLayout.Updated += new EventHandler( OnLayoutRootUpdated ); - } - - if( LayoutChanged != null ) - LayoutChanged( this, EventArgs.Empty ); - - //if (Layout != null) - // Layout.CollectGarbage(); - - CommandManager.InvalidateRequerySuggested(); - } - - #endregion - - #region LayoutUpdateStrategy - - /// - /// LayoutUpdateStrategy Dependency Property - /// - public static readonly DependencyProperty LayoutUpdateStrategyProperty = DependencyProperty.Register( "LayoutUpdateStrategy", typeof( ILayoutUpdateStrategy ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( ILayoutUpdateStrategy )null ) ); - - /// - /// Gets or sets the LayoutUpdateStrategy property. This dependency property - /// indicates the strategy class to call when AvalonDock needs to positionate a LayoutAnchorable inside an existing layout. - /// - /// Sometimes it's impossible to automatically insert an anchorable in the layout without specifing the target parent pane. - /// Set this property to an object that will be asked to insert the anchorable to the desidered position. - public ILayoutUpdateStrategy LayoutUpdateStrategy - { - get - { - return ( ILayoutUpdateStrategy )GetValue( LayoutUpdateStrategyProperty ); - } - set - { - SetValue( LayoutUpdateStrategyProperty, value ); - } - } - - #endregion - - #region DocumentPaneTemplate - - /// - /// DocumentPaneTemplate Dependency Property - /// - public static readonly DependencyProperty DocumentPaneTemplateProperty = DependencyProperty.Register( "DocumentPaneTemplate", typeof( ControlTemplate ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( ControlTemplate )null, new PropertyChangedCallback( OnDocumentPaneTemplateChanged ) ) ); - - /// - /// Gets or sets the DocumentPaneDataTemplate property. This dependency property - /// indicates . - /// - public ControlTemplate DocumentPaneTemplate - { - get - { - return ( ControlTemplate )GetValue( DocumentPaneTemplateProperty ); - } - set - { - SetValue( DocumentPaneTemplateProperty, value ); - } - } - - /// - /// Handles changes to the DocumentPaneTemplate property. - /// - private static void OnDocumentPaneTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnDocumentPaneTemplateChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the DocumentPaneTemplate property. - /// - protected virtual void OnDocumentPaneTemplateChanged( DependencyPropertyChangedEventArgs e ) - { - } - - #endregion - - #region AnchorablePaneTemplate - - /// - /// AnchorablePaneTemplate Dependency Property - /// - public static readonly DependencyProperty AnchorablePaneTemplateProperty = DependencyProperty.Register( "AnchorablePaneTemplate", typeof( ControlTemplate ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( ControlTemplate )null, new PropertyChangedCallback( OnAnchorablePaneTemplateChanged ) ) ); - - /// - /// Gets or sets the AnchorablePaneTemplate property. This dependency property - /// indicates .... - /// - public ControlTemplate AnchorablePaneTemplate - { - get - { - return ( ControlTemplate )GetValue( AnchorablePaneTemplateProperty ); - } - set - { - SetValue( AnchorablePaneTemplateProperty, value ); - } - } - - /// - /// Handles changes to the AnchorablePaneDataTemplate property. - /// - private static void OnAnchorablePaneTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnAnchorablePaneTemplateChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the AnchorablePaneDataTemplate property. - /// - protected virtual void OnAnchorablePaneTemplateChanged( DependencyPropertyChangedEventArgs e ) - { - } - - #endregion - - #region AnchorSideTemplate - - /// - /// AnchorSideTemplate Dependency Property - /// - public static readonly DependencyProperty AnchorSideTemplateProperty = DependencyProperty.Register( "AnchorSideTemplate", typeof( ControlTemplate ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( ControlTemplate )null ) ); - - /// - /// Gets or sets the AnchorSideTemplate property. This dependency property - /// indicates .... - /// - public ControlTemplate AnchorSideTemplate - { - get - { - return ( ControlTemplate )GetValue( AnchorSideTemplateProperty ); - } - set - { - SetValue( AnchorSideTemplateProperty, value ); - } - } - - #endregion - - #region AnchorGroupTemplate - - /// - /// AnchorGroupTemplate Dependency Property - /// - public static readonly DependencyProperty AnchorGroupTemplateProperty = DependencyProperty.Register( "AnchorGroupTemplate", typeof( ControlTemplate ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( ControlTemplate )null ) ); - - /// - /// Gets or sets the AnchorGroupTemplate property. This dependency property - /// indicates the template used to render the AnchorGroup control. - /// - public ControlTemplate AnchorGroupTemplate - { - get - { - return ( ControlTemplate )GetValue( AnchorGroupTemplateProperty ); - } - set - { - SetValue( AnchorGroupTemplateProperty, value ); - } - } - - #endregion - - #region AnchorTemplate - - /// - /// AnchorTemplate Dependency Property - /// - public static readonly DependencyProperty AnchorTemplateProperty = DependencyProperty.Register( "AnchorTemplate", typeof( ControlTemplate ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( ControlTemplate )null ) ); - - /// - /// Gets or sets the AnchorTemplate property. This dependency property - /// indicates .... - /// - public ControlTemplate AnchorTemplate - { - get - { - return ( ControlTemplate )GetValue( AnchorTemplateProperty ); - } - set - { - SetValue( AnchorTemplateProperty, value ); - } - } - - #endregion - - #region DocumentPaneControlStyle - - /// - /// DocumentPaneControlStyle Dependency Property - /// - public static readonly DependencyProperty DocumentPaneControlStyleProperty = DependencyProperty.Register( "DocumentPaneControlStyle", typeof( Style ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( Style )null, new PropertyChangedCallback( OnDocumentPaneControlStyleChanged ) ) ); - - /// - /// Gets or sets the DocumentPaneControlStyle property. This dependency property - /// indicates .... - /// - public Style DocumentPaneControlStyle - { - get - { - return ( Style )GetValue( DocumentPaneControlStyleProperty ); - } - set - { - SetValue( DocumentPaneControlStyleProperty, value ); - } - } - - /// - /// Handles changes to the DocumentPaneControlStyle property. - /// - private static void OnDocumentPaneControlStyleChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnDocumentPaneControlStyleChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the DocumentPaneControlStyle property. - /// - protected virtual void OnDocumentPaneControlStyleChanged( DependencyPropertyChangedEventArgs e ) - { - } - - #endregion - - #region AnchorablePaneControlStyle - - /// - /// AnchorablePaneControlStyle Dependency Property - /// - public static readonly DependencyProperty AnchorablePaneControlStyleProperty = DependencyProperty.Register( "AnchorablePaneControlStyle", typeof( Style ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( Style )null, new PropertyChangedCallback( OnAnchorablePaneControlStyleChanged ) ) ); - - /// - /// Gets or sets the AnchorablePaneControlStyle property. This dependency property - /// indicates the style to apply to AnchorablePaneControl. - /// - public Style AnchorablePaneControlStyle - { - get - { - return ( Style )GetValue( AnchorablePaneControlStyleProperty ); - } - set - { - SetValue( AnchorablePaneControlStyleProperty, value ); - } - } - - /// - /// Handles changes to the AnchorablePaneControlStyle property. - /// - private static void OnAnchorablePaneControlStyleChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnAnchorablePaneControlStyleChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the AnchorablePaneControlStyle property. - /// - protected virtual void OnAnchorablePaneControlStyleChanged( DependencyPropertyChangedEventArgs e ) - { - } - - #endregion - - #region DocumentHeaderTemplate - - /// - /// DocumentHeaderTemplate Dependency Property - /// - public static readonly DependencyProperty DocumentHeaderTemplateProperty = DependencyProperty.Register( "DocumentHeaderTemplate", typeof( DataTemplate ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( DataTemplate )null, new PropertyChangedCallback( OnDocumentHeaderTemplateChanged ), new CoerceValueCallback( CoerceDocumentHeaderTemplateValue ) ) ); - - /// - /// Gets or sets the DocumentHeaderTemplate property. This dependency property - /// indicates data template to use for document header. - /// - public DataTemplate DocumentHeaderTemplate - { - get - { - return ( DataTemplate )GetValue( DocumentHeaderTemplateProperty ); - } - set - { - SetValue( DocumentHeaderTemplateProperty, value ); - } - } - - /// - /// Handles changes to the DocumentHeaderTemplate property. - /// - private static void OnDocumentHeaderTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnDocumentHeaderTemplateChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the DocumentHeaderTemplate property. - /// - protected virtual void OnDocumentHeaderTemplateChanged( DependencyPropertyChangedEventArgs e ) - { - } - - /// - /// Coerces the DocumentHeaderTemplate value. - /// - private static object CoerceDocumentHeaderTemplateValue( DependencyObject d, object value ) - { - if( value != null && - d.GetValue( DocumentHeaderTemplateSelectorProperty ) != null ) - return null; - return value; - } - - #endregion - - #region DocumentHeaderTemplateSelector - - /// - /// DocumentHeaderTemplateSelector Dependency Property - /// - public static readonly DependencyProperty DocumentHeaderTemplateSelectorProperty = DependencyProperty.Register( "DocumentHeaderTemplateSelector", typeof( DataTemplateSelector ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( DataTemplateSelector )null, new PropertyChangedCallback( OnDocumentHeaderTemplateSelectorChanged ), new CoerceValueCallback( CoerceDocumentHeaderTemplateSelectorValue ) ) ); - - /// - /// Gets or sets the DocumentHeaderTemplateSelector property. This dependency property - /// indicates the template selector that is used when selcting the data template for the header. - /// - public DataTemplateSelector DocumentHeaderTemplateSelector - { - get - { - return ( DataTemplateSelector )GetValue( DocumentHeaderTemplateSelectorProperty ); - } - set - { - SetValue( DocumentHeaderTemplateSelectorProperty, value ); - } - } - - /// - /// Handles changes to the DocumentHeaderTemplateSelector property. - /// - private static void OnDocumentHeaderTemplateSelectorChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnDocumentHeaderTemplateSelectorChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the DocumentHeaderTemplateSelector property. - /// - protected virtual void OnDocumentHeaderTemplateSelectorChanged( DependencyPropertyChangedEventArgs e ) - { - if( e.NewValue != null && - DocumentHeaderTemplate != null ) - DocumentHeaderTemplate = null; - - if( DocumentPaneMenuItemHeaderTemplateSelector == null ) - DocumentPaneMenuItemHeaderTemplateSelector = DocumentHeaderTemplateSelector; - - } - - /// - /// Coerces the DocumentHeaderTemplateSelector value. - /// - private static object CoerceDocumentHeaderTemplateSelectorValue( DependencyObject d, object value ) - { - return value; - } - - #endregion - - #region DocumentTitleTemplate - - /// - /// DocumentTitleTemplate Dependency Property - /// - public static readonly DependencyProperty DocumentTitleTemplateProperty = DependencyProperty.Register( "DocumentTitleTemplate", typeof( DataTemplate ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( DataTemplate )null, new PropertyChangedCallback( OnDocumentTitleTemplateChanged ), new CoerceValueCallback( CoerceDocumentTitleTemplateValue ) ) ); - - /// - /// Gets or sets the DocumentTitleTemplate property. This dependency property - /// indicates the datatemplate to use when creating the title for a document. - /// - public DataTemplate DocumentTitleTemplate - { - get - { - return ( DataTemplate )GetValue( DocumentTitleTemplateProperty ); - } - set - { - SetValue( DocumentTitleTemplateProperty, value ); - } - } - - /// - /// Handles changes to the DocumentTitleTemplate property. - /// - private static void OnDocumentTitleTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnDocumentTitleTemplateChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the DocumentTitleTemplate property. - /// - protected virtual void OnDocumentTitleTemplateChanged( DependencyPropertyChangedEventArgs e ) - { - } - - /// - /// Coerces the DocumentTitleTemplate value. - /// - private static object CoerceDocumentTitleTemplateValue( DependencyObject d, object value ) - { - if( value != null && - d.GetValue( DocumentTitleTemplateSelectorProperty ) != null ) - return null; - - return value; - } - - #endregion - - #region DocumentTitleTemplateSelector - - /// - /// DocumentTitleTemplateSelector Dependency Property - /// - public static readonly DependencyProperty DocumentTitleTemplateSelectorProperty = DependencyProperty.Register( "DocumentTitleTemplateSelector", typeof( DataTemplateSelector ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( DataTemplateSelector )null, new PropertyChangedCallback( OnDocumentTitleTemplateSelectorChanged ), new CoerceValueCallback( CoerceDocumentTitleTemplateSelectorValue ) ) ); - - /// - /// Gets or sets the DocumentTitleTemplateSelector property. This dependency property - /// indicates the data template selector to use when creating the data template for the title. - /// - public DataTemplateSelector DocumentTitleTemplateSelector - { - get - { - return ( DataTemplateSelector )GetValue( DocumentTitleTemplateSelectorProperty ); - } - set - { - SetValue( DocumentTitleTemplateSelectorProperty, value ); - } - } - - /// - /// Handles changes to the DocumentTitleTemplateSelector property. - /// - private static void OnDocumentTitleTemplateSelectorChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnDocumentTitleTemplateSelectorChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the DocumentTitleTemplateSelector property. - /// - protected virtual void OnDocumentTitleTemplateSelectorChanged( DependencyPropertyChangedEventArgs e ) - { - if( e.NewValue != null ) - DocumentTitleTemplate = null; - } - - /// - /// Coerces the DocumentTitleTemplateSelector value. - /// - private static object CoerceDocumentTitleTemplateSelectorValue( DependencyObject d, object value ) - { - return value; - } - - #endregion - - #region AnchorableTitleTemplate - - /// - /// AnchorableTitleTemplate Dependency Property - /// - public static readonly DependencyProperty AnchorableTitleTemplateProperty = DependencyProperty.Register( "AnchorableTitleTemplate", typeof( DataTemplate ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( DataTemplate )null, new PropertyChangedCallback( OnAnchorableTitleTemplateChanged ), new CoerceValueCallback( CoerceAnchorableTitleTemplateValue ) ) ); - - /// - /// Gets or sets the AnchorableTitleTemplate property. This dependency property - /// indicates the data template to use for anchorables title. - /// - public DataTemplate AnchorableTitleTemplate - { - get - { - return ( DataTemplate )GetValue( AnchorableTitleTemplateProperty ); - } - set - { - SetValue( AnchorableTitleTemplateProperty, value ); - } - } - - /// - /// Handles changes to the AnchorableTitleTemplate property. - /// - private static void OnAnchorableTitleTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnAnchorableTitleTemplateChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the AnchorableTitleTemplate property. - /// - protected virtual void OnAnchorableTitleTemplateChanged( DependencyPropertyChangedEventArgs e ) - { - } - - /// - /// Coerces the AnchorableTitleTemplate value. - /// - private static object CoerceAnchorableTitleTemplateValue( DependencyObject d, object value ) - { - if( value != null && - d.GetValue( AnchorableTitleTemplateSelectorProperty ) != null ) - return null; - return value; - } - - #endregion - - #region AnchorableTitleTemplateSelector - - /// - /// AnchorableTitleTemplateSelector Dependency Property - /// - public static readonly DependencyProperty AnchorableTitleTemplateSelectorProperty = DependencyProperty.Register( "AnchorableTitleTemplateSelector", typeof( DataTemplateSelector ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( DataTemplateSelector )null, new PropertyChangedCallback( OnAnchorableTitleTemplateSelectorChanged ) ) ); - - /// - /// Gets or sets the AnchorableTitleTemplateSelector property. This dependency property - /// indicates selctor to use when selecting data template for the title of anchorables. - /// - public DataTemplateSelector AnchorableTitleTemplateSelector - { - get - { - return ( DataTemplateSelector )GetValue( AnchorableTitleTemplateSelectorProperty ); - } - set - { - SetValue( AnchorableTitleTemplateSelectorProperty, value ); - } - } - - /// - /// Handles changes to the AnchorableTitleTemplateSelector property. - /// - private static void OnAnchorableTitleTemplateSelectorChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnAnchorableTitleTemplateSelectorChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the AnchorableTitleTemplateSelector property. - /// - protected virtual void OnAnchorableTitleTemplateSelectorChanged( DependencyPropertyChangedEventArgs e ) - { - if( e.NewValue != null && - AnchorableTitleTemplate != null ) - AnchorableTitleTemplate = null; - } - - #endregion - - #region AnchorableHeaderTemplate - - /// - /// AnchorableHeaderTemplate Dependency Property - /// - public static readonly DependencyProperty AnchorableHeaderTemplateProperty = DependencyProperty.Register( "AnchorableHeaderTemplate", typeof( DataTemplate ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( DataTemplate )null, new PropertyChangedCallback( OnAnchorableHeaderTemplateChanged ), new CoerceValueCallback( CoerceAnchorableHeaderTemplateValue ) ) ); - - /// - /// Gets or sets the AnchorableHeaderTemplate property. This dependency property - /// indicates the data template to use for anchorable templates. - /// - public DataTemplate AnchorableHeaderTemplate - { - get - { - return ( DataTemplate )GetValue( AnchorableHeaderTemplateProperty ); - } - set - { - SetValue( AnchorableHeaderTemplateProperty, value ); - } - } - - /// - /// Handles changes to the AnchorableHeaderTemplate property. - /// - private static void OnAnchorableHeaderTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnAnchorableHeaderTemplateChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the AnchorableHeaderTemplate property. - /// - protected virtual void OnAnchorableHeaderTemplateChanged( DependencyPropertyChangedEventArgs e ) - { - } - - /// - /// Coerces the AnchorableHeaderTemplate value. - /// - private static object CoerceAnchorableHeaderTemplateValue( DependencyObject d, object value ) - { - if( value != null && - d.GetValue( AnchorableHeaderTemplateSelectorProperty ) != null ) - return null; - - return value; - } - - #endregion - - #region AnchorableHeaderTemplateSelector - - /// - /// AnchorableHeaderTemplateSelector Dependency Property - /// - public static readonly DependencyProperty AnchorableHeaderTemplateSelectorProperty = DependencyProperty.Register( "AnchorableHeaderTemplateSelector", typeof( DataTemplateSelector ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( DataTemplateSelector )null, new PropertyChangedCallback( OnAnchorableHeaderTemplateSelectorChanged ) ) ); - - /// - /// Gets or sets the AnchorableHeaderTemplateSelector property. This dependency property - /// indicates the selector to use when selecting the data template for anchorable headers. - /// - public DataTemplateSelector AnchorableHeaderTemplateSelector - { - get - { - return ( DataTemplateSelector )GetValue( AnchorableHeaderTemplateSelectorProperty ); - } - set - { - SetValue( AnchorableHeaderTemplateSelectorProperty, value ); - } - } - - /// - /// Handles changes to the AnchorableHeaderTemplateSelector property. - /// - private static void OnAnchorableHeaderTemplateSelectorChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnAnchorableHeaderTemplateSelectorChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the AnchorableHeaderTemplateSelector property. - /// - protected virtual void OnAnchorableHeaderTemplateSelectorChanged( DependencyPropertyChangedEventArgs e ) - { - if( e.NewValue != null ) - AnchorableHeaderTemplate = null; - } - - #endregion - - #region LayoutRootPanel - - /// - /// LayoutRootPanel Dependency Property - /// - public static readonly DependencyProperty LayoutRootPanelProperty = DependencyProperty.Register( "LayoutRootPanel", typeof( LayoutPanelControl ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( LayoutPanelControl )null, new PropertyChangedCallback( OnLayoutRootPanelChanged ) ) ); - - /// - /// Gets or sets the LayoutRootPanel property. This dependency property - /// indicates the layout panel control which is attached to the Layout.Root property. - /// - public LayoutPanelControl LayoutRootPanel - { - get - { - return ( LayoutPanelControl )GetValue( LayoutRootPanelProperty ); - } - set - { - SetValue( LayoutRootPanelProperty, value ); - } - } - - /// - /// Handles changes to the LayoutRootPanel property. - /// - private static void OnLayoutRootPanelChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnLayoutRootPanelChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the LayoutRootPanel property. - /// - protected virtual void OnLayoutRootPanelChanged( DependencyPropertyChangedEventArgs e ) - { - if( e.OldValue != null ) - InternalRemoveLogicalChild( e.OldValue ); - if( e.NewValue != null ) - InternalAddLogicalChild( e.NewValue ); - } - - #endregion - - #region RightSidePanel - - /// - /// RightSidePanel Dependency Property - /// - public static readonly DependencyProperty RightSidePanelProperty = DependencyProperty.Register( "RightSidePanel", typeof( LayoutAnchorSideControl ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( LayoutAnchorSideControl )null, new PropertyChangedCallback( OnRightSidePanelChanged ) ) ); - - /// - /// Gets or sets the RightSidePanel property. This dependency property - /// indicates right side anchor panel. - /// - public LayoutAnchorSideControl RightSidePanel - { - get - { - return ( LayoutAnchorSideControl )GetValue( RightSidePanelProperty ); - } - set - { - SetValue( RightSidePanelProperty, value ); - } - } - - /// - /// Handles changes to the RightSidePanel property. - /// - private static void OnRightSidePanelChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnRightSidePanelChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the RightSidePanel property. - /// - protected virtual void OnRightSidePanelChanged( DependencyPropertyChangedEventArgs e ) - { - if( e.OldValue != null ) - InternalRemoveLogicalChild( e.OldValue ); - if( e.NewValue != null ) - InternalAddLogicalChild( e.NewValue ); - } - - #endregion - - #region LeftSidePanel - - /// - /// LeftSidePanel Dependency Property - /// - public static readonly DependencyProperty LeftSidePanelProperty = DependencyProperty.Register( "LeftSidePanel", typeof( LayoutAnchorSideControl ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( LayoutAnchorSideControl )null, new PropertyChangedCallback( OnLeftSidePanelChanged ) ) ); - - /// - /// Gets or sets the LeftSidePanel property. This dependency property - /// indicates the left side panel control. - /// - public LayoutAnchorSideControl LeftSidePanel - { - get - { - return ( LayoutAnchorSideControl )GetValue( LeftSidePanelProperty ); - } - set - { - SetValue( LeftSidePanelProperty, value ); - } - } - - /// - /// Handles changes to the LeftSidePanel property. - /// - private static void OnLeftSidePanelChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnLeftSidePanelChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the LeftSidePanel property. - /// - protected virtual void OnLeftSidePanelChanged( DependencyPropertyChangedEventArgs e ) - { - if( e.OldValue != null ) - InternalRemoveLogicalChild( e.OldValue ); - if( e.NewValue != null ) - InternalAddLogicalChild( e.NewValue ); - } - - #endregion - - #region TopSidePanel - - /// - /// TopSidePanel Dependency Property - /// - public static readonly DependencyProperty TopSidePanelProperty = DependencyProperty.Register( "TopSidePanel", typeof( LayoutAnchorSideControl ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( LayoutAnchorSideControl )null, new PropertyChangedCallback( OnTopSidePanelChanged ) ) ); - - /// - /// Gets or sets the TopSidePanel property. This dependency property - /// indicates top side control panel. - /// - public LayoutAnchorSideControl TopSidePanel - { - get - { - return ( LayoutAnchorSideControl )GetValue( TopSidePanelProperty ); - } - set - { - SetValue( TopSidePanelProperty, value ); - } - } - - /// - /// Handles changes to the TopSidePanel property. - /// - private static void OnTopSidePanelChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnTopSidePanelChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the TopSidePanel property. - /// - protected virtual void OnTopSidePanelChanged( DependencyPropertyChangedEventArgs e ) - { - if( e.OldValue != null ) - InternalRemoveLogicalChild( e.OldValue ); - if( e.NewValue != null ) - InternalAddLogicalChild( e.NewValue ); - } - - #endregion - - #region BottomSidePanel - - /// - /// BottomSidePanel Dependency Property - /// - public static readonly DependencyProperty BottomSidePanelProperty = DependencyProperty.Register( "BottomSidePanel", typeof( LayoutAnchorSideControl ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( LayoutAnchorSideControl )null, new PropertyChangedCallback( OnBottomSidePanelChanged ) ) ); - - /// - /// Gets or sets the BottomSidePanel property. This dependency property - /// indicates bottom side panel control. - /// - public LayoutAnchorSideControl BottomSidePanel - { - get - { - return ( LayoutAnchorSideControl )GetValue( BottomSidePanelProperty ); - } - set - { - SetValue( BottomSidePanelProperty, value ); - } - } - - /// - /// Handles changes to the BottomSidePanel property. - /// - private static void OnBottomSidePanelChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnBottomSidePanelChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the BottomSidePanel property. - /// - protected virtual void OnBottomSidePanelChanged( DependencyPropertyChangedEventArgs e ) - { - if( e.OldValue != null ) - InternalRemoveLogicalChild( e.OldValue ); - if( e.NewValue != null ) - InternalAddLogicalChild( e.NewValue ); - } - - #endregion - - #region LogicalChildren - - List _logicalChildren = new List(); - - protected override System.Collections.IEnumerator LogicalChildren - { - get - { - return _logicalChildren.Select( ch => ch.GetValueOrDefault() ).GetEnumerator(); - } - } - - public System.Collections.IEnumerator LogicalChildrenPublic - { - get - { - return this.LogicalChildren; - } - } - - - internal void InternalAddLogicalChild( object element ) - { + this.Loaded += new RoutedEventHandler(DockingManager_Loaded); + this.Unloaded += new RoutedEventHandler(DockingManager_Unloaded); + } + + #endregion + + #region Properties + + #region Layout + + /// + /// Layout Dependency Property + /// + public static readonly DependencyProperty LayoutProperty = DependencyProperty.Register("Layout", typeof(LayoutRoot), typeof(DockingManager), + new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnLayoutChanged), new CoerceValueCallback(CoerceLayoutValue))); + + /// + /// Gets or sets the Layout property. This dependency property + /// indicates layout tree. + /// + public LayoutRoot Layout + { + get + { + return (LayoutRoot)GetValue(LayoutProperty); + } + set + { + SetValue(LayoutProperty, value); + } + } + + /// + /// Coerces the value. + /// + private static object CoerceLayoutValue(DependencyObject d, object value) + { + if (value == null) + return new LayoutRoot() { RootPanel = new LayoutPanel(new LayoutDocumentPaneGroup(new LayoutDocumentPane())) }; + + ((DockingManager)d).OnLayoutChanging(value as LayoutRoot); + + return value; + } + + /// + /// Handles changes to the Layout property. + /// + private static void OnLayoutChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnLayoutChanged(e.OldValue as LayoutRoot, e.NewValue as LayoutRoot); + } + + /// + /// Provides derived classes an opportunity to handle changes to the property. + /// + protected virtual void OnLayoutChanged(LayoutRoot oldLayout, LayoutRoot newLayout) + { + if (oldLayout != null) + { + oldLayout.PropertyChanged -= new PropertyChangedEventHandler(OnLayoutRootPropertyChanged); + oldLayout.Updated -= new EventHandler(OnLayoutRootUpdated); + } + + foreach (var fwc in _fwList.ToArray()) + { + fwc.KeepContentVisibleOnClose = true; + fwc.InternalClose(); + } + + _fwList.Clear(); + + foreach (var fwc in _fwHiddenList.ToArray()) + { + fwc.InternalClose(); + } + + _fwHiddenList.Clear(); + + DetachDocumentsSource(oldLayout, DocumentsSource); + DetachAnchorablesSource(oldLayout, AnchorablesSource); + + if (oldLayout != null && + oldLayout.Manager == this) + oldLayout.Manager = null; + + ClearLogicalChildrenList(); + DetachLayoutItems(); + + Layout.Manager = this; + + AttachLayoutItems(); + AttachDocumentsSource(newLayout, DocumentsSource); + AttachAnchorablesSource(newLayout, AnchorablesSource); + + if (IsLoaded) + { + LayoutRootPanel = CreateUIElementForModel(Layout.RootPanel) as LayoutPanelControl; + LeftSidePanel = CreateUIElementForModel(Layout.LeftSide) as LayoutAnchorSideControl; + TopSidePanel = CreateUIElementForModel(Layout.TopSide) as LayoutAnchorSideControl; + RightSidePanel = CreateUIElementForModel(Layout.RightSide) as LayoutAnchorSideControl; + BottomSidePanel = CreateUIElementForModel(Layout.BottomSide) as LayoutAnchorSideControl; + + foreach (var fw in Layout.FloatingWindows.ToArray()) + { + if (fw.IsValid) + _fwList.Add(CreateUIElementForModel(fw) as LayoutFloatingWindowControl); + } + + foreach (var fw in _fwList.ToArray()) + { + var window = fw.Model as LayoutAnchorableFloatingWindow; + if (window != null && window.RootPanel.IsMaximized) + { + fw.WindowState = WindowState.Normal; + fw.Show(); + fw.WindowState = WindowState.Maximized; + } + else + fw.Show(); + //fw.Owner = Window.GetWindow(this); + //fw.SetParentToMainWindowOf(this); + } + + // In order to prevent resource leaks, unsubscribe from SizeChanged event for case when user call loading of Layout Settigns. + SizeChanged -= OnSizeChanged; + SizeChanged += OnSizeChanged; + } + + if (newLayout != null) + { + newLayout.PropertyChanged += new PropertyChangedEventHandler(OnLayoutRootPropertyChanged); + newLayout.Updated += new EventHandler(OnLayoutRootUpdated); + } + + if (LayoutChanged != null) + LayoutChanged(this, EventArgs.Empty); + + //if (Layout != null) + // Layout.CollectGarbage(); + + CommandManager.InvalidateRequerySuggested(); + } + + #endregion + + #region LayoutUpdateStrategy + + /// + /// LayoutUpdateStrategy Dependency Property + /// + public static readonly DependencyProperty LayoutUpdateStrategyProperty = DependencyProperty.Register("LayoutUpdateStrategy", typeof(ILayoutUpdateStrategy), typeof(DockingManager), + new FrameworkPropertyMetadata((ILayoutUpdateStrategy)null)); + + /// + /// Gets or sets the LayoutUpdateStrategy property. This dependency property + /// indicates the strategy class to call when AvalonDock needs to positionate a LayoutAnchorable inside an existing layout. + /// + /// Sometimes it's impossible to automatically insert an anchorable in the layout without specifing the target parent pane. + /// Set this property to an object that will be asked to insert the anchorable to the desidered position. + public ILayoutUpdateStrategy LayoutUpdateStrategy + { + get + { + return (ILayoutUpdateStrategy)GetValue(LayoutUpdateStrategyProperty); + } + set + { + SetValue(LayoutUpdateStrategyProperty, value); + } + } + + #endregion + + #region DocumentPaneTemplate + + /// + /// DocumentPaneTemplate Dependency Property + /// + public static readonly DependencyProperty DocumentPaneTemplateProperty = DependencyProperty.Register("DocumentPaneTemplate", typeof(ControlTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((ControlTemplate)null, new PropertyChangedCallback(OnDocumentPaneTemplateChanged))); + + /// + /// Gets or sets the DocumentPaneDataTemplate property. This dependency property + /// indicates . + /// + public ControlTemplate DocumentPaneTemplate + { + get + { + return (ControlTemplate)GetValue(DocumentPaneTemplateProperty); + } + set + { + SetValue(DocumentPaneTemplateProperty, value); + } + } + + /// + /// Handles changes to the DocumentPaneTemplate property. + /// + private static void OnDocumentPaneTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentPaneTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentPaneTemplate property. + /// + protected virtual void OnDocumentPaneTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + #endregion + + #region AnchorablePaneTemplate + + /// + /// AnchorablePaneTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorablePaneTemplateProperty = DependencyProperty.Register("AnchorablePaneTemplate", typeof(ControlTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((ControlTemplate)null, new PropertyChangedCallback(OnAnchorablePaneTemplateChanged))); + + /// + /// Gets or sets the AnchorablePaneTemplate property. This dependency property + /// indicates .... + /// + public ControlTemplate AnchorablePaneTemplate + { + get + { + return (ControlTemplate)GetValue(AnchorablePaneTemplateProperty); + } + set + { + SetValue(AnchorablePaneTemplateProperty, value); + } + } + + /// + /// Handles changes to the AnchorablePaneDataTemplate property. + /// + private static void OnAnchorablePaneTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAnchorablePaneTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorablePaneDataTemplate property. + /// + protected virtual void OnAnchorablePaneTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + #endregion + + #region AnchorSideTemplate + + /// + /// AnchorSideTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorSideTemplateProperty = DependencyProperty.Register("AnchorSideTemplate", typeof(ControlTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((ControlTemplate)null)); + + /// + /// Gets or sets the AnchorSideTemplate property. This dependency property + /// indicates .... + /// + public ControlTemplate AnchorSideTemplate + { + get + { + return (ControlTemplate)GetValue(AnchorSideTemplateProperty); + } + set + { + SetValue(AnchorSideTemplateProperty, value); + } + } + + #endregion + + #region AnchorGroupTemplate + + /// + /// AnchorGroupTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorGroupTemplateProperty = DependencyProperty.Register("AnchorGroupTemplate", typeof(ControlTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((ControlTemplate)null)); + + /// + /// Gets or sets the AnchorGroupTemplate property. This dependency property + /// indicates the template used to render the AnchorGroup control. + /// + public ControlTemplate AnchorGroupTemplate + { + get + { + return (ControlTemplate)GetValue(AnchorGroupTemplateProperty); + } + set + { + SetValue(AnchorGroupTemplateProperty, value); + } + } + + #endregion + + #region AnchorTemplate + + /// + /// AnchorTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorTemplateProperty = DependencyProperty.Register("AnchorTemplate", typeof(ControlTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((ControlTemplate)null)); + + /// + /// Gets or sets the AnchorTemplate property. This dependency property + /// indicates .... + /// + public ControlTemplate AnchorTemplate + { + get + { + return (ControlTemplate)GetValue(AnchorTemplateProperty); + } + set + { + SetValue(AnchorTemplateProperty, value); + } + } + + #endregion + + #region DocumentPaneControlStyle + + /// + /// DocumentPaneControlStyle Dependency Property + /// + public static readonly DependencyProperty DocumentPaneControlStyleProperty = DependencyProperty.Register("DocumentPaneControlStyle", typeof(Style), typeof(DockingManager), + new FrameworkPropertyMetadata((Style)null, new PropertyChangedCallback(OnDocumentPaneControlStyleChanged))); + + /// + /// Gets or sets the DocumentPaneControlStyle property. This dependency property + /// indicates .... + /// + public Style DocumentPaneControlStyle + { + get + { + return (Style)GetValue(DocumentPaneControlStyleProperty); + } + set + { + SetValue(DocumentPaneControlStyleProperty, value); + } + } + + /// + /// Handles changes to the DocumentPaneControlStyle property. + /// + private static void OnDocumentPaneControlStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentPaneControlStyleChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentPaneControlStyle property. + /// + protected virtual void OnDocumentPaneControlStyleChanged(DependencyPropertyChangedEventArgs e) + { + } + + #endregion + + #region AnchorablePaneControlStyle + + /// + /// AnchorablePaneControlStyle Dependency Property + /// + public static readonly DependencyProperty AnchorablePaneControlStyleProperty = DependencyProperty.Register("AnchorablePaneControlStyle", typeof(Style), typeof(DockingManager), + new FrameworkPropertyMetadata((Style)null, new PropertyChangedCallback(OnAnchorablePaneControlStyleChanged))); + + /// + /// Gets or sets the AnchorablePaneControlStyle property. This dependency property + /// indicates the style to apply to AnchorablePaneControl. + /// + public Style AnchorablePaneControlStyle + { + get + { + return (Style)GetValue(AnchorablePaneControlStyleProperty); + } + set + { + SetValue(AnchorablePaneControlStyleProperty, value); + } + } + + /// + /// Handles changes to the AnchorablePaneControlStyle property. + /// + private static void OnAnchorablePaneControlStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAnchorablePaneControlStyleChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorablePaneControlStyle property. + /// + protected virtual void OnAnchorablePaneControlStyleChanged(DependencyPropertyChangedEventArgs e) + { + } + + #endregion + + #region DocumentHeaderTemplate + + /// + /// DocumentHeaderTemplate Dependency Property + /// + public static readonly DependencyProperty DocumentHeaderTemplateProperty = DependencyProperty.Register("DocumentHeaderTemplate", typeof(DataTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplate)null, new PropertyChangedCallback(OnDocumentHeaderTemplateChanged), new CoerceValueCallback(CoerceDocumentHeaderTemplateValue))); + + /// + /// Gets or sets the DocumentHeaderTemplate property. This dependency property + /// indicates data template to use for document header. + /// + public DataTemplate DocumentHeaderTemplate + { + get + { + return (DataTemplate)GetValue(DocumentHeaderTemplateProperty); + } + set + { + SetValue(DocumentHeaderTemplateProperty, value); + } + } + + /// + /// Handles changes to the DocumentHeaderTemplate property. + /// + private static void OnDocumentHeaderTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentHeaderTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentHeaderTemplate property. + /// + protected virtual void OnDocumentHeaderTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the DocumentHeaderTemplate value. + /// + private static object CoerceDocumentHeaderTemplateValue(DependencyObject d, object value) + { + if (value != null && + d.GetValue(DocumentHeaderTemplateSelectorProperty) != null) + return null; + return value; + } + + #endregion + + #region DocumentHeaderTemplateSelector + + /// + /// DocumentHeaderTemplateSelector Dependency Property + /// + public static readonly DependencyProperty DocumentHeaderTemplateSelectorProperty = DependencyProperty.Register("DocumentHeaderTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplateSelector)null, new PropertyChangedCallback(OnDocumentHeaderTemplateSelectorChanged), new CoerceValueCallback(CoerceDocumentHeaderTemplateSelectorValue))); + + /// + /// Gets or sets the DocumentHeaderTemplateSelector property. This dependency property + /// indicates the template selector that is used when selcting the data template for the header. + /// + public DataTemplateSelector DocumentHeaderTemplateSelector + { + get + { + return (DataTemplateSelector)GetValue(DocumentHeaderTemplateSelectorProperty); + } + set + { + SetValue(DocumentHeaderTemplateSelectorProperty, value); + } + } + + /// + /// Handles changes to the DocumentHeaderTemplateSelector property. + /// + private static void OnDocumentHeaderTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentHeaderTemplateSelectorChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentHeaderTemplateSelector property. + /// + protected virtual void OnDocumentHeaderTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) + { + if (e.NewValue != null && + DocumentHeaderTemplate != null) + DocumentHeaderTemplate = null; + + if (DocumentPaneMenuItemHeaderTemplateSelector == null) + DocumentPaneMenuItemHeaderTemplateSelector = DocumentHeaderTemplateSelector; + + } + + /// + /// Coerces the DocumentHeaderTemplateSelector value. + /// + private static object CoerceDocumentHeaderTemplateSelectorValue(DependencyObject d, object value) + { + return value; + } + + #endregion + + #region DocumentTitleTemplate + + /// + /// DocumentTitleTemplate Dependency Property + /// + public static readonly DependencyProperty DocumentTitleTemplateProperty = DependencyProperty.Register("DocumentTitleTemplate", typeof(DataTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplate)null, new PropertyChangedCallback(OnDocumentTitleTemplateChanged), new CoerceValueCallback(CoerceDocumentTitleTemplateValue))); + + /// + /// Gets or sets the DocumentTitleTemplate property. This dependency property + /// indicates the datatemplate to use when creating the title for a document. + /// + public DataTemplate DocumentTitleTemplate + { + get + { + return (DataTemplate)GetValue(DocumentTitleTemplateProperty); + } + set + { + SetValue(DocumentTitleTemplateProperty, value); + } + } + + /// + /// Handles changes to the DocumentTitleTemplate property. + /// + private static void OnDocumentTitleTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentTitleTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentTitleTemplate property. + /// + protected virtual void OnDocumentTitleTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the DocumentTitleTemplate value. + /// + private static object CoerceDocumentTitleTemplateValue(DependencyObject d, object value) + { + if (value != null && + d.GetValue(DocumentTitleTemplateSelectorProperty) != null) + return null; + + return value; + } + + #endregion + + #region DocumentTitleTemplateSelector + + /// + /// DocumentTitleTemplateSelector Dependency Property + /// + public static readonly DependencyProperty DocumentTitleTemplateSelectorProperty = DependencyProperty.Register("DocumentTitleTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplateSelector)null, new PropertyChangedCallback(OnDocumentTitleTemplateSelectorChanged), new CoerceValueCallback(CoerceDocumentTitleTemplateSelectorValue))); + + /// + /// Gets or sets the DocumentTitleTemplateSelector property. This dependency property + /// indicates the data template selector to use when creating the data template for the title. + /// + public DataTemplateSelector DocumentTitleTemplateSelector + { + get + { + return (DataTemplateSelector)GetValue(DocumentTitleTemplateSelectorProperty); + } + set + { + SetValue(DocumentTitleTemplateSelectorProperty, value); + } + } + + /// + /// Handles changes to the DocumentTitleTemplateSelector property. + /// + private static void OnDocumentTitleTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentTitleTemplateSelectorChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentTitleTemplateSelector property. + /// + protected virtual void OnDocumentTitleTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) + { + if (e.NewValue != null) + DocumentTitleTemplate = null; + } + + /// + /// Coerces the DocumentTitleTemplateSelector value. + /// + private static object CoerceDocumentTitleTemplateSelectorValue(DependencyObject d, object value) + { + return value; + } + + #endregion + + #region AnchorableTitleTemplate + + /// + /// AnchorableTitleTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorableTitleTemplateProperty = DependencyProperty.Register("AnchorableTitleTemplate", typeof(DataTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplate)null, new PropertyChangedCallback(OnAnchorableTitleTemplateChanged), new CoerceValueCallback(CoerceAnchorableTitleTemplateValue))); + + /// + /// Gets or sets the AnchorableTitleTemplate property. This dependency property + /// indicates the data template to use for anchorables title. + /// + public DataTemplate AnchorableTitleTemplate + { + get + { + return (DataTemplate)GetValue(AnchorableTitleTemplateProperty); + } + set + { + SetValue(AnchorableTitleTemplateProperty, value); + } + } + + /// + /// Handles changes to the AnchorableTitleTemplate property. + /// + private static void OnAnchorableTitleTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAnchorableTitleTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorableTitleTemplate property. + /// + protected virtual void OnAnchorableTitleTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the AnchorableTitleTemplate value. + /// + private static object CoerceAnchorableTitleTemplateValue(DependencyObject d, object value) + { + if (value != null && + d.GetValue(AnchorableTitleTemplateSelectorProperty) != null) + return null; + return value; + } + + #endregion + + #region AnchorableTitleTemplateSelector + + /// + /// AnchorableTitleTemplateSelector Dependency Property + /// + public static readonly DependencyProperty AnchorableTitleTemplateSelectorProperty = DependencyProperty.Register("AnchorableTitleTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplateSelector)null, new PropertyChangedCallback(OnAnchorableTitleTemplateSelectorChanged))); + + /// + /// Gets or sets the AnchorableTitleTemplateSelector property. This dependency property + /// indicates selctor to use when selecting data template for the title of anchorables. + /// + public DataTemplateSelector AnchorableTitleTemplateSelector + { + get + { + return (DataTemplateSelector)GetValue(AnchorableTitleTemplateSelectorProperty); + } + set + { + SetValue(AnchorableTitleTemplateSelectorProperty, value); + } + } + + /// + /// Handles changes to the AnchorableTitleTemplateSelector property. + /// + private static void OnAnchorableTitleTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAnchorableTitleTemplateSelectorChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorableTitleTemplateSelector property. + /// + protected virtual void OnAnchorableTitleTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) + { + if (e.NewValue != null && + AnchorableTitleTemplate != null) + AnchorableTitleTemplate = null; + } + + #endregion + + #region AnchorableHeaderTemplate + + /// + /// AnchorableHeaderTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorableHeaderTemplateProperty = DependencyProperty.Register("AnchorableHeaderTemplate", typeof(DataTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplate)null, new PropertyChangedCallback(OnAnchorableHeaderTemplateChanged), new CoerceValueCallback(CoerceAnchorableHeaderTemplateValue))); + + /// + /// Gets or sets the AnchorableHeaderTemplate property. This dependency property + /// indicates the data template to use for anchorable templates. + /// + public DataTemplate AnchorableHeaderTemplate + { + get + { + return (DataTemplate)GetValue(AnchorableHeaderTemplateProperty); + } + set + { + SetValue(AnchorableHeaderTemplateProperty, value); + } + } + + /// + /// Handles changes to the AnchorableHeaderTemplate property. + /// + private static void OnAnchorableHeaderTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAnchorableHeaderTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorableHeaderTemplate property. + /// + protected virtual void OnAnchorableHeaderTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the AnchorableHeaderTemplate value. + /// + private static object CoerceAnchorableHeaderTemplateValue(DependencyObject d, object value) + { + if (value != null && + d.GetValue(AnchorableHeaderTemplateSelectorProperty) != null) + return null; + + return value; + } + + #endregion + + #region AnchorableHeaderTemplateSelector + + /// + /// AnchorableHeaderTemplateSelector Dependency Property + /// + public static readonly DependencyProperty AnchorableHeaderTemplateSelectorProperty = DependencyProperty.Register("AnchorableHeaderTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplateSelector)null, new PropertyChangedCallback(OnAnchorableHeaderTemplateSelectorChanged))); + + /// + /// Gets or sets the AnchorableHeaderTemplateSelector property. This dependency property + /// indicates the selector to use when selecting the data template for anchorable headers. + /// + public DataTemplateSelector AnchorableHeaderTemplateSelector + { + get + { + return (DataTemplateSelector)GetValue(AnchorableHeaderTemplateSelectorProperty); + } + set + { + SetValue(AnchorableHeaderTemplateSelectorProperty, value); + } + } + + /// + /// Handles changes to the AnchorableHeaderTemplateSelector property. + /// + private static void OnAnchorableHeaderTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAnchorableHeaderTemplateSelectorChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorableHeaderTemplateSelector property. + /// + protected virtual void OnAnchorableHeaderTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) + { + if (e.NewValue != null) + AnchorableHeaderTemplate = null; + } + + #endregion + + #region LayoutRootPanel + + /// + /// LayoutRootPanel Dependency Property + /// + public static readonly DependencyProperty LayoutRootPanelProperty = DependencyProperty.Register("LayoutRootPanel", typeof(LayoutPanelControl), typeof(DockingManager), + new FrameworkPropertyMetadata((LayoutPanelControl)null, new PropertyChangedCallback(OnLayoutRootPanelChanged))); + + /// + /// Gets or sets the LayoutRootPanel property. This dependency property + /// indicates the layout panel control which is attached to the Layout.Root property. + /// + public LayoutPanelControl LayoutRootPanel + { + get + { + return (LayoutPanelControl)GetValue(LayoutRootPanelProperty); + } + set + { + SetValue(LayoutRootPanelProperty, value); + } + } + + /// + /// Handles changes to the LayoutRootPanel property. + /// + private static void OnLayoutRootPanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnLayoutRootPanelChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the LayoutRootPanel property. + /// + protected virtual void OnLayoutRootPanelChanged(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue != null) + InternalRemoveLogicalChild(e.OldValue); + if (e.NewValue != null) + InternalAddLogicalChild(e.NewValue); + } + + #endregion + + #region RightSidePanel + + /// + /// RightSidePanel Dependency Property + /// + public static readonly DependencyProperty RightSidePanelProperty = DependencyProperty.Register("RightSidePanel", typeof(LayoutAnchorSideControl), typeof(DockingManager), + new FrameworkPropertyMetadata((LayoutAnchorSideControl)null, new PropertyChangedCallback(OnRightSidePanelChanged))); + + /// + /// Gets or sets the RightSidePanel property. This dependency property + /// indicates right side anchor panel. + /// + public LayoutAnchorSideControl RightSidePanel + { + get + { + return (LayoutAnchorSideControl)GetValue(RightSidePanelProperty); + } + set + { + SetValue(RightSidePanelProperty, value); + } + } + + /// + /// Handles changes to the RightSidePanel property. + /// + private static void OnRightSidePanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnRightSidePanelChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the RightSidePanel property. + /// + protected virtual void OnRightSidePanelChanged(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue != null) + InternalRemoveLogicalChild(e.OldValue); + if (e.NewValue != null) + InternalAddLogicalChild(e.NewValue); + } + + #endregion + + #region LeftSidePanel + + /// + /// LeftSidePanel Dependency Property + /// + public static readonly DependencyProperty LeftSidePanelProperty = DependencyProperty.Register("LeftSidePanel", typeof(LayoutAnchorSideControl), typeof(DockingManager), + new FrameworkPropertyMetadata((LayoutAnchorSideControl)null, new PropertyChangedCallback(OnLeftSidePanelChanged))); + + /// + /// Gets or sets the LeftSidePanel property. This dependency property + /// indicates the left side panel control. + /// + public LayoutAnchorSideControl LeftSidePanel + { + get + { + return (LayoutAnchorSideControl)GetValue(LeftSidePanelProperty); + } + set + { + SetValue(LeftSidePanelProperty, value); + } + } + + /// + /// Handles changes to the LeftSidePanel property. + /// + private static void OnLeftSidePanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnLeftSidePanelChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the LeftSidePanel property. + /// + protected virtual void OnLeftSidePanelChanged(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue != null) + InternalRemoveLogicalChild(e.OldValue); + if (e.NewValue != null) + InternalAddLogicalChild(e.NewValue); + } + + #endregion + + #region TopSidePanel + + /// + /// TopSidePanel Dependency Property + /// + public static readonly DependencyProperty TopSidePanelProperty = DependencyProperty.Register("TopSidePanel", typeof(LayoutAnchorSideControl), typeof(DockingManager), + new FrameworkPropertyMetadata((LayoutAnchorSideControl)null, new PropertyChangedCallback(OnTopSidePanelChanged))); + + /// + /// Gets or sets the TopSidePanel property. This dependency property + /// indicates top side control panel. + /// + public LayoutAnchorSideControl TopSidePanel + { + get + { + return (LayoutAnchorSideControl)GetValue(TopSidePanelProperty); + } + set + { + SetValue(TopSidePanelProperty, value); + } + } + + /// + /// Handles changes to the TopSidePanel property. + /// + private static void OnTopSidePanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnTopSidePanelChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the TopSidePanel property. + /// + protected virtual void OnTopSidePanelChanged(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue != null) + InternalRemoveLogicalChild(e.OldValue); + if (e.NewValue != null) + InternalAddLogicalChild(e.NewValue); + } + + #endregion + + #region BottomSidePanel + + /// + /// BottomSidePanel Dependency Property + /// + public static readonly DependencyProperty BottomSidePanelProperty = DependencyProperty.Register("BottomSidePanel", typeof(LayoutAnchorSideControl), typeof(DockingManager), + new FrameworkPropertyMetadata((LayoutAnchorSideControl)null, new PropertyChangedCallback(OnBottomSidePanelChanged))); + + /// + /// Gets or sets the BottomSidePanel property. This dependency property + /// indicates bottom side panel control. + /// + public LayoutAnchorSideControl BottomSidePanel + { + get + { + return (LayoutAnchorSideControl)GetValue(BottomSidePanelProperty); + } + set + { + SetValue(BottomSidePanelProperty, value); + } + } + + /// + /// Handles changes to the BottomSidePanel property. + /// + private static void OnBottomSidePanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnBottomSidePanelChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the BottomSidePanel property. + /// + protected virtual void OnBottomSidePanelChanged(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue != null) + InternalRemoveLogicalChild(e.OldValue); + if (e.NewValue != null) + InternalAddLogicalChild(e.NewValue); + } + + #endregion + + #region LogicalChildren + + List _logicalChildren = new List(); + + protected override System.Collections.IEnumerator LogicalChildren + { + get + { + return _logicalChildren.Select(ch => ch.GetValueOrDefault()).GetEnumerator(); + } + } + + public System.Collections.IEnumerator LogicalChildrenPublic + { + get + { + return this.LogicalChildren; + } + } + + + internal void InternalAddLogicalChild(object element) + { #if DEBUG - if( _logicalChildren.Select( ch => ch.GetValueOrDefault() ).Contains( element ) ) - new InvalidOperationException(); + if (_logicalChildren.Select(ch => ch.GetValueOrDefault()).Contains(element)) + new InvalidOperationException(); #endif - if( _logicalChildren.Select( ch => ch.GetValueOrDefault() ).Contains( element ) ) - return; - - _logicalChildren.Add( new WeakReference( element ) ); - AddLogicalChild( element ); - } - - internal void InternalRemoveLogicalChild( object element ) - { - var wrToRemove = _logicalChildren.FirstOrDefault( ch => ch.GetValueOrDefault() == element ); - if( wrToRemove != null ) - _logicalChildren.Remove( wrToRemove ); - RemoveLogicalChild( element ); - } - - private void ClearLogicalChildrenList() - { - foreach( var child in _logicalChildren.Select( ch => ch.GetValueOrDefault() ).ToArray() ) - RemoveLogicalChild( child ); - _logicalChildren.Clear(); - } - - #endregion - - #region AutoHideWindow - - /// - /// AutoHideWindow Read-Only Dependency Property - /// - private static readonly DependencyPropertyKey AutoHideWindowPropertyKey = DependencyProperty.RegisterReadOnly( "AutoHideWindow", typeof( LayoutAutoHideWindowControl ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( LayoutAutoHideWindowControl )null, new PropertyChangedCallback( OnAutoHideWindowChanged ) ) ); - - public static readonly DependencyProperty AutoHideWindowProperty = AutoHideWindowPropertyKey.DependencyProperty; - - /// - /// Gets the AutoHideWindow property. This dependency property - /// indicates the currently shown autohide window. - /// - public LayoutAutoHideWindowControl AutoHideWindow - { - get - { - return ( LayoutAutoHideWindowControl )GetValue( AutoHideWindowProperty ); - } - } - - /// - /// Provides a secure method for setting the AutoHideWindow property. - /// This dependency property indicates the currently shown autohide window. - /// - /// The new value for the property. - protected void SetAutoHideWindow( LayoutAutoHideWindowControl value ) - { - SetValue( AutoHideWindowPropertyKey, value ); - } - - /// - /// Handles changes to the AutoHideWindow property. - /// - private static void OnAutoHideWindowChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnAutoHideWindowChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the AutoHideWindow property. - /// - protected virtual void OnAutoHideWindowChanged( DependencyPropertyChangedEventArgs e ) - { - if( e.OldValue != null ) - InternalRemoveLogicalChild( e.OldValue ); - if( e.NewValue != null ) - InternalAddLogicalChild( e.NewValue ); - - } - - #endregion - - #region Floating Windows - - public IEnumerable FloatingWindows - { - get - { - return _fwList; - } - } - - #endregion - - #region LayoutItemTemplate - - /// - /// LayoutItemTemplate Dependency Property - /// - public static readonly DependencyProperty LayoutItemTemplateProperty = DependencyProperty.Register( "LayoutItemTemplate", typeof( DataTemplate ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( DataTemplate )null, new PropertyChangedCallback( OnLayoutItemTemplateChanged ) ) ); - - /// - /// Gets or sets the AnchorableTemplate property. This dependency property - /// indicates the template to use to render anchorable and document contents. - /// - public DataTemplate LayoutItemTemplate - { - get - { - return ( DataTemplate )GetValue( LayoutItemTemplateProperty ); - } - set - { - SetValue( LayoutItemTemplateProperty, value ); - } - } - - /// - /// Handles changes to the AnchorableTemplate property. - /// - private static void OnLayoutItemTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnLayoutItemTemplateChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the AnchorableTemplate property. - /// - protected virtual void OnLayoutItemTemplateChanged( DependencyPropertyChangedEventArgs e ) - { - } - - #endregion - - #region LayoutItemTemplateSelector - - /// - /// LayoutItemTemplateSelector Dependency Property - /// - public static readonly DependencyProperty LayoutItemTemplateSelectorProperty = DependencyProperty.Register( "LayoutItemTemplateSelector", typeof( DataTemplateSelector ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( DataTemplateSelector )null, new PropertyChangedCallback( OnLayoutItemTemplateSelectorChanged ) ) ); - - /// - /// Gets or sets the LayoutItemTemplateSelector property. This dependency property - /// indicates selector object to use for anchorable templates. - /// - public DataTemplateSelector LayoutItemTemplateSelector - { - get - { - return ( DataTemplateSelector )GetValue( LayoutItemTemplateSelectorProperty ); - } - set - { - SetValue( LayoutItemTemplateSelectorProperty, value ); - } - } - - /// - /// Handles changes to the LayoutItemTemplateSelector property. - /// - private static void OnLayoutItemTemplateSelectorChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnLayoutItemTemplateSelectorChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the LayoutItemTemplateSelector property. - /// - protected virtual void OnLayoutItemTemplateSelectorChanged( DependencyPropertyChangedEventArgs e ) - { - } - - #endregion - - #region DocumentsSource - - /// - /// DocumentsSource Dependency Property - /// - public static readonly DependencyProperty DocumentsSourceProperty = DependencyProperty.Register( "DocumentsSource", typeof( IEnumerable ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( IEnumerable )null, new PropertyChangedCallback( OnDocumentsSourceChanged ) ) ); - - /// - /// Gets or sets the DocumentsSource property. This dependency property - /// indicates the source collection of documents. - /// - public IEnumerable DocumentsSource - { - get - { - return ( IEnumerable )GetValue( DocumentsSourceProperty ); - } - set - { - SetValue( DocumentsSourceProperty, value ); - } - } - - /// - /// Handles changes to the DocumentsSource property. - /// - private static void OnDocumentsSourceChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnDocumentsSourceChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the DocumentsSource property. - /// - protected virtual void OnDocumentsSourceChanged( DependencyPropertyChangedEventArgs e ) - { - DetachDocumentsSource( Layout, e.OldValue as IEnumerable ); - AttachDocumentsSource( Layout, e.NewValue as IEnumerable ); - } - - #endregion - - #region DocumentContextMenu - - /// - /// DocumentContextMenu Dependency Property - /// - public static readonly DependencyProperty DocumentContextMenuProperty = DependencyProperty.Register( "DocumentContextMenu", typeof( ContextMenu ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( ContextMenu )null ) ); - - /// - /// Gets or sets the DocumentContextMenu property. This dependency property - /// indicates context menu to show for documents. - /// - public ContextMenu DocumentContextMenu - { - get - { - return ( ContextMenu )GetValue( DocumentContextMenuProperty ); - } - set - { - SetValue( DocumentContextMenuProperty, value ); - } - } - - #endregion - - #region AnchorablesSource - - /// - /// AnchorablesSource Dependency Property - /// - public static readonly DependencyProperty AnchorablesSourceProperty = DependencyProperty.Register( "AnchorablesSource", typeof( IEnumerable ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( IEnumerable )null, new PropertyChangedCallback( OnAnchorablesSourceChanged ) ) ); - - /// - /// Gets or sets the AnchorablesSource property. This dependency property - /// indicates source collection of anchorables. - /// - public IEnumerable AnchorablesSource - { - get - { - return ( IEnumerable )GetValue( AnchorablesSourceProperty ); - } - set - { - SetValue( AnchorablesSourceProperty, value ); - } - } - - /// - /// Handles changes to the AnchorablesSource property. - /// - private static void OnAnchorablesSourceChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnAnchorablesSourceChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the AnchorablesSource property. - /// - protected virtual void OnAnchorablesSourceChanged( DependencyPropertyChangedEventArgs e ) - { - DetachAnchorablesSource( Layout, e.OldValue as IEnumerable ); - AttachAnchorablesSource( Layout, e.NewValue as IEnumerable ); - } - - - - #endregion - - #region ActiveContent - - /// - /// ActiveContent Dependency Property - /// - public static readonly DependencyProperty ActiveContentProperty = DependencyProperty.Register( "ActiveContent", typeof( object ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( object )null, new PropertyChangedCallback( OnActiveContentChanged ) ) ); - - /// - /// Gets or sets the ActiveContent property. This dependency property - /// indicates the content currently active. - /// - public object ActiveContent - { - get - { - return ( object )GetValue( ActiveContentProperty ); - } - set - { - SetValue( ActiveContentProperty, value ); - } - } - - /// - /// Handles changes to the ActiveContent property. - /// - private static void OnActiveContentChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).InternalSetActiveContent( e.NewValue ); - ( ( DockingManager )d ).OnActiveContentChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the ActiveContent property. - /// - protected virtual void OnActiveContentChanged( DependencyPropertyChangedEventArgs e ) - { - if( ActiveContentChanged != null ) - ActiveContentChanged( this, EventArgs.Empty ); - } - - #endregion - - #region AnchorableContextMenu - - /// - /// AnchorableContextMenu Dependency Property - /// - public static readonly DependencyProperty AnchorableContextMenuProperty = DependencyProperty.Register( "AnchorableContextMenu", typeof( ContextMenu ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( ContextMenu )null ) ); - - /// - /// Gets or sets the AnchorableContextMenu property. This dependency property - /// indicates the context menu to show up for anchorables. - /// - public ContextMenu AnchorableContextMenu - { - get - { - return ( ContextMenu )GetValue( AnchorableContextMenuProperty ); - } - set - { - SetValue( AnchorableContextMenuProperty, value ); - } - } - - #endregion - - #region Theme - - /// - /// Theme Dependency Property - /// - public static readonly DependencyProperty ThemeProperty = DependencyProperty.Register( "Theme", typeof( Theme ), typeof( DockingManager ), - new FrameworkPropertyMetadata( null, new PropertyChangedCallback( OnThemeChanged ) ) ); - - /// - /// Gets or sets the Theme property. This dependency property - /// indicates the theme to use for AvalonDock controls. - /// - public Theme Theme - { - get - { - return ( Theme )GetValue( ThemeProperty ); - } - set - { - SetValue( ThemeProperty, value ); - } - } - - /// - /// Handles changes to the Theme property. - /// - private static void OnThemeChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnThemeChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the Theme property. - /// - protected virtual void OnThemeChanged( DependencyPropertyChangedEventArgs e ) - { - var oldTheme = e.OldValue as Theme; - var newTheme = e.NewValue as Theme; - var resources = this.Resources; - if( oldTheme != null ) - { - if( oldTheme is DictionaryTheme ) - { - if( currentThemeResourceDictionary != null ) - { - resources.MergedDictionaries.Remove( currentThemeResourceDictionary ); - currentThemeResourceDictionary = null; - } - } - else - { - var resourceDictionaryToRemove = - resources.MergedDictionaries.FirstOrDefault( r => r.Source == oldTheme.GetResourceUri() ); - if( resourceDictionaryToRemove != null ) - resources.MergedDictionaries.Remove( - resourceDictionaryToRemove ); - } - } - - if( newTheme != null ) - { - if( newTheme is DictionaryTheme ) - { - currentThemeResourceDictionary = ( ( DictionaryTheme )newTheme ).ThemeResourceDictionary; - resources.MergedDictionaries.Add( currentThemeResourceDictionary ); - } - else - { - resources.MergedDictionaries.Add( new ResourceDictionary() { Source = newTheme.GetResourceUri() } ); - } - } - - foreach( var fwc in _fwList ) - fwc.UpdateThemeResources( oldTheme ); - - if( _navigatorWindow != null ) - _navigatorWindow.UpdateThemeResources(); - - if( _overlayWindow != null ) - _overlayWindow.UpdateThemeResources(); - } - - #endregion - - #region GridSplitterWidth - - /// - /// GridSplitterWidth Dependency Property - /// - public static readonly DependencyProperty GridSplitterWidthProperty = DependencyProperty.Register( "GridSplitterWidth", typeof( double ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( double )6.0 ) ); - - /// - /// Gets or sets the GridSplitterWidth property. This dependency property - /// indicates width of grid splitters. - /// - public double GridSplitterWidth - { - get - { - return ( double )GetValue( GridSplitterWidthProperty ); - } - set - { - SetValue( GridSplitterWidthProperty, value ); - } - } - - #endregion - - #region GridSplitterHeight - - /// - /// GridSplitterHeight Dependency Property - /// - public static readonly DependencyProperty GridSplitterHeightProperty = DependencyProperty.Register( "GridSplitterHeight", typeof( double ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( double )6.0 ) ); - - /// - /// Gets or sets the GridSplitterHeight property. This dependency property - /// indicates height of grid splitters. - /// - public double GridSplitterHeight - { - get - { - return ( double )GetValue( GridSplitterHeightProperty ); - } - set - { - SetValue( GridSplitterHeightProperty, value ); - } - } - - #endregion - - #region DocumentPaneMenuItemHeaderTemplate - - /// - /// DocumentPaneMenuItemHeaderTemplate Dependency Property - /// - public static readonly DependencyProperty DocumentPaneMenuItemHeaderTemplateProperty = DependencyProperty.Register( "DocumentPaneMenuItemHeaderTemplate", typeof( DataTemplate ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( DataTemplate )null, new PropertyChangedCallback( OnDocumentPaneMenuItemHeaderTemplateChanged ), new CoerceValueCallback( CoerceDocumentPaneMenuItemHeaderTemplateValue ) ) ); - - /// - /// Gets or sets the DocumentPaneMenuItemHeaderTemplate property. This dependency property - /// indicates the header template to use while creating menu items for the document panes. - /// - public DataTemplate DocumentPaneMenuItemHeaderTemplate - { - get - { - return ( DataTemplate )GetValue( DocumentPaneMenuItemHeaderTemplateProperty ); - } - set - { - SetValue( DocumentPaneMenuItemHeaderTemplateProperty, value ); - } - } - - /// - /// Handles changes to the DocumentPaneMenuItemHeaderTemplate property. - /// - private static void OnDocumentPaneMenuItemHeaderTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnDocumentPaneMenuItemHeaderTemplateChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the DocumentPaneMenuItemHeaderTemplate property. - /// - protected virtual void OnDocumentPaneMenuItemHeaderTemplateChanged( DependencyPropertyChangedEventArgs e ) - { - } - - /// - /// Coerces the DocumentPaneMenuItemHeaderTemplate value. - /// - private static object CoerceDocumentPaneMenuItemHeaderTemplateValue( DependencyObject d, object value ) - { - if( value != null && - d.GetValue( DocumentPaneMenuItemHeaderTemplateSelectorProperty ) != null ) - return null; - if( value == null ) - return d.GetValue( DocumentHeaderTemplateProperty ); - - return value; - } - - #endregion - - #region DocumentPaneMenuItemHeaderTemplateSelector - - /// - /// DocumentPaneMenuItemHeaderTemplateSelector Dependency Property - /// - public static readonly DependencyProperty DocumentPaneMenuItemHeaderTemplateSelectorProperty = DependencyProperty.Register( "DocumentPaneMenuItemHeaderTemplateSelector", typeof( DataTemplateSelector ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( DataTemplateSelector )null, new PropertyChangedCallback( OnDocumentPaneMenuItemHeaderTemplateSelectorChanged ), new CoerceValueCallback( CoerceDocumentPaneMenuItemHeaderTemplateSelectorValue ) ) ); - - /// - /// Gets or sets the DocumentPaneMenuItemHeaderTemplateSelector property. This dependency property - /// indicates the data template selector to use for the menu items show when user select the DocumentPane document switch context menu. - /// - public DataTemplateSelector DocumentPaneMenuItemHeaderTemplateSelector - { - get - { - return ( DataTemplateSelector )GetValue( DocumentPaneMenuItemHeaderTemplateSelectorProperty ); - } - set - { - SetValue( DocumentPaneMenuItemHeaderTemplateSelectorProperty, value ); - } - } - - /// - /// Handles changes to the DocumentPaneMenuItemHeaderTemplateSelector property. - /// - private static void OnDocumentPaneMenuItemHeaderTemplateSelectorChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnDocumentPaneMenuItemHeaderTemplateSelectorChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the DocumentPaneMenuItemHeaderTemplateSelector property. - /// - protected virtual void OnDocumentPaneMenuItemHeaderTemplateSelectorChanged( DependencyPropertyChangedEventArgs e ) - { - if( e.NewValue != null && - DocumentPaneMenuItemHeaderTemplate != null ) - DocumentPaneMenuItemHeaderTemplate = null; - - } - - /// - /// Coerces the DocumentPaneMenuItemHeaderTemplateSelector value. - /// - private static object CoerceDocumentPaneMenuItemHeaderTemplateSelectorValue( DependencyObject d, object value ) - { - return value; - } - - #endregion - - #region IconContentTemplate - - /// - /// IconContentTemplate Dependency Property - /// - public static readonly DependencyProperty IconContentTemplateProperty = DependencyProperty.Register( "IconContentTemplate", typeof( DataTemplate ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( DataTemplate )null ) ); - - /// - /// Gets or sets the IconContentTemplate property. This dependency property - /// indicates the data template to use while extracting the icon from model. - /// - public DataTemplate IconContentTemplate - { - get - { - return ( DataTemplate )GetValue( IconContentTemplateProperty ); - } - set - { - SetValue( IconContentTemplateProperty, value ); - } - } - - #endregion - - #region IconContentTemplateSelector - - /// - /// IconContentTemplateSelector Dependency Property - /// - public static readonly DependencyProperty IconContentTemplateSelectorProperty = DependencyProperty.Register( "IconContentTemplateSelector", typeof( DataTemplateSelector ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( DataTemplateSelector )null ) ); - - /// - /// Gets or sets the IconContentTemplateSelector property. This dependency property - /// indicates data template selector to use while selecting the datatamplate for content icons. - /// - public DataTemplateSelector IconContentTemplateSelector - { - get - { - return ( DataTemplateSelector )GetValue( IconContentTemplateSelectorProperty ); - } - set - { - SetValue( IconContentTemplateSelectorProperty, value ); - } - } - - #endregion - - #region LayoutItemContainerStyle - - /// - /// LayoutItemContainerStyle Dependency Property - /// - public static readonly DependencyProperty LayoutItemContainerStyleProperty = DependencyProperty.Register( "LayoutItemContainerStyle", typeof( Style ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( Style )null, new PropertyChangedCallback( OnLayoutItemContainerStyleChanged ) ) ); - - /// - /// Gets or sets the LayoutItemContainerStyle property. This dependency property - /// indicates the style to apply to LayoutDocumentItem objects. A LayoutDocumentItem object is created when a new LayoutDocument is created inside the current Layout. - /// - public Style LayoutItemContainerStyle - { - get - { - return ( Style )GetValue( LayoutItemContainerStyleProperty ); - } - set - { - SetValue( LayoutItemContainerStyleProperty, value ); - } - } - - /// - /// Handles changes to the LayoutItemContainerStyle property. - /// - private static void OnLayoutItemContainerStyleChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnLayoutItemContainerStyleChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the LayoutItemContainerStyle property. - /// - protected virtual void OnLayoutItemContainerStyleChanged( DependencyPropertyChangedEventArgs e ) - { - AttachLayoutItems(); - } - - #endregion - - #region LayoutItemContainerStyleSelector - - /// - /// LayoutItemContainerStyleSelector Dependency Property - /// - public static readonly DependencyProperty LayoutItemContainerStyleSelectorProperty = DependencyProperty.Register( "LayoutItemContainerStyleSelector", typeof( StyleSelector ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( StyleSelector )null, new PropertyChangedCallback( OnLayoutItemContainerStyleSelectorChanged ) ) ); - - /// - /// Gets or sets the LayoutItemContainerStyleSelector property. This dependency property - /// indicates style selector of the LayoutDocumentItemStyle. - /// - public StyleSelector LayoutItemContainerStyleSelector - { - get - { - return ( StyleSelector )GetValue( LayoutItemContainerStyleSelectorProperty ); - } - set - { - SetValue( LayoutItemContainerStyleSelectorProperty, value ); - } - } - - /// - /// Handles changes to the LayoutItemContainerStyleSelector property. - /// - private static void OnLayoutItemContainerStyleSelectorChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( DockingManager )d ).OnLayoutItemContainerStyleSelectorChanged( e ); - } - - /// - /// Provides derived classes an opportunity to handle changes to the LayoutItemContainerStyleSelector property. - /// - protected virtual void OnLayoutItemContainerStyleSelectorChanged( DependencyPropertyChangedEventArgs e ) - { - AttachLayoutItems(); - } - - #endregion - - #region ShowSystemMenu - - /// - /// ShowSystemMenu Dependency Property - /// - public static readonly DependencyProperty ShowSystemMenuProperty = DependencyProperty.Register( "ShowSystemMenu", typeof( bool ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( bool )true ) ); - - /// - /// Gets or sets the ShowSystemMenu property. This dependency property - /// indicates if floating windows should show the system menu when a custom context menu is not defined. - /// - public bool ShowSystemMenu - { - get - { - return ( bool )GetValue( ShowSystemMenuProperty ); - } - set - { - SetValue( ShowSystemMenuProperty, value ); - } - } - - #endregion - - #region AllowMixedOrientation - - /// - /// AllowMixedOrientation Dependency Property - /// - public static readonly DependencyProperty AllowMixedOrientationProperty = DependencyProperty.Register( "AllowMixedOrientation", typeof( bool ), typeof( DockingManager ), - new FrameworkPropertyMetadata( ( bool )false ) ); - - /// - /// Gets or sets the AllowMixedOrientation property. This dependency property - /// indicates if the manager should allow mixed orientation for document panes. - /// - public bool AllowMixedOrientation - { - get - { - return ( bool )GetValue( AllowMixedOrientationProperty ); - } - set - { - SetValue( AllowMixedOrientationProperty, value ); - } - } - - #endregion - - #endregion - - #region Private Properties - - private bool IsNavigatorWindowActive - { - get - { - return _navigatorWindow != null; - } - } - - #endregion - - #region Overrides - - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - - _autohideArea = GetTemplateChild( "PART_AutoHideArea" ) as FrameworkElement; - } - - protected override void OnInitialized( EventArgs e ) - { - base.OnInitialized( e ); - } - - - protected override Size ArrangeOverride( Size arrangeBounds ) - { - _areas = null; - return base.ArrangeOverride( arrangeBounds ); - } - - protected override void OnPreviewKeyDown( KeyEventArgs e ) - { - if( Keyboard.IsKeyDown( Key.LeftCtrl ) || Keyboard.IsKeyDown( Key.RightCtrl ) ) - { - if( e.IsDown && e.Key == Key.Tab ) - { - if( !IsNavigatorWindowActive ) - { - ShowNavigatorWindow(); - e.Handled = true; - } - } - } - - base.OnPreviewKeyDown( e ); - } - - #endregion - - #region Public Methods - - /// - /// Return the LayoutItem wrapper for the content passed as argument - /// - /// LayoutContent to search - /// Either a LayoutAnchorableItem or LayoutDocumentItem which contains the LayoutContent passed as argument - public LayoutItem GetLayoutItemFromModel( LayoutContent content ) - { - return _layoutItems.FirstOrDefault( item => item.LayoutElement == content ); - } - - public LayoutFloatingWindowControl CreateFloatingWindow( LayoutContent contentModel, bool isContentImmutable ) - { - LayoutFloatingWindowControl lfwc = null; - - if( contentModel is LayoutAnchorable ) - { - var parent = contentModel.Parent as ILayoutPane; - if( parent == null ) - { - var pane = new LayoutAnchorablePane( contentModel as LayoutAnchorable ) - { - FloatingTop = contentModel.FloatingTop, - FloatingLeft = contentModel.FloatingLeft, - FloatingWidth = contentModel.FloatingWidth, - FloatingHeight = contentModel.FloatingHeight - }; - lfwc = this.CreateFloatingWindowForLayoutAnchorableWithoutParent( pane, isContentImmutable ); - } - } - - if( lfwc == null ) - { - lfwc = this.CreateFloatingWindowCore( contentModel, isContentImmutable ); - } - - return lfwc; - } - - #endregion - - #region Internal Methods - - internal UIElement CreateUIElementForModel( ILayoutElement model ) - { - if( model is LayoutPanel ) - return new LayoutPanelControl( model as LayoutPanel ); - if( model is LayoutAnchorablePaneGroup ) - return new LayoutAnchorablePaneGroupControl( model as LayoutAnchorablePaneGroup ); - if( model is LayoutDocumentPaneGroup ) - return new LayoutDocumentPaneGroupControl( model as LayoutDocumentPaneGroup ); - - if( model is LayoutAnchorSide ) - { - var templateModelView = new LayoutAnchorSideControl( model as LayoutAnchorSide ); - templateModelView.SetBinding( LayoutAnchorSideControl.TemplateProperty, new Binding( DockingManager.AnchorSideTemplateProperty.Name) { Source = this } ); - return templateModelView; - } - if( model is LayoutAnchorGroup ) - { - var templateModelView = new LayoutAnchorGroupControl( model as LayoutAnchorGroup ); - templateModelView.SetBinding( LayoutAnchorGroupControl.TemplateProperty, new Binding( DockingManager.AnchorGroupTemplateProperty.Name) { Source = this } ); - return templateModelView; - } - - if( model is LayoutDocumentPane ) - { - var templateModelView = new LayoutDocumentPaneControl( model as LayoutDocumentPane ); - templateModelView.SetBinding( LayoutDocumentPaneControl.StyleProperty, new Binding( DockingManager.DocumentPaneControlStyleProperty.Name) { Source = this } ); - return templateModelView; - } - if( model is LayoutAnchorablePane ) - { - var templateModelView = new LayoutAnchorablePaneControl( model as LayoutAnchorablePane ); - templateModelView.SetBinding( LayoutAnchorablePaneControl.StyleProperty, new Binding( DockingManager.AnchorablePaneControlStyleProperty.Name ) { Source = this } ); - return templateModelView; - } - - if( model is LayoutAnchorableFloatingWindow ) - { - if( DesignerProperties.GetIsInDesignMode( this ) ) - return null; - var modelFW = model as LayoutAnchorableFloatingWindow; - var newFW = new LayoutAnchorableFloatingWindowControl( modelFW ) - { - //Owner = Window.GetWindow(this) - }; - newFW.SetParentToMainWindowOf( this ); - - // Floating Window can also contain only Pane Groups at its base (issue #27) so we check for - // RootPanel (which is a LayoutAnchorablePaneGroup) and make sure the window is positioned back - // in current (or nearest) monitor - var panegroup = modelFW.RootPanel; - if (panegroup != null) - { - panegroup.KeepInsideNearestMonitor(); // Check position is valid in current setup - - newFW.Left = panegroup.FloatingLeft; // Position the window to previous or nearest valid position - newFW.Top = panegroup.FloatingTop; - newFW.Width = panegroup.FloatingWidth; - newFW.Height = panegroup.FloatingHeight; - } - - newFW.ShowInTaskbar = false; - - Dispatcher.BeginInvoke( new Action( () => - { - newFW.Show(); - } ), DispatcherPriority.Send ); - - if( panegroup != null && panegroup.IsMaximized ) - { - newFW.WindowState = WindowState.Maximized; - } - - return newFW; - } - - if( model is LayoutDocumentFloatingWindow ) - { - if( DesignerProperties.GetIsInDesignMode( this ) ) - return null; - var modelFW = model as LayoutDocumentFloatingWindow; - var newFW = new LayoutDocumentFloatingWindowControl( modelFW ) - { - //Owner = Window.GetWindow(this) - }; - newFW.SetParentToMainWindowOf( this ); - - var paneForExtensions = modelFW.RootPanel; - if( paneForExtensions != null ) - { - //ensure that floating window position is inside current (or nearest) monitor - paneForExtensions.KeepInsideNearestMonitor(); - - newFW.Left = paneForExtensions.FloatingLeft; - newFW.Top = paneForExtensions.FloatingTop; - newFW.Width = paneForExtensions.FloatingWidth; - newFW.Height = paneForExtensions.FloatingHeight; - } - - newFW.ShowInTaskbar = false; - newFW.Show(); - // Do not set the WindowState before showing or it will be lost - if( paneForExtensions != null && paneForExtensions.IsMaximized ) - { - newFW.WindowState = WindowState.Maximized; - } - return newFW; - } - - if( model is LayoutDocument ) - { - var templateModelView = new LayoutDocumentControl() { Model = model as LayoutDocument }; - return templateModelView; - } - - return null; - } - - internal void ShowAutoHideWindow( LayoutAnchorControl anchor ) - { - _autoHideWindowManager.ShowAutoHideWindow( anchor ); - //if (_autohideArea == null) - // return; - - //if (AutoHideWindow != null && AutoHideWindow.Model == anchor.Model) - // return; - - //Trace.WriteLine("ShowAutoHideWindow()"); - - //_currentAutohiddenAnchor = new WeakReference(anchor); - - //HideAutoHideWindow(anchor); - - //SetAutoHideWindow(new LayoutAutoHideWindowControl(anchor)); - //AutoHideWindow.Show(); - } - - internal void HideAutoHideWindow( LayoutAnchorControl anchor ) - { - _autoHideWindowManager.HideAutoWindow( anchor ); - } - - internal FrameworkElement GetAutoHideAreaElement() - { - return _autohideArea; - } - - internal void StartDraggingFloatingWindowForContent( LayoutContent contentModel, bool startDrag = true ) - { - var fwc = this.CreateFloatingWindow( contentModel, false ); - if( fwc != null ) - { - Dispatcher.BeginInvoke( new Action( () => - { - if( startDrag ) - fwc.AttachDrag(); - fwc.Show(); - } ), DispatcherPriority.Send ); - } - } - - internal void StartDraggingFloatingWindowForPane( LayoutAnchorablePane paneModel ) - { - var fwc = this.CreateFloatingWindowForLayoutAnchorableWithoutParent( paneModel, false ); - if( fwc != null ) - { - fwc.AttachDrag(); - fwc.Show(); - } - } - - internal IEnumerable GetFloatingWindowsByZOrder() - { - IntPtr windowParentHanlde; - var parentWindow = Window.GetWindow( this ); - if( parentWindow != null ) - { - windowParentHanlde = new WindowInteropHelper( parentWindow ).Handle; - } - else - { - var mainProcess = Process.GetCurrentProcess(); - if( mainProcess == null ) - yield break; - - windowParentHanlde = mainProcess.MainWindowHandle; - } - - IntPtr currentHandle = Win32Helper.GetWindow( windowParentHanlde, ( uint )Win32Helper.GetWindow_Cmd.GW_HWNDFIRST ); - while( currentHandle != IntPtr.Zero ) - { - LayoutFloatingWindowControl ctrl = _fwList.FirstOrDefault( fw => new WindowInteropHelper( fw ).Handle == currentHandle ); - if( ctrl != null && ctrl.Model.Root != null && ctrl.Model.Root.Manager == this ) - yield return ctrl; - - currentHandle = Win32Helper.GetWindow( currentHandle, ( uint )Win32Helper.GetWindow_Cmd.GW_HWNDNEXT ); - } - } - - internal void RemoveFloatingWindow( LayoutFloatingWindowControl floatingWindow ) - { - _fwList.Remove( floatingWindow ); - } - - internal void _ExecuteCloseCommand( LayoutDocument document ) - { - if( DocumentClosing != null ) - { - var evargs = new DocumentClosingEventArgs( document ); - DocumentClosing( this, evargs ); - if( evargs.Cancel ) - return; - } - - if( document.CloseDocument() ) - { - this.RemoveViewFromLogicalChild( document ); - - if( DocumentClosed != null ) - { - var evargs = new DocumentClosedEventArgs( document ); - DocumentClosed( this, evargs ); - } - } - } - - internal void _ExecuteCloseAllButThisCommand( LayoutContent contentSelected ) - { - foreach( var contentToClose in Layout.Descendents().OfType().Where( d => d != contentSelected && ( d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow ) ).ToArray() ) - { - this.Close( contentToClose ); - } - } - - internal void _ExecuteCloseAllCommand( LayoutContent contentSelected ) - { - foreach( var contentToClose in Layout.Descendents().OfType().Where( d => ( d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow ) ).ToArray() ) - { - this.Close( contentToClose ); - } - } - - internal void _ExecuteCloseCommand( LayoutAnchorable anchorable ) - { - var model = anchorable as LayoutAnchorable; - if( model != null ) - { - model.CloseAnchorable(); - this.RemoveViewFromLogicalChild( anchorable ); - } - } - - internal void _ExecuteHideCommand( LayoutAnchorable anchorable ) - { - var model = anchorable as LayoutAnchorable; - if( model != null ) - { - model.Hide(); - } - } - - internal void _ExecuteAutoHideCommand( LayoutAnchorable _anchorable ) - { - _anchorable.ToggleAutoHide(); - } - - - internal void _ExecuteFloatCommand( LayoutContent contentToFloat ) - { - contentToFloat.Float(); - } - - internal void _ExecuteDockCommand( LayoutAnchorable anchorable ) - { - anchorable.Dock(); - } - - internal void _ExecuteDockAsDocumentCommand( LayoutContent content ) - { - content.DockAsDocument(); - } - - internal void _ExecuteContentActivateCommand( LayoutContent content ) - { - content.IsActive = true; - } - - #endregion - - #region Private Methods - - private void OnLayoutRootPropertyChanged( object sender, PropertyChangedEventArgs e ) - { - if( e.PropertyName == "RootPanel" ) - { - if( IsInitialized ) - { - var layoutRootPanel = CreateUIElementForModel( Layout.RootPanel ) as LayoutPanelControl; - LayoutRootPanel = layoutRootPanel; - } - } - else if( e.PropertyName == "ActiveContent" ) - { - if( Layout.ActiveContent != null ) - { - //set focus on active element only after a layout pass is completed - //it's possible that it is not yet visible in the visual tree - //if (_setFocusAsyncOperation == null) - //{ - // _setFocusAsyncOperation = Dispatcher.BeginInvoke(new Action(() => - // { - if( Layout.ActiveContent != null ) - FocusElementManager.SetFocusOnLastElement( Layout.ActiveContent ); - //_setFocusAsyncOperation = null; - // } ), DispatcherPriority.Input ); - //} - } - - if( !_insideInternalSetActiveContent ) - { - this.ActiveContent = ( Layout.ActiveContent != null ) ? Layout.ActiveContent.Content : null; - } - } - } - - private void OnLayoutRootUpdated( object sender, EventArgs e ) - { - CommandManager.InvalidateRequerySuggested(); - } - - private void OnLayoutChanging( LayoutRoot newLayout ) - { - if( LayoutChanging != null ) - LayoutChanging( this, EventArgs.Empty ); - } - - private void DockingManager_Loaded( object sender, RoutedEventArgs e ) - { - if( !DesignerProperties.GetIsInDesignMode( this ) ) - { - if( Layout.Manager == this ) - { - LayoutRootPanel = CreateUIElementForModel( Layout.RootPanel ) as LayoutPanelControl; - LeftSidePanel = CreateUIElementForModel( Layout.LeftSide ) as LayoutAnchorSideControl; - TopSidePanel = CreateUIElementForModel( Layout.TopSide ) as LayoutAnchorSideControl; - RightSidePanel = CreateUIElementForModel( Layout.RightSide ) as LayoutAnchorSideControl; - BottomSidePanel = CreateUIElementForModel( Layout.BottomSide ) as LayoutAnchorSideControl; - - // In order to prevent resource leaks, unsubscribe from SizeChanged event for case when we have no stored Layout settings. - SizeChanged -= OnSizeChanged; - SizeChanged += OnSizeChanged; - } - - SetupAutoHideWindow(); - - foreach( var fwc in _fwHiddenList ) - { - fwc.EnableBindings(); - if( fwc.KeepContentVisibleOnClose ) - { - fwc.Show(); - fwc.KeepContentVisibleOnClose = false; - } - - _fwList.Add( fwc ); - } - _fwHiddenList.Clear(); - - //load windows not already loaded! - foreach( var fw in Layout.FloatingWindows.Where( fw => !_fwList.Any( fwc => fwc.Model == fw ) ) ) - _fwList.Add( CreateUIElementForModel( fw ) as LayoutFloatingWindowControl ); - - //create the overlaywindow if it's possible - if( IsVisible ) - CreateOverlayWindow(); - FocusElementManager.SetupFocusManagement( this ); - } - } - - /// - /// Method executes when the control has changed its height and/or width. - /// - /// - /// - private void OnSizeChanged(object sender, SizeChangedEventArgs e) - { - // Lets make sure this always remains non-negative to avoid crach in layout system - double width = Math.Max(ActualWidth - GridSplitterWidth - RightSidePanel.ActualWidth - LeftSidePanel.ActualWidth, 0); - double height = Math.Max(ActualHeight - GridSplitterHeight - TopSidePanel.ActualHeight - BottomSidePanel.ActualHeight, 0); - - LayoutRootPanel.AdjustFixedChildrenPanelSizes(new Size(width, height)); - } - - private void DockingManager_Unloaded( object sender, RoutedEventArgs e ) - { - SizeChanged -= OnSizeChanged; - - if( !DesignerProperties.GetIsInDesignMode( this ) ) - { - if( _autoHideWindowManager != null ) - { - _autoHideWindowManager.HideAutoWindow(); - } - - if( AutoHideWindow != null ) - { - AutoHideWindow.Dispose(); - } - - foreach( var fw in _fwList.ToArray() ) - { - ////fw.Owner = null; - //fw.SetParentWindowToNull(); - //fw.KeepContentVisibleOnClose = true; - //// To avoid calling Close method multiple times. - //fw.InternalClose(true); - - // Unloaded can occure not only after closing of the application, but after switching between tabs. - // For such case it's better to hide the floating windows instead of closing it. - // We clear bindings on visibility during the owner is unloaded. - if( fw.IsVisible ) - { - fw.KeepContentVisibleOnClose = true; - fw.Hide(); - } - fw.DisableBindings(); - _fwHiddenList.Add( fw ); - } - - _fwList.Clear(); - - DestroyOverlayWindow(); - FocusElementManager.FinalizeFocusManagement( this ); - } - } - - private void SetupAutoHideWindow() - { - if( _autoHideWindowManager != null ) - _autoHideWindowManager.HideAutoWindow(); - else - _autoHideWindowManager = new AutoHideWindowManager( this ); - - if( AutoHideWindow != null ) - { - AutoHideWindow.Dispose(); - } - - SetAutoHideWindow( new LayoutAutoHideWindowControl() ); - } - - private void CreateOverlayWindow() - { - if( _overlayWindow == null ) - { - _overlayWindow = new OverlayWindow( this ); - } - Rect rectWindow = new Rect( this.PointToScreenDPIWithoutFlowDirection( new Point() ), this.TransformActualSizeToAncestor() ); - _overlayWindow.Left = rectWindow.Left; - _overlayWindow.Top = rectWindow.Top; - _overlayWindow.Width = rectWindow.Width; - _overlayWindow.Height = rectWindow.Height; - } - - private void DestroyOverlayWindow() - { - if( _overlayWindow != null ) - { - _overlayWindow.Close(); - _overlayWindow = null; - } - } - - private void AttachDocumentsSource( LayoutRoot layout, IEnumerable documentsSource ) - { - if( documentsSource == null ) - return; - - if( layout == null ) - return; - - //if (layout.Descendents().OfType().Any()) - // throw new InvalidOperationException("Unable to set the DocumentsSource property if LayoutDocument objects are already present in the model"); - var documentsImported = layout.Descendents().OfType().Select( d => d.Content ).ToArray(); - var documents = documentsSource as IEnumerable; - var listOfDocumentsToImport = new List( documents.OfType() ); - - foreach( var document in listOfDocumentsToImport.ToArray() ) - { - if( documentsImported.Contains( document ) ) - listOfDocumentsToImport.Remove( document ); - } - - - LayoutDocumentPane documentPane = null; - if( layout.LastFocusedDocument != null ) - { - documentPane = layout.LastFocusedDocument.Parent as LayoutDocumentPane; - } - - if( documentPane == null ) - { - documentPane = layout.Descendents().OfType().FirstOrDefault(); - } - - //if (documentPane == null) - // throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); - - _suspendLayoutItemCreation = true; - foreach( var documentContentToImport in listOfDocumentsToImport ) - { - - //documentPane.Children.Add(new LayoutDocument() { Content = documentToImport }); - - var documentToImport = new LayoutDocument() - { - Content = documentContentToImport - }; - - bool added = false; - if( LayoutUpdateStrategy != null ) - { - added = LayoutUpdateStrategy.BeforeInsertDocument( layout, documentToImport, documentPane ); - } - - if( !added ) - { - if( documentPane == null ) - throw new InvalidOperationException( "Layout must contains at least one LayoutDocumentPane in order to host documents" ); - - documentPane.Children.Add( documentToImport ); - added = true; - } - - if( LayoutUpdateStrategy != null ) - LayoutUpdateStrategy.AfterInsertDocument( layout, documentToImport ); - - - CreateDocumentLayoutItem( documentToImport ); - - } - _suspendLayoutItemCreation = false; - - - var documentsSourceAsNotifier = documentsSource as INotifyCollectionChanged; - if( documentsSourceAsNotifier != null ) - documentsSourceAsNotifier.CollectionChanged += new NotifyCollectionChangedEventHandler( documentsSourceElementsChanged ); - } - - private void documentsSourceElementsChanged( object sender, NotifyCollectionChangedEventArgs e ) - { - if( Layout == null ) - return; - - //When deserializing documents are created automatically by the deserializer - if( SuspendDocumentsSourceBinding ) - return; - - //handle remove - if( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || - e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) - { - if( e.OldItems != null ) - { - var documentsToRemove = Layout.Descendents().OfType().Where( d => e.OldItems.Contains( d.Content ) ).ToArray(); - foreach( var documentToRemove in documentsToRemove ) - { - ( documentToRemove.Parent as ILayoutContainer ).RemoveChild( - documentToRemove ); - this.RemoveViewFromLogicalChild( documentToRemove ); - } - } - } - - //handle add - if( e.NewItems != null && - ( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || - e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) ) - { - if( e.NewItems != null ) - { - LayoutDocumentPane documentPane = null; - if( Layout.LastFocusedDocument != null ) - { - documentPane = Layout.LastFocusedDocument.Parent as LayoutDocumentPane; - } - - if( documentPane == null ) - { - documentPane = Layout.Descendents().OfType().FirstOrDefault(); - } - - //if (documentPane == null) - // throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); - - _suspendLayoutItemCreation = true; - - foreach( var documentContentToImport in e.NewItems ) - { - var documentToImport = new LayoutDocument() - { - Content = documentContentToImport - }; - - bool added = false; - if( LayoutUpdateStrategy != null ) - { - added = LayoutUpdateStrategy.BeforeInsertDocument( Layout, documentToImport, documentPane ); - } - - if( !added ) - { - if( documentPane == null ) - throw new InvalidOperationException( "Layout must contains at least one LayoutDocumentPane in order to host documents" ); - - documentPane.Children.Add( documentToImport ); - added = true; - } - - if( LayoutUpdateStrategy != null ) - { - LayoutUpdateStrategy.AfterInsertDocument( Layout, documentToImport ); - } - - - var root = documentToImport.Root; - - if( root != null && root.Manager == this ) - { - CreateDocumentLayoutItem( documentToImport ); - } - } - _suspendLayoutItemCreation = false; - } - } - - if( e.Action == NotifyCollectionChangedAction.Reset ) - { - //NOTE: I'm going to clear every document present in layout but - //some documents may have been added directly to the layout, for now I clear them too - var documentsToRemove = Layout.Descendents().OfType().ToArray(); - foreach( var documentToRemove in documentsToRemove ) - { - ( documentToRemove.Parent as ILayoutContainer ).RemoveChild( - documentToRemove ); - this.RemoveViewFromLogicalChild( documentToRemove ); - } - } - - if( Layout != null ) - { - Layout.CollectGarbage(); - } - } - - private void DetachDocumentsSource( LayoutRoot layout, IEnumerable documentsSource ) - { - if( documentsSource == null ) - return; - - if( layout == null ) - return; - - var documentsToRemove = layout.Descendents().OfType() - .Where( d => documentsSource.Contains( d.Content ) ).ToArray(); - - foreach( var documentToRemove in documentsToRemove ) - { - ( documentToRemove.Parent as ILayoutContainer ).RemoveChild( - documentToRemove ); - this.RemoveViewFromLogicalChild( documentToRemove ); - } - - var documentsSourceAsNotifier = documentsSource as INotifyCollectionChanged; - if( documentsSourceAsNotifier != null ) - documentsSourceAsNotifier.CollectionChanged -= new NotifyCollectionChangedEventHandler( documentsSourceElementsChanged ); - } - - private void Close( LayoutContent contentToClose ) - { - if( !contentToClose.CanClose ) - return; - - var layoutItem = GetLayoutItemFromModel( contentToClose ); - if( layoutItem.CloseCommand != null ) - { - if( layoutItem.CloseCommand.CanExecute( null ) ) - layoutItem.CloseCommand.Execute( null ); - } - else - { - if( contentToClose is LayoutDocument ) - _ExecuteCloseCommand( contentToClose as LayoutDocument ); - else if( contentToClose is LayoutAnchorable ) - _ExecuteCloseCommand( contentToClose as LayoutAnchorable ); - } - } - - private void AttachAnchorablesSource( LayoutRoot layout, IEnumerable anchorablesSource ) - { - if( anchorablesSource == null ) - return; - - if( layout == null ) - return; - - //if (layout.Descendents().OfType().Any()) - // throw new InvalidOperationException("Unable to set the AnchorablesSource property if LayoutAnchorable objects are already present in the model"); - var anchorablesImported = layout.Descendents().OfType().Select( d => d.Content ).ToArray(); - var anchorables = anchorablesSource as IEnumerable; - var listOfAnchorablesToImport = new List( anchorables.OfType() ); - - foreach( var document in listOfAnchorablesToImport.ToArray() ) - { - if( anchorablesImported.Contains( document ) ) - listOfAnchorablesToImport.Remove( document ); - } - - LayoutAnchorablePane anchorablePane = null; - if( layout.ActiveContent != null ) - { - //look for active content parent pane - anchorablePane = layout.ActiveContent.Parent as LayoutAnchorablePane; - } - - if( anchorablePane == null ) - { - //look for a pane on the right side - anchorablePane = layout.Descendents().OfType().Where( pane => !pane.IsHostedInFloatingWindow && pane.GetSide() == AnchorSide.Right ).FirstOrDefault(); - } - - if( anchorablePane == null ) - { - //look for an available pane - anchorablePane = layout.Descendents().OfType().FirstOrDefault(); - } - - _suspendLayoutItemCreation = true; - foreach( var anchorableContentToImport in listOfAnchorablesToImport ) - { - var anchorableToImport = new LayoutAnchorable() - { - Content = anchorableContentToImport - }; - - bool added = false; - if( LayoutUpdateStrategy != null ) - { - added = LayoutUpdateStrategy.BeforeInsertAnchorable( layout, anchorableToImport, anchorablePane ); - } - - if( !added ) - { - if( anchorablePane == null ) - { - var mainLayoutPanel = new LayoutPanel() { Orientation = Orientation.Horizontal }; - if( layout.RootPanel != null ) - { - mainLayoutPanel.Children.Add( layout.RootPanel ); - } - - layout.RootPanel = mainLayoutPanel; - anchorablePane = new LayoutAnchorablePane() { DockWidth = new GridLength( 200.0, GridUnitType.Pixel ) }; - mainLayoutPanel.Children.Add( anchorablePane ); - } - - anchorablePane.Children.Add( anchorableToImport ); - added = true; - } - - if( LayoutUpdateStrategy != null ) - LayoutUpdateStrategy.AfterInsertAnchorable( layout, anchorableToImport ); - - - CreateAnchorableLayoutItem( anchorableToImport ); - - } - - _suspendLayoutItemCreation = false; - - var anchorablesSourceAsNotifier = anchorablesSource as INotifyCollectionChanged; - if( anchorablesSourceAsNotifier != null ) - anchorablesSourceAsNotifier.CollectionChanged += new NotifyCollectionChangedEventHandler( anchorablesSourceElementsChanged ); - } - - private void anchorablesSourceElementsChanged( object sender, NotifyCollectionChangedEventArgs e ) - { - if( Layout == null ) - return; - - //When deserializing documents are created automatically by the deserializer - if( SuspendAnchorablesSourceBinding ) - return; - - //handle remove - if( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || - e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) - { - if( e.OldItems != null ) - { - var anchorablesToRemove = Layout.Descendents().OfType().Where( d => e.OldItems.Contains( d.Content ) ).ToArray(); - foreach( var anchorableToRemove in anchorablesToRemove ) - { - anchorableToRemove.Content = null; - ( anchorableToRemove.Parent as ILayoutContainer ).RemoveChild( - anchorableToRemove ); - this.RemoveViewFromLogicalChild( anchorableToRemove ); - } - } - } - - //handle add - if( e.NewItems != null && - ( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || - e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) ) - { - if( e.NewItems != null ) - { - LayoutAnchorablePane anchorablePane = null; - - if( Layout.ActiveContent != null ) - { - //look for active content parent pane - anchorablePane = Layout.ActiveContent.Parent as LayoutAnchorablePane; - } - - if( anchorablePane == null ) - { - //look for a pane on the right side - anchorablePane = Layout.Descendents().OfType().Where( pane => !pane.IsHostedInFloatingWindow && pane.GetSide() == AnchorSide.Right ).FirstOrDefault(); - } - - if( anchorablePane == null ) - { - //look for an available pane - anchorablePane = Layout.Descendents().OfType().FirstOrDefault(); - } - - _suspendLayoutItemCreation = true; - foreach( var anchorableContentToImport in e.NewItems ) - { - var anchorableToImport = new LayoutAnchorable() - { - Content = anchorableContentToImport - }; - - bool added = false; - if( LayoutUpdateStrategy != null ) - { - added = LayoutUpdateStrategy.BeforeInsertAnchorable( Layout, anchorableToImport, anchorablePane ); - } - - if( !added ) - { - if( anchorablePane == null ) - { - var mainLayoutPanel = new LayoutPanel() { Orientation = Orientation.Horizontal }; - if( Layout.RootPanel != null ) - { - mainLayoutPanel.Children.Add( Layout.RootPanel ); - } - - Layout.RootPanel = mainLayoutPanel; - anchorablePane = new LayoutAnchorablePane() { DockWidth = new GridLength( 200.0, GridUnitType.Pixel ) }; - mainLayoutPanel.Children.Add( anchorablePane ); - } - - anchorablePane.Children.Add( anchorableToImport ); - added = true; - } - - if( LayoutUpdateStrategy != null ) - { - LayoutUpdateStrategy.AfterInsertAnchorable( Layout, anchorableToImport ); - } - - var root = anchorableToImport.Root; - - if( root != null && root.Manager == this ) - { - CreateAnchorableLayoutItem( anchorableToImport ); - } - - } - _suspendLayoutItemCreation = false; - } - } - - if( e.Action == NotifyCollectionChangedAction.Reset ) - { - //NOTE: I'm going to clear every anchorable present in layout but - //some anchorable may have been added directly to the layout, for now I clear them too - var anchorablesToRemove = Layout.Descendents().OfType().ToArray(); - foreach( var anchorableToRemove in anchorablesToRemove ) - { - ( anchorableToRemove.Parent as ILayoutContainer ).RemoveChild( - anchorableToRemove ); - this.RemoveViewFromLogicalChild( anchorableToRemove ); - } - } - - if( Layout != null ) - Layout.CollectGarbage(); - } - - private void DetachAnchorablesSource( LayoutRoot layout, IEnumerable anchorablesSource ) - { - if( anchorablesSource == null ) - return; - - if( layout == null ) - return; - - var anchorablesToRemove = layout.Descendents().OfType() - .Where( d => anchorablesSource.Contains( d.Content ) ).ToArray(); - - foreach( var anchorableToRemove in anchorablesToRemove ) - { - ( anchorableToRemove.Parent as ILayoutContainer ).RemoveChild( - anchorableToRemove ); - this.RemoveViewFromLogicalChild( anchorableToRemove ); - } - - var anchorablesSourceAsNotifier = anchorablesSource as INotifyCollectionChanged; - if( anchorablesSourceAsNotifier != null ) - anchorablesSourceAsNotifier.CollectionChanged -= new NotifyCollectionChangedEventHandler( anchorablesSourceElementsChanged ); - } - - private void RemoveViewFromLogicalChild( LayoutContent layoutContent ) - { - if( layoutContent == null ) - return; - - var layoutItem = this.GetLayoutItemFromModel( layoutContent ); - if( layoutItem != null ) - { - if( layoutItem.IsViewExists() ) - { - this.InternalRemoveLogicalChild( layoutItem.View ); - } - } - } - - private void InternalSetActiveContent( object contentObject ) - { - var layoutContent = Layout.Descendents().OfType().FirstOrDefault( lc => lc == contentObject || lc.Content == contentObject ); - _insideInternalSetActiveContent = true; - Layout.ActiveContent = layoutContent; - _insideInternalSetActiveContent = false; - } - - private void DetachLayoutItems() - { - if( Layout != null ) - { - _layoutItems.ForEach( i => i.Detach() ); - _layoutItems.Clear(); - Layout.ElementAdded -= new EventHandler( Layout_ElementAdded ); - Layout.ElementRemoved -= new EventHandler( Layout_ElementRemoved ); - } - } - - private void Layout_ElementRemoved( object sender, LayoutElementEventArgs e ) - { - if( _suspendLayoutItemCreation ) - return; - - CollectLayoutItemsDeleted(); - } - - private void Layout_ElementAdded( object sender, LayoutElementEventArgs e ) - { - if( _suspendLayoutItemCreation ) - return; - - foreach( var content in Layout.Descendents().OfType() ) - { - if( content is LayoutDocument ) - CreateDocumentLayoutItem( content as LayoutDocument ); - else //if (content is LayoutAnchorable) - CreateAnchorableLayoutItem( content as LayoutAnchorable ); - } - - CollectLayoutItemsDeleted(); - } - - private void CollectLayoutItemsDeleted() - { - if( _collectLayoutItemsOperations != null ) - return; - _collectLayoutItemsOperations = Dispatcher.BeginInvoke( new Action( () => - { - _collectLayoutItemsOperations = null; - foreach( var itemToRemove in _layoutItems.Where( item => item.LayoutElement.Root != Layout ).ToArray() ) - { - - if( itemToRemove != null && - itemToRemove.Model != null && - itemToRemove.Model is UIElement ) - { - //((ILogicalChildrenContainer)this).InternalRemoveLogicalChild(itemToRemove.Model as UIElement); - } - - itemToRemove.Detach(); - _layoutItems.Remove( itemToRemove ); - - } - } ) ); - } - - private void AttachLayoutItems() - { - if( Layout != null ) - { - foreach( var document in Layout.Descendents().OfType().ToArray() ) - { - CreateDocumentLayoutItem( document ); - //var documentItem = new LayoutDocumentItem(); - //documentItem.Attach(document); - //ApplyStyleToLayoutItem(documentItem); - //_layoutItems.Add(documentItem); - } - foreach( var anchorable in Layout.Descendents().OfType().ToArray() ) - { - CreateAnchorableLayoutItem( anchorable ); - //var anchorableItem = new LayoutAnchorableItem(); - //anchorableItem.Attach(anchorable); - //ApplyStyleToLayoutItem(anchorableItem); - //_layoutItems.Add(anchorableItem); - } - - Layout.ElementAdded += new EventHandler( Layout_ElementAdded ); - Layout.ElementRemoved += new EventHandler( Layout_ElementRemoved ); - } - } - - private void ApplyStyleToLayoutItem( LayoutItem layoutItem ) - { - layoutItem._ClearDefaultBindings(); - if( LayoutItemContainerStyle != null ) - layoutItem.Style = LayoutItemContainerStyle; - else if( LayoutItemContainerStyleSelector != null ) - layoutItem.Style = LayoutItemContainerStyleSelector.SelectStyle( layoutItem.Model, layoutItem ); - layoutItem._SetDefaultBindings(); - } - - private void CreateAnchorableLayoutItem( LayoutAnchorable contentToAttach ) - { - if( _layoutItems.Any( item => item.LayoutElement == contentToAttach ) ) - { - foreach( var item in _layoutItems ) - { - ApplyStyleToLayoutItem( item ); - } - return; - } - - var layoutItem = new LayoutAnchorableItem(); - layoutItem.Attach( contentToAttach ); - _layoutItems.Add( layoutItem ); - ApplyStyleToLayoutItem( layoutItem ); - - if( contentToAttach != null && - contentToAttach.Content != null && - contentToAttach.Content is UIElement ) - { - InternalAddLogicalChild( contentToAttach.Content ); - } - - } - - private void CreateDocumentLayoutItem( LayoutDocument contentToAttach ) - { - if( _layoutItems.Any( item => item.LayoutElement == contentToAttach ) ) - { - foreach( var item in _layoutItems ) - { - ApplyStyleToLayoutItem( item ); - } - return; - } - - var layoutItem = new LayoutDocumentItem(); - layoutItem.Attach( contentToAttach ); - _layoutItems.Add( layoutItem ); - ApplyStyleToLayoutItem( layoutItem ); - - if( contentToAttach != null && - contentToAttach.Content != null && - contentToAttach.Content is UIElement ) - { - InternalAddLogicalChild( contentToAttach.Content ); - } - - } - - private void ShowNavigatorWindow() - { - if( _navigatorWindow == null ) - { - _navigatorWindow = new NavigatorWindow( this ) - { - Owner = Window.GetWindow( this ), - WindowStartupLocation = WindowStartupLocation.CenterOwner - }; - } - - _navigatorWindow.ShowDialog(); - _navigatorWindow = null; - } - - private LayoutFloatingWindowControl CreateFloatingWindowForLayoutAnchorableWithoutParent( LayoutAnchorablePane paneModel, bool isContentImmutable ) - { - if( paneModel.Children.Any( c => !c.CanFloat ) ) - return null; - var paneAsPositionableElement = paneModel as ILayoutPositionableElement; - var paneAsWithActualSize = paneModel as ILayoutPositionableElementWithActualSize; - - double fwWidth = paneAsPositionableElement.FloatingWidth; - double fwHeight = paneAsPositionableElement.FloatingHeight; - double fwLeft = paneAsPositionableElement.FloatingLeft; - double fwTop = paneAsPositionableElement.FloatingTop; - - if( fwWidth == 0.0 ) - fwWidth = paneAsWithActualSize.ActualWidth + 10; //10 includes BorderThickness and Margins inside LayoutAnchorableFloatingWindowControl. - if( fwHeight == 0.0 ) - fwHeight = paneAsWithActualSize.ActualHeight + 10; //10 includes BorderThickness and Margins inside LayoutAnchorableFloatingWindowControl. - - var destPane = new LayoutAnchorablePane() - { - DockWidth = paneAsPositionableElement.DockWidth, - DockHeight = paneAsPositionableElement.DockHeight, - DockMinHeight = paneAsPositionableElement.DockMinHeight, - DockMinWidth = paneAsPositionableElement.DockMinWidth, - FloatingLeft = paneAsPositionableElement.FloatingLeft, - FloatingTop = paneAsPositionableElement.FloatingTop, - FloatingWidth = paneAsPositionableElement.FloatingWidth, - FloatingHeight = paneAsPositionableElement.FloatingHeight, - }; - - bool savePreviousContainer = paneModel.FindParent() == null; - int currentSelectedContentIndex = paneModel.SelectedContentIndex; - while( paneModel.Children.Count > 0 ) - { - var contentModel = paneModel.Children[ paneModel.Children.Count - 1 ] as LayoutAnchorable; - - if( savePreviousContainer ) - { - var contentModelAsPreviousContainer = contentModel as ILayoutPreviousContainer; - contentModelAsPreviousContainer.PreviousContainer = paneModel; - contentModel.PreviousContainerIndex = paneModel.Children.Count - 1; - } - - paneModel.RemoveChildAt( paneModel.Children.Count - 1 ); - destPane.Children.Insert( 0, contentModel ); - } - - if( destPane.Children.Count > 0 ) - { - destPane.SelectedContentIndex = currentSelectedContentIndex; - } - - - LayoutFloatingWindow fw; - LayoutFloatingWindowControl fwc; - fw = new LayoutAnchorableFloatingWindow() - { - RootPanel = new LayoutAnchorablePaneGroup( - destPane ) - { - DockHeight = destPane.DockHeight, - DockWidth = destPane.DockWidth, - DockMinHeight = destPane.DockMinHeight, - DockMinWidth = destPane.DockMinWidth, - } - }; - - Layout.FloatingWindows.Add( fw ); - - fwc = new LayoutAnchorableFloatingWindowControl( - fw as LayoutAnchorableFloatingWindow, isContentImmutable ) - { - Width = fwWidth, - Height = fwHeight, - Top = fwTop, - Left = fwLeft - }; - - - - //fwc.Owner = Window.GetWindow(this); - //fwc.SetParentToMainWindowOf(this); - - - _fwList.Add( fwc ); - - Layout.CollectGarbage(); - - InvalidateArrange(); - - return fwc; - } - - private LayoutFloatingWindowControl CreateFloatingWindowCore( LayoutContent contentModel, bool isContentImmutable ) - { - if( !contentModel.CanFloat ) - return null; - var contentModelAsAnchorable = contentModel as LayoutAnchorable; - if( contentModelAsAnchorable != null && - contentModelAsAnchorable.IsAutoHidden ) - contentModelAsAnchorable.ToggleAutoHide(); - - var parentPane = contentModel.Parent as ILayoutPane; - var parentPaneAsPositionableElement = contentModel.Parent as ILayoutPositionableElement; - var parentPaneAsWithActualSize = contentModel.Parent as ILayoutPositionableElementWithActualSize; - var contentModelParentChildrenIndex = parentPane.Children.ToList().IndexOf( contentModel ); - - if( contentModel.FindParent() == null ) - { - ( (ILayoutPreviousContainer)contentModel ).PreviousContainer = parentPane; - contentModel.PreviousContainerIndex = contentModelParentChildrenIndex; - } - - parentPane.RemoveChildAt( contentModelParentChildrenIndex ); - - double fwWidth = contentModel.FloatingWidth; - double fwHeight = contentModel.FloatingHeight; - - if( fwWidth == 0.0 ) - fwWidth = parentPaneAsPositionableElement.FloatingWidth; - if( fwHeight == 0.0 ) - fwHeight = parentPaneAsPositionableElement.FloatingHeight; - - if( fwWidth == 0.0 ) - fwWidth = parentPaneAsWithActualSize.ActualWidth + 10; //10 includes BorderThickness and Margins inside LayoutDocumentFloatingWindowControl. - if( fwHeight == 0.0 ) - fwHeight = parentPaneAsWithActualSize.ActualHeight + 10; //10 includes BorderThickness and Margins inside LayoutDocumentFloatingWindowControl. - - LayoutFloatingWindow fw; - LayoutFloatingWindowControl fwc; - if( contentModel is LayoutAnchorable ) - { - var anchorableContent = contentModel as LayoutAnchorable; - fw = new LayoutAnchorableFloatingWindow() - { - RootPanel = new LayoutAnchorablePaneGroup( - new LayoutAnchorablePane( anchorableContent ) - { - DockWidth = parentPaneAsPositionableElement.DockWidth, - DockHeight = parentPaneAsPositionableElement.DockHeight, - DockMinHeight = parentPaneAsPositionableElement.DockMinHeight, - DockMinWidth = parentPaneAsPositionableElement.DockMinWidth, - FloatingLeft = parentPaneAsPositionableElement.FloatingLeft, - FloatingTop = parentPaneAsPositionableElement.FloatingTop, - FloatingWidth = parentPaneAsPositionableElement.FloatingWidth, - FloatingHeight = parentPaneAsPositionableElement.FloatingHeight, - } ) - }; - - Layout.FloatingWindows.Add( fw ); - - fwc = new LayoutAnchorableFloatingWindowControl( - fw as LayoutAnchorableFloatingWindow, isContentImmutable ) - { - Width = fwWidth, - Height = fwHeight, - Left = contentModel.FloatingLeft, - Top = contentModel.FloatingTop - }; - } - else - { - var anchorableDocument = contentModel as LayoutDocument; - fw = new LayoutDocumentFloatingWindow() - { - RootPanel = new LayoutDocumentPaneGroup( - new LayoutDocumentPane(anchorableDocument) - { - DockWidth = parentPaneAsPositionableElement.DockWidth, - DockHeight = parentPaneAsPositionableElement.DockHeight, - DockMinHeight = parentPaneAsPositionableElement.DockMinHeight, - DockMinWidth = parentPaneAsPositionableElement.DockMinWidth, - FloatingLeft = parentPaneAsPositionableElement.FloatingLeft, - FloatingTop = parentPaneAsPositionableElement.FloatingTop, - FloatingWidth = parentPaneAsPositionableElement.FloatingWidth, - FloatingHeight = parentPaneAsPositionableElement.FloatingHeight, - }) - }; - - Layout.FloatingWindows.Add( fw ); - - fwc = new LayoutDocumentFloatingWindowControl( - fw as LayoutDocumentFloatingWindow, isContentImmutable ) - { - Width = fwWidth, - Height = fwHeight, - Left = contentModel.FloatingLeft, - Top = contentModel.FloatingTop - }; - } - - //fwc.Owner = Window.GetWindow(this); - //fwc.SetParentToMainWindowOf(this); - - _fwList.Add( fwc ); - - Layout.CollectGarbage(); - - UpdateLayout(); - - return fwc; - } - - #endregion - - #region Events - - /// - /// Event fired when property changes - /// - public event EventHandler LayoutChanged; - - /// - /// Event fired when property is about to be changed - /// - public event EventHandler LayoutChanging; - - /// - /// Event fired when a document is about to be closed - /// - /// Subscribers have the opportuniy to cancel the operation. - public event EventHandler DocumentClosing; - - /// - /// Event fired after a document is closed - /// - public event EventHandler DocumentClosed; - - public event EventHandler ActiveContentChanged; - - #endregion - - #region IOverlayWindowHost Interface - - bool IOverlayWindowHost.HitTest( Point dragPoint ) - { - Rect detectionRect = new Rect( this.PointToScreenDPIWithoutFlowDirection( new Point() ), this.TransformActualSizeToAncestor() ); - return detectionRect.Contains( dragPoint ); - } - - DockingManager IOverlayWindowHost.Manager - { - get - { - return this; - } - } - - IOverlayWindow IOverlayWindowHost.ShowOverlayWindow( LayoutFloatingWindowControl draggingWindow ) - { - CreateOverlayWindow(); - _overlayWindow.Owner = draggingWindow; - _overlayWindow.EnableDropTargets(); - _overlayWindow.Show(); - return _overlayWindow; - } - - void IOverlayWindowHost.HideOverlayWindow() - { - _areas = null; - _overlayWindow.Owner = null; - _overlayWindow.HideDropTargets(); - } - - IEnumerable IOverlayWindowHost.GetDropAreas( LayoutFloatingWindowControl draggingWindow ) - { - if( _areas != null ) - return _areas; - - bool isDraggingDocuments = draggingWindow.Model is LayoutDocumentFloatingWindow; - - _areas = new List(); - - if( !isDraggingDocuments ) - { - _areas.Add( new DropArea( - this, - DropAreaType.DockingManager ) ); - - foreach( var areaHost in this.FindVisualChildren() ) - { - if( areaHost.Model.Descendents().Any() ) - { - _areas.Add( new DropArea( - areaHost, - DropAreaType.AnchorablePane ) ); - } - } - } - - // Determine if floatingWindow is configured to dock as document or not - bool dockAsDocument = true; - if (isDraggingDocuments == false) - { - var toolWindow = draggingWindow.Model as LayoutAnchorableFloatingWindow; - if (toolWindow != null) - { - foreach (var item in GetAnchorableInFloatingWindow(draggingWindow)) - { - if (item.CanDockAsTabbedDocument == false) - { - dockAsDocument = false; - break; - } - } - } - } - - // Dock only documents and tools in DocumentPane if configuration does allow that - if (dockAsDocument == true) - { - foreach( var areaHost in this.FindVisualChildren() ) - { - _areas.Add( new DropArea( - areaHost, - DropAreaType.DocumentPane ) ); - } - } - - foreach( var areaHost in this.FindVisualChildren() ) - { - var documentGroupModel = areaHost.Model as LayoutDocumentPaneGroup; - if( documentGroupModel.Children.Where( c => c.IsVisible ).Count() == 0 ) - { - _areas.Add( new DropArea( - areaHost, - DropAreaType.DocumentPaneGroup ) ); - } - } - - return _areas; - } - - /// - /// Finds all objects (toolwindows) within a - /// (if any) and return them. - /// - /// - /// - private IEnumerable GetAnchorableInFloatingWindow(LayoutFloatingWindowControl draggingWindow) - { - var layoutAnchorableFloatingWindow = draggingWindow.Model as LayoutAnchorableFloatingWindow; - if (layoutAnchorableFloatingWindow != null) - { - //big part of code for getting type - var layoutAnchorablePane = layoutAnchorableFloatingWindow.SinglePane as LayoutAnchorablePane; - - if (layoutAnchorablePane != null - && (layoutAnchorableFloatingWindow.IsSinglePane - && layoutAnchorablePane.SelectedContent != null)) - { - var layoutAnchorable = ((LayoutAnchorablePane)layoutAnchorableFloatingWindow.SinglePane).SelectedContent as LayoutAnchorable; - yield return layoutAnchorable; - } - else - { - foreach (var item in GetLayoutAnchorable(layoutAnchorableFloatingWindow.RootPanel)) - { - yield return item; - } - } - } - } - - /// - /// Finds all objects (toolwindows) within a - /// (if any) and return them. - /// - /// - /// - internal IEnumerable GetLayoutAnchorable(LayoutAnchorablePaneGroup layoutAnchPaneGroup) - { - if (layoutAnchPaneGroup != null) - { - foreach (var anchorable in layoutAnchPaneGroup.Descendents().OfType()) - { - yield return anchorable; - } - } - } - #endregion - } + if (_logicalChildren.Select(ch => ch.GetValueOrDefault()).Contains(element)) + return; + + _logicalChildren.Add(new WeakReference(element)); + AddLogicalChild(element); + } + + internal void InternalRemoveLogicalChild(object element) + { + var wrToRemove = _logicalChildren.FirstOrDefault(ch => ch.GetValueOrDefault() == element); + if (wrToRemove != null) + _logicalChildren.Remove(wrToRemove); + RemoveLogicalChild(element); + } + + private void ClearLogicalChildrenList() + { + foreach (var child in _logicalChildren.Select(ch => ch.GetValueOrDefault()).ToArray()) + RemoveLogicalChild(child); + _logicalChildren.Clear(); + } + + #endregion + + #region AutoHideWindow + + /// + /// AutoHideWindow Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey AutoHideWindowPropertyKey = DependencyProperty.RegisterReadOnly("AutoHideWindow", typeof(LayoutAutoHideWindowControl), typeof(DockingManager), + new FrameworkPropertyMetadata((LayoutAutoHideWindowControl)null, new PropertyChangedCallback(OnAutoHideWindowChanged))); + + public static readonly DependencyProperty AutoHideWindowProperty = AutoHideWindowPropertyKey.DependencyProperty; + + /// + /// Gets the AutoHideWindow property. This dependency property + /// indicates the currently shown autohide window. + /// + public LayoutAutoHideWindowControl AutoHideWindow + { + get + { + return (LayoutAutoHideWindowControl)GetValue(AutoHideWindowProperty); + } + } + + /// + /// Provides a secure method for setting the AutoHideWindow property. + /// This dependency property indicates the currently shown autohide window. + /// + /// The new value for the property. + protected void SetAutoHideWindow(LayoutAutoHideWindowControl value) + { + SetValue(AutoHideWindowPropertyKey, value); + } + + /// + /// Handles changes to the AutoHideWindow property. + /// + private static void OnAutoHideWindowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAutoHideWindowChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AutoHideWindow property. + /// + protected virtual void OnAutoHideWindowChanged(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue != null) + InternalRemoveLogicalChild(e.OldValue); + if (e.NewValue != null) + InternalAddLogicalChild(e.NewValue); + + } + + #endregion + + #region Floating Windows + + public IEnumerable FloatingWindows + { + get + { + return _fwList; + } + } + + #endregion + + #region LayoutItemTemplate + + /// + /// LayoutItemTemplate Dependency Property + /// + public static readonly DependencyProperty LayoutItemTemplateProperty = DependencyProperty.Register("LayoutItemTemplate", typeof(DataTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplate)null, new PropertyChangedCallback(OnLayoutItemTemplateChanged))); + + /// + /// Gets or sets the AnchorableTemplate property. This dependency property + /// indicates the template to use to render anchorable and document contents. + /// + public DataTemplate LayoutItemTemplate + { + get + { + return (DataTemplate)GetValue(LayoutItemTemplateProperty); + } + set + { + SetValue(LayoutItemTemplateProperty, value); + } + } + + /// + /// Handles changes to the AnchorableTemplate property. + /// + private static void OnLayoutItemTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnLayoutItemTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorableTemplate property. + /// + protected virtual void OnLayoutItemTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + #endregion + + #region LayoutItemTemplateSelector + + /// + /// LayoutItemTemplateSelector Dependency Property + /// + public static readonly DependencyProperty LayoutItemTemplateSelectorProperty = DependencyProperty.Register("LayoutItemTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplateSelector)null, new PropertyChangedCallback(OnLayoutItemTemplateSelectorChanged))); + + /// + /// Gets or sets the LayoutItemTemplateSelector property. This dependency property + /// indicates selector object to use for anchorable templates. + /// + public DataTemplateSelector LayoutItemTemplateSelector + { + get + { + return (DataTemplateSelector)GetValue(LayoutItemTemplateSelectorProperty); + } + set + { + SetValue(LayoutItemTemplateSelectorProperty, value); + } + } + + /// + /// Handles changes to the LayoutItemTemplateSelector property. + /// + private static void OnLayoutItemTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnLayoutItemTemplateSelectorChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the LayoutItemTemplateSelector property. + /// + protected virtual void OnLayoutItemTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) + { + } + + #endregion + + #region DocumentsSource + + /// + /// DocumentsSource Dependency Property + /// + public static readonly DependencyProperty DocumentsSourceProperty = DependencyProperty.Register("DocumentsSource", typeof(IEnumerable), typeof(DockingManager), + new FrameworkPropertyMetadata((IEnumerable)null, new PropertyChangedCallback(OnDocumentsSourceChanged))); + + /// + /// Gets or sets the DocumentsSource property. This dependency property + /// indicates the source collection of documents. + /// + public IEnumerable DocumentsSource + { + get + { + return (IEnumerable)GetValue(DocumentsSourceProperty); + } + set + { + SetValue(DocumentsSourceProperty, value); + } + } + + /// + /// Handles changes to the DocumentsSource property. + /// + private static void OnDocumentsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentsSourceChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentsSource property. + /// + protected virtual void OnDocumentsSourceChanged(DependencyPropertyChangedEventArgs e) + { + DetachDocumentsSource(Layout, e.OldValue as IEnumerable); + AttachDocumentsSource(Layout, e.NewValue as IEnumerable); + } + + #endregion + + #region DocumentContextMenu + + /// + /// DocumentContextMenu Dependency Property + /// + public static readonly DependencyProperty DocumentContextMenuProperty = DependencyProperty.Register("DocumentContextMenu", typeof(ContextMenu), typeof(DockingManager), + new FrameworkPropertyMetadata((ContextMenu)null)); + + /// + /// Gets or sets the DocumentContextMenu property. This dependency property + /// indicates context menu to show for documents. + /// + public ContextMenu DocumentContextMenu + { + get + { + return (ContextMenu)GetValue(DocumentContextMenuProperty); + } + set + { + SetValue(DocumentContextMenuProperty, value); + } + } + + #endregion + + #region AnchorablesSource + + /// + /// AnchorablesSource Dependency Property + /// + public static readonly DependencyProperty AnchorablesSourceProperty = DependencyProperty.Register("AnchorablesSource", typeof(IEnumerable), typeof(DockingManager), + new FrameworkPropertyMetadata((IEnumerable)null, new PropertyChangedCallback(OnAnchorablesSourceChanged))); + + /// + /// Gets or sets the AnchorablesSource property. This dependency property + /// indicates source collection of anchorables. + /// + public IEnumerable AnchorablesSource + { + get + { + return (IEnumerable)GetValue(AnchorablesSourceProperty); + } + set + { + SetValue(AnchorablesSourceProperty, value); + } + } + + /// + /// Handles changes to the AnchorablesSource property. + /// + private static void OnAnchorablesSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAnchorablesSourceChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorablesSource property. + /// + protected virtual void OnAnchorablesSourceChanged(DependencyPropertyChangedEventArgs e) + { + DetachAnchorablesSource(Layout, e.OldValue as IEnumerable); + AttachAnchorablesSource(Layout, e.NewValue as IEnumerable); + } + + + + #endregion + + #region ActiveContent + + /// + /// ActiveContent Dependency Property + /// + public static readonly DependencyProperty ActiveContentProperty = DependencyProperty.Register("ActiveContent", typeof(object), typeof(DockingManager), + new FrameworkPropertyMetadata((object)null, new PropertyChangedCallback(OnActiveContentChanged))); + + /// + /// Gets or sets the ActiveContent property. This dependency property + /// indicates the content currently active. + /// + public object ActiveContent + { + get + { + return (object)GetValue(ActiveContentProperty); + } + set + { + SetValue(ActiveContentProperty, value); + } + } + + /// + /// Handles changes to the ActiveContent property. + /// + private static void OnActiveContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).InternalSetActiveContent(e.NewValue); + ((DockingManager)d).OnActiveContentChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the ActiveContent property. + /// + protected virtual void OnActiveContentChanged(DependencyPropertyChangedEventArgs e) + { + if (ActiveContentChanged != null) + ActiveContentChanged(this, EventArgs.Empty); + } + + #endregion + + #region AnchorableContextMenu + + /// + /// AnchorableContextMenu Dependency Property + /// + public static readonly DependencyProperty AnchorableContextMenuProperty = DependencyProperty.Register("AnchorableContextMenu", typeof(ContextMenu), typeof(DockingManager), + new FrameworkPropertyMetadata((ContextMenu)null)); + + /// + /// Gets or sets the AnchorableContextMenu property. This dependency property + /// indicates the context menu to show up for anchorables. + /// + public ContextMenu AnchorableContextMenu + { + get + { + return (ContextMenu)GetValue(AnchorableContextMenuProperty); + } + set + { + SetValue(AnchorableContextMenuProperty, value); + } + } + + #endregion + + #region Theme + + /// + /// Theme Dependency Property + /// + public static readonly DependencyProperty ThemeProperty = DependencyProperty.Register("Theme", typeof(Theme), typeof(DockingManager), + new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnThemeChanged))); + + /// + /// Gets or sets the Theme property. This dependency property + /// indicates the theme to use for AvalonDock controls. + /// + public Theme Theme + { + get + { + return (Theme)GetValue(ThemeProperty); + } + set + { + SetValue(ThemeProperty, value); + } + } + + /// + /// Handles changes to the Theme property. + /// + private static void OnThemeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnThemeChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the Theme property. + /// + protected virtual void OnThemeChanged(DependencyPropertyChangedEventArgs e) + { + var oldTheme = e.OldValue as Theme; + var newTheme = e.NewValue as Theme; + var resources = this.Resources; + if (oldTheme != null) + { + if (oldTheme is DictionaryTheme) + { + if (currentThemeResourceDictionary != null) + { + resources.MergedDictionaries.Remove(currentThemeResourceDictionary); + currentThemeResourceDictionary = null; + } + } + else + { + var resourceDictionaryToRemove = + resources.MergedDictionaries.FirstOrDefault(r => r.Source == oldTheme.GetResourceUri()); + if (resourceDictionaryToRemove != null) + resources.MergedDictionaries.Remove( + resourceDictionaryToRemove); + } + } + + if (newTheme != null) + { + if (newTheme is DictionaryTheme) + { + currentThemeResourceDictionary = ((DictionaryTheme)newTheme).ThemeResourceDictionary; + resources.MergedDictionaries.Add(currentThemeResourceDictionary); + } + else + { + resources.MergedDictionaries.Add(new ResourceDictionary() { Source = newTheme.GetResourceUri() }); + } + } + + foreach (var fwc in _fwList) + fwc.UpdateThemeResources(oldTheme); + + if (_navigatorWindow != null) + _navigatorWindow.UpdateThemeResources(); + + if (_overlayWindow != null) + _overlayWindow.UpdateThemeResources(); + } + + #endregion + + #region GridSplitterWidth + + /// + /// GridSplitterWidth Dependency Property + /// + public static readonly DependencyProperty GridSplitterWidthProperty = DependencyProperty.Register("GridSplitterWidth", typeof(double), typeof(DockingManager), + new FrameworkPropertyMetadata((double)6.0)); + + /// + /// Gets or sets the GridSplitterWidth property. This dependency property + /// indicates width of grid splitters. + /// + public double GridSplitterWidth + { + get + { + return (double)GetValue(GridSplitterWidthProperty); + } + set + { + SetValue(GridSplitterWidthProperty, value); + } + } + + #endregion + + #region GridSplitterHeight + + /// + /// GridSplitterHeight Dependency Property + /// + public static readonly DependencyProperty GridSplitterHeightProperty = DependencyProperty.Register("GridSplitterHeight", typeof(double), typeof(DockingManager), + new FrameworkPropertyMetadata((double)6.0)); + + /// + /// Gets or sets the GridSplitterHeight property. This dependency property + /// indicates height of grid splitters. + /// + public double GridSplitterHeight + { + get + { + return (double)GetValue(GridSplitterHeightProperty); + } + set + { + SetValue(GridSplitterHeightProperty, value); + } + } + + #endregion + + #region DocumentPaneMenuItemHeaderTemplate + + /// + /// DocumentPaneMenuItemHeaderTemplate Dependency Property + /// + public static readonly DependencyProperty DocumentPaneMenuItemHeaderTemplateProperty = DependencyProperty.Register("DocumentPaneMenuItemHeaderTemplate", typeof(DataTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplate)null, new PropertyChangedCallback(OnDocumentPaneMenuItemHeaderTemplateChanged), new CoerceValueCallback(CoerceDocumentPaneMenuItemHeaderTemplateValue))); + + /// + /// Gets or sets the DocumentPaneMenuItemHeaderTemplate property. This dependency property + /// indicates the header template to use while creating menu items for the document panes. + /// + public DataTemplate DocumentPaneMenuItemHeaderTemplate + { + get + { + return (DataTemplate)GetValue(DocumentPaneMenuItemHeaderTemplateProperty); + } + set + { + SetValue(DocumentPaneMenuItemHeaderTemplateProperty, value); + } + } + + /// + /// Handles changes to the DocumentPaneMenuItemHeaderTemplate property. + /// + private static void OnDocumentPaneMenuItemHeaderTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentPaneMenuItemHeaderTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentPaneMenuItemHeaderTemplate property. + /// + protected virtual void OnDocumentPaneMenuItemHeaderTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the DocumentPaneMenuItemHeaderTemplate value. + /// + private static object CoerceDocumentPaneMenuItemHeaderTemplateValue(DependencyObject d, object value) + { + if (value != null && + d.GetValue(DocumentPaneMenuItemHeaderTemplateSelectorProperty) != null) + return null; + if (value == null) + return d.GetValue(DocumentHeaderTemplateProperty); + + return value; + } + + #endregion + + #region DocumentPaneMenuItemHeaderTemplateSelector + + /// + /// DocumentPaneMenuItemHeaderTemplateSelector Dependency Property + /// + public static readonly DependencyProperty DocumentPaneMenuItemHeaderTemplateSelectorProperty = DependencyProperty.Register("DocumentPaneMenuItemHeaderTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplateSelector)null, new PropertyChangedCallback(OnDocumentPaneMenuItemHeaderTemplateSelectorChanged), new CoerceValueCallback(CoerceDocumentPaneMenuItemHeaderTemplateSelectorValue))); + + /// + /// Gets or sets the DocumentPaneMenuItemHeaderTemplateSelector property. This dependency property + /// indicates the data template selector to use for the menu items show when user select the DocumentPane document switch context menu. + /// + public DataTemplateSelector DocumentPaneMenuItemHeaderTemplateSelector + { + get + { + return (DataTemplateSelector)GetValue(DocumentPaneMenuItemHeaderTemplateSelectorProperty); + } + set + { + SetValue(DocumentPaneMenuItemHeaderTemplateSelectorProperty, value); + } + } + + /// + /// Handles changes to the DocumentPaneMenuItemHeaderTemplateSelector property. + /// + private static void OnDocumentPaneMenuItemHeaderTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentPaneMenuItemHeaderTemplateSelectorChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentPaneMenuItemHeaderTemplateSelector property. + /// + protected virtual void OnDocumentPaneMenuItemHeaderTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) + { + if (e.NewValue != null && + DocumentPaneMenuItemHeaderTemplate != null) + DocumentPaneMenuItemHeaderTemplate = null; + + } + + /// + /// Coerces the DocumentPaneMenuItemHeaderTemplateSelector value. + /// + private static object CoerceDocumentPaneMenuItemHeaderTemplateSelectorValue(DependencyObject d, object value) + { + return value; + } + + #endregion + + #region IconContentTemplate + + /// + /// IconContentTemplate Dependency Property + /// + public static readonly DependencyProperty IconContentTemplateProperty = DependencyProperty.Register("IconContentTemplate", typeof(DataTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplate)null)); + + /// + /// Gets or sets the IconContentTemplate property. This dependency property + /// indicates the data template to use while extracting the icon from model. + /// + public DataTemplate IconContentTemplate + { + get + { + return (DataTemplate)GetValue(IconContentTemplateProperty); + } + set + { + SetValue(IconContentTemplateProperty, value); + } + } + + #endregion + + #region IconContentTemplateSelector + + /// + /// IconContentTemplateSelector Dependency Property + /// + public static readonly DependencyProperty IconContentTemplateSelectorProperty = DependencyProperty.Register("IconContentTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplateSelector)null)); + + /// + /// Gets or sets the IconContentTemplateSelector property. This dependency property + /// indicates data template selector to use while selecting the datatamplate for content icons. + /// + public DataTemplateSelector IconContentTemplateSelector + { + get + { + return (DataTemplateSelector)GetValue(IconContentTemplateSelectorProperty); + } + set + { + SetValue(IconContentTemplateSelectorProperty, value); + } + } + + #endregion + + #region LayoutItemContainerStyle + + /// + /// LayoutItemContainerStyle Dependency Property + /// + public static readonly DependencyProperty LayoutItemContainerStyleProperty = DependencyProperty.Register("LayoutItemContainerStyle", typeof(Style), typeof(DockingManager), + new FrameworkPropertyMetadata((Style)null, new PropertyChangedCallback(OnLayoutItemContainerStyleChanged))); + + /// + /// Gets or sets the LayoutItemContainerStyle property. This dependency property + /// indicates the style to apply to LayoutDocumentItem objects. A LayoutDocumentItem object is created when a new LayoutDocument is created inside the current Layout. + /// + public Style LayoutItemContainerStyle + { + get + { + return (Style)GetValue(LayoutItemContainerStyleProperty); + } + set + { + SetValue(LayoutItemContainerStyleProperty, value); + } + } + + /// + /// Handles changes to the LayoutItemContainerStyle property. + /// + private static void OnLayoutItemContainerStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnLayoutItemContainerStyleChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the LayoutItemContainerStyle property. + /// + protected virtual void OnLayoutItemContainerStyleChanged(DependencyPropertyChangedEventArgs e) + { + AttachLayoutItems(); + } + + #endregion + + #region LayoutItemContainerStyleSelector + + /// + /// LayoutItemContainerStyleSelector Dependency Property + /// + public static readonly DependencyProperty LayoutItemContainerStyleSelectorProperty = DependencyProperty.Register("LayoutItemContainerStyleSelector", typeof(StyleSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((StyleSelector)null, new PropertyChangedCallback(OnLayoutItemContainerStyleSelectorChanged))); + + /// + /// Gets or sets the LayoutItemContainerStyleSelector property. This dependency property + /// indicates style selector of the LayoutDocumentItemStyle. + /// + public StyleSelector LayoutItemContainerStyleSelector + { + get + { + return (StyleSelector)GetValue(LayoutItemContainerStyleSelectorProperty); + } + set + { + SetValue(LayoutItemContainerStyleSelectorProperty, value); + } + } + + /// + /// Handles changes to the LayoutItemContainerStyleSelector property. + /// + private static void OnLayoutItemContainerStyleSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnLayoutItemContainerStyleSelectorChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the LayoutItemContainerStyleSelector property. + /// + protected virtual void OnLayoutItemContainerStyleSelectorChanged(DependencyPropertyChangedEventArgs e) + { + AttachLayoutItems(); + } + + #endregion + + #region ShowSystemMenu + + /// + /// ShowSystemMenu Dependency Property + /// + public static readonly DependencyProperty ShowSystemMenuProperty = DependencyProperty.Register("ShowSystemMenu", typeof(bool), typeof(DockingManager), + new FrameworkPropertyMetadata((bool)true)); + + /// + /// Gets or sets the ShowSystemMenu property. This dependency property + /// indicates if floating windows should show the system menu when a custom context menu is not defined. + /// + public bool ShowSystemMenu + { + get + { + return (bool)GetValue(ShowSystemMenuProperty); + } + set + { + SetValue(ShowSystemMenuProperty, value); + } + } + + #endregion + + #region AllowMixedOrientation + + /// + /// AllowMixedOrientation Dependency Property + /// + public static readonly DependencyProperty AllowMixedOrientationProperty = DependencyProperty.Register("AllowMixedOrientation", typeof(bool), typeof(DockingManager), + new FrameworkPropertyMetadata((bool)false)); + + /// + /// Gets or sets the AllowMixedOrientation property. This dependency property + /// indicates if the manager should allow mixed orientation for document panes. + /// + public bool AllowMixedOrientation + { + get + { + return (bool)GetValue(AllowMixedOrientationProperty); + } + set + { + SetValue(AllowMixedOrientationProperty, value); + } + } + + #endregion + + #endregion + + #region Private Properties + + private bool IsNavigatorWindowActive + { + get + { + return _navigatorWindow != null; + } + } + + #endregion + + #region Overrides + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + + _autohideArea = GetTemplateChild("PART_AutoHideArea") as FrameworkElement; + } + + protected override void OnInitialized(EventArgs e) + { + base.OnInitialized(e); + } + + + protected override Size ArrangeOverride(Size arrangeBounds) + { + _areas = null; + return base.ArrangeOverride(arrangeBounds); + } + + protected override void OnPreviewKeyDown(KeyEventArgs e) + { + if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) + { + if (e.IsDown && e.Key == Key.Tab) + { + if (!IsNavigatorWindowActive) + { + ShowNavigatorWindow(); + e.Handled = true; + } + } + } + + base.OnPreviewKeyDown(e); + } + + #endregion + + #region Public Methods + + /// + /// Return the LayoutItem wrapper for the content passed as argument + /// + /// LayoutContent to search + /// Either a LayoutAnchorableItem or LayoutDocumentItem which contains the LayoutContent passed as argument + public LayoutItem GetLayoutItemFromModel(LayoutContent content) + { + return _layoutItems.FirstOrDefault(item => item.LayoutElement == content); + } + + public LayoutFloatingWindowControl CreateFloatingWindow(LayoutContent contentModel, bool isContentImmutable) + { + LayoutFloatingWindowControl lfwc = null; + + if (contentModel is LayoutAnchorable) + { + var parent = contentModel.Parent as ILayoutPane; + if (parent == null) + { + var pane = new LayoutAnchorablePane(contentModel as LayoutAnchorable) + { + FloatingTop = contentModel.FloatingTop, + FloatingLeft = contentModel.FloatingLeft, + FloatingWidth = contentModel.FloatingWidth, + FloatingHeight = contentModel.FloatingHeight + }; + lfwc = this.CreateFloatingWindowForLayoutAnchorableWithoutParent(pane, isContentImmutable); + } + } + + if (lfwc == null) + { + lfwc = this.CreateFloatingWindowCore(contentModel, isContentImmutable); + } + + return lfwc; + } + + #endregion + + #region Internal Methods + + internal UIElement CreateUIElementForModel(ILayoutElement model) + { + if (model is LayoutPanel) + return new LayoutPanelControl(model as LayoutPanel); + if (model is LayoutAnchorablePaneGroup) + return new LayoutAnchorablePaneGroupControl(model as LayoutAnchorablePaneGroup); + if (model is LayoutDocumentPaneGroup) + return new LayoutDocumentPaneGroupControl(model as LayoutDocumentPaneGroup); + + if (model is LayoutAnchorSide) + { + var templateModelView = new LayoutAnchorSideControl(model as LayoutAnchorSide); + templateModelView.SetBinding(LayoutAnchorSideControl.TemplateProperty, new Binding(DockingManager.AnchorSideTemplateProperty.Name) { Source = this }); + return templateModelView; + } + if (model is LayoutAnchorGroup) + { + var templateModelView = new LayoutAnchorGroupControl(model as LayoutAnchorGroup); + templateModelView.SetBinding(LayoutAnchorGroupControl.TemplateProperty, new Binding(DockingManager.AnchorGroupTemplateProperty.Name) { Source = this }); + return templateModelView; + } + + if (model is LayoutDocumentPane) + { + var templateModelView = new LayoutDocumentPaneControl(model as LayoutDocumentPane); + templateModelView.SetBinding(LayoutDocumentPaneControl.StyleProperty, new Binding(DockingManager.DocumentPaneControlStyleProperty.Name) { Source = this }); + return templateModelView; + } + if (model is LayoutAnchorablePane) + { + var templateModelView = new LayoutAnchorablePaneControl(model as LayoutAnchorablePane); + templateModelView.SetBinding(LayoutAnchorablePaneControl.StyleProperty, new Binding(DockingManager.AnchorablePaneControlStyleProperty.Name) { Source = this }); + return templateModelView; + } + + if (model is LayoutAnchorableFloatingWindow) + { + if (DesignerProperties.GetIsInDesignMode(this)) + return null; + var modelFW = model as LayoutAnchorableFloatingWindow; + var newFW = new LayoutAnchorableFloatingWindowControl(modelFW) + { + //Owner = Window.GetWindow(this) + }; + newFW.SetParentToMainWindowOf(this); + + // Floating Window can also contain only Pane Groups at its base (issue #27) so we check for + // RootPanel (which is a LayoutAnchorablePaneGroup) and make sure the window is positioned back + // in current (or nearest) monitor + var panegroup = modelFW.RootPanel; + if (panegroup != null) + { + panegroup.KeepInsideNearestMonitor(); // Check position is valid in current setup + + newFW.Left = panegroup.FloatingLeft; // Position the window to previous or nearest valid position + newFW.Top = panegroup.FloatingTop; + newFW.Width = panegroup.FloatingWidth; + newFW.Height = panegroup.FloatingHeight; + } + + newFW.ShowInTaskbar = false; + + Dispatcher.BeginInvoke(new Action(() => + { + newFW.Show(); + }), DispatcherPriority.Send); + + if (panegroup != null && panegroup.IsMaximized) + { + newFW.WindowState = WindowState.Maximized; + } + + return newFW; + } + + if (model is LayoutDocumentFloatingWindow) + { + if (DesignerProperties.GetIsInDesignMode(this)) + return null; + var modelFW = model as LayoutDocumentFloatingWindow; + var newFW = new LayoutDocumentFloatingWindowControl(modelFW) + { + //Owner = Window.GetWindow(this) + }; + newFW.SetParentToMainWindowOf(this); + + var paneForExtensions = modelFW.RootPanel; + if (paneForExtensions != null) + { + //ensure that floating window position is inside current (or nearest) monitor + paneForExtensions.KeepInsideNearestMonitor(); + + newFW.Left = paneForExtensions.FloatingLeft; + newFW.Top = paneForExtensions.FloatingTop; + newFW.Width = paneForExtensions.FloatingWidth; + newFW.Height = paneForExtensions.FloatingHeight; + } + + newFW.ShowInTaskbar = false; + newFW.Show(); + // Do not set the WindowState before showing or it will be lost + if (paneForExtensions != null && paneForExtensions.IsMaximized) + { + newFW.WindowState = WindowState.Maximized; + } + return newFW; + } + + if (model is LayoutDocument) + { + var templateModelView = new LayoutDocumentControl() { Model = model as LayoutDocument }; + return templateModelView; + } + + return null; + } + + internal void ShowAutoHideWindow(LayoutAnchorControl anchor) + { + _autoHideWindowManager.ShowAutoHideWindow(anchor); + //if (_autohideArea == null) + // return; + + //if (AutoHideWindow != null && AutoHideWindow.Model == anchor.Model) + // return; + + //Trace.WriteLine("ShowAutoHideWindow()"); + + //_currentAutohiddenAnchor = new WeakReference(anchor); + + //HideAutoHideWindow(anchor); + + //SetAutoHideWindow(new LayoutAutoHideWindowControl(anchor)); + //AutoHideWindow.Show(); + } + + internal void HideAutoHideWindow(LayoutAnchorControl anchor) + { + _autoHideWindowManager.HideAutoWindow(anchor); + } + + internal FrameworkElement GetAutoHideAreaElement() + { + return _autohideArea; + } + + internal void StartDraggingFloatingWindowForContent(LayoutContent contentModel, bool startDrag = true) + { + LayoutFloatingWindowControl fwc = null; + + // For last document re-use floating window + if (contentModel.Parent.ChildrenCount == 1) + { + foreach (var fw in _fwList) + foreach (var layoutElement in ((LayoutDocumentFloatingWindow)fw.Model).Children) + foreach (var pane in ((LayoutDocumentPaneGroup)layoutElement).Children) + foreach (var layoutDoc in ((LayoutDocumentPane)pane).Children) + if (layoutDoc == contentModel) + fwc = fw; + } + + var show = fwc == null; // Do not show already visible floating window + if (fwc == null) + fwc = this.CreateFloatingWindow(contentModel, false); + + if (fwc != null) + { + Dispatcher.BeginInvoke(new Action(() => + { + // Activate only inactive document + if (startDrag) fwc.AttachDrag(!contentModel.IsActive); + if (show) fwc.Show(); + }), DispatcherPriority.Send); + } + } + + internal void StartDraggingFloatingWindowForPane(LayoutAnchorablePane paneModel) + { + var fwc = this.CreateFloatingWindowForLayoutAnchorableWithoutParent(paneModel, false); + if (fwc != null) + { + fwc.AttachDrag(); + fwc.Show(); + } + } + + internal IEnumerable GetFloatingWindowsByZOrder() + { + IntPtr windowParentHanlde; + var parentWindow = Window.GetWindow(this); + if (parentWindow != null) + { + windowParentHanlde = new WindowInteropHelper(parentWindow).Handle; + } + else + { + var mainProcess = Process.GetCurrentProcess(); + if (mainProcess == null) + yield break; + + windowParentHanlde = mainProcess.MainWindowHandle; + } + + IntPtr currentHandle = Win32Helper.GetWindow(windowParentHanlde, (uint)Win32Helper.GetWindow_Cmd.GW_HWNDFIRST); + while (currentHandle != IntPtr.Zero) + { + LayoutFloatingWindowControl ctrl = _fwList.FirstOrDefault(fw => new WindowInteropHelper(fw).Handle == currentHandle); + if (ctrl != null && ctrl.Model.Root != null && ctrl.Model.Root.Manager == this) + yield return ctrl; + + currentHandle = Win32Helper.GetWindow(currentHandle, (uint)Win32Helper.GetWindow_Cmd.GW_HWNDNEXT); + } + } + + internal void RemoveFloatingWindow(LayoutFloatingWindowControl floatingWindow) + { + _fwList.Remove(floatingWindow); + } + + internal void _ExecuteCloseCommand(LayoutDocument document) + { + if (DocumentClosing != null) + { + var evargs = new DocumentClosingEventArgs(document); + DocumentClosing(this, evargs); + if (evargs.Cancel) + return; + } + + if (document.CloseDocument()) + { + this.RemoveViewFromLogicalChild(document); + + if (DocumentClosed != null) + { + var evargs = new DocumentClosedEventArgs(document); + DocumentClosed(this, evargs); + } + } + } + + internal void _ExecuteCloseAllButThisCommand(LayoutContent contentSelected) + { + foreach (var contentToClose in Layout.Descendents().OfType().Where(d => d != contentSelected && (d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow)).ToArray()) + { + this.Close(contentToClose); + } + } + + internal void _ExecuteCloseAllCommand(LayoutContent contentSelected) + { + foreach (var contentToClose in Layout.Descendents().OfType().Where(d => (d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow)).ToArray()) + { + this.Close(contentToClose); + } + } + + internal void _ExecuteCloseCommand(LayoutAnchorable anchorable) + { + var model = anchorable as LayoutAnchorable; + if (model != null) + { + model.CloseAnchorable(); + this.RemoveViewFromLogicalChild(anchorable); + } + } + + internal void _ExecuteHideCommand(LayoutAnchorable anchorable) + { + var model = anchorable as LayoutAnchorable; + if (model != null) + { + model.Hide(); + } + } + + internal void _ExecuteAutoHideCommand(LayoutAnchorable _anchorable) + { + _anchorable.ToggleAutoHide(); + } + + + internal void _ExecuteFloatCommand(LayoutContent contentToFloat) + { + contentToFloat.Float(); + } + + internal void _ExecuteDockCommand(LayoutAnchorable anchorable) + { + anchorable.Dock(); + } + + internal void _ExecuteDockAsDocumentCommand(LayoutContent content) + { + content.DockAsDocument(); + } + + internal void _ExecuteContentActivateCommand(LayoutContent content) + { + content.IsActive = true; + } + + #endregion + + #region Private Methods + + private void OnLayoutRootPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == "RootPanel") + { + if (IsInitialized) + { + var layoutRootPanel = CreateUIElementForModel(Layout.RootPanel) as LayoutPanelControl; + LayoutRootPanel = layoutRootPanel; + } + } + else if (e.PropertyName == "ActiveContent") + { + if (Layout.ActiveContent != null) + { + //set focus on active element only after a layout pass is completed + //it's possible that it is not yet visible in the visual tree + //if (_setFocusAsyncOperation == null) + //{ + // _setFocusAsyncOperation = Dispatcher.BeginInvoke(new Action(() => + // { + if (Layout.ActiveContent != null) + FocusElementManager.SetFocusOnLastElement(Layout.ActiveContent); + //_setFocusAsyncOperation = null; + // } ), DispatcherPriority.Input ); + //} + } + + if (!_insideInternalSetActiveContent) + { + this.ActiveContent = (Layout.ActiveContent != null) ? Layout.ActiveContent.Content : null; + } + } + } + + private void OnLayoutRootUpdated(object sender, EventArgs e) + { + CommandManager.InvalidateRequerySuggested(); + } + + private void OnLayoutChanging(LayoutRoot newLayout) + { + if (LayoutChanging != null) + LayoutChanging(this, EventArgs.Empty); + } + + private void DockingManager_Loaded(object sender, RoutedEventArgs e) + { + if (!DesignerProperties.GetIsInDesignMode(this)) + { + if (Layout.Manager == this) + { + LayoutRootPanel = CreateUIElementForModel(Layout.RootPanel) as LayoutPanelControl; + LeftSidePanel = CreateUIElementForModel(Layout.LeftSide) as LayoutAnchorSideControl; + TopSidePanel = CreateUIElementForModel(Layout.TopSide) as LayoutAnchorSideControl; + RightSidePanel = CreateUIElementForModel(Layout.RightSide) as LayoutAnchorSideControl; + BottomSidePanel = CreateUIElementForModel(Layout.BottomSide) as LayoutAnchorSideControl; + + // In order to prevent resource leaks, unsubscribe from SizeChanged event for case when we have no stored Layout settings. + SizeChanged -= OnSizeChanged; + SizeChanged += OnSizeChanged; + } + + SetupAutoHideWindow(); + + foreach (var fwc in _fwHiddenList) + { + fwc.EnableBindings(); + if (fwc.KeepContentVisibleOnClose) + { + fwc.Show(); + fwc.KeepContentVisibleOnClose = false; + } + + _fwList.Add(fwc); + } + _fwHiddenList.Clear(); + + //load windows not already loaded! + foreach (var fw in Layout.FloatingWindows.Where(fw => !_fwList.Any(fwc => fwc.Model == fw))) + _fwList.Add(CreateUIElementForModel(fw) as LayoutFloatingWindowControl); + + //create the overlaywindow if it's possible + if (IsVisible) + CreateOverlayWindow(); + FocusElementManager.SetupFocusManagement(this); + } + } + + /// + /// Method executes when the control has changed its height and/or width. + /// + /// + /// + private void OnSizeChanged(object sender, SizeChangedEventArgs e) + { + // Lets make sure this always remains non-negative to avoid crach in layout system + double width = Math.Max(ActualWidth - GridSplitterWidth - RightSidePanel.ActualWidth - LeftSidePanel.ActualWidth, 0); + double height = Math.Max(ActualHeight - GridSplitterHeight - TopSidePanel.ActualHeight - BottomSidePanel.ActualHeight, 0); + + LayoutRootPanel.AdjustFixedChildrenPanelSizes(new Size(width, height)); + } + + private void DockingManager_Unloaded(object sender, RoutedEventArgs e) + { + SizeChanged -= OnSizeChanged; + + if (!DesignerProperties.GetIsInDesignMode(this)) + { + if (_autoHideWindowManager != null) + { + _autoHideWindowManager.HideAutoWindow(); + } + + if (AutoHideWindow != null) + { + AutoHideWindow.Dispose(); + } + + foreach (var fw in _fwList.ToArray()) + { + ////fw.Owner = null; + //fw.SetParentWindowToNull(); + //fw.KeepContentVisibleOnClose = true; + //// To avoid calling Close method multiple times. + //fw.InternalClose(true); + + // Unloaded can occure not only after closing of the application, but after switching between tabs. + // For such case it's better to hide the floating windows instead of closing it. + // We clear bindings on visibility during the owner is unloaded. + if (fw.IsVisible) + { + fw.KeepContentVisibleOnClose = true; + fw.Hide(); + } + fw.DisableBindings(); + _fwHiddenList.Add(fw); + } + + _fwList.Clear(); + + DestroyOverlayWindow(); + FocusElementManager.FinalizeFocusManagement(this); + } + } + + private void SetupAutoHideWindow() + { + if (_autoHideWindowManager != null) + _autoHideWindowManager.HideAutoWindow(); + else + _autoHideWindowManager = new AutoHideWindowManager(this); + + if (AutoHideWindow != null) + { + AutoHideWindow.Dispose(); + } + + SetAutoHideWindow(new LayoutAutoHideWindowControl()); + } + + private void CreateOverlayWindow() + { + if (_overlayWindow == null) + { + _overlayWindow = new OverlayWindow(this); + } + Rect rectWindow = new Rect(this.PointToScreenDPIWithoutFlowDirection(new Point()), this.TransformActualSizeToAncestor()); + _overlayWindow.Left = rectWindow.Left; + _overlayWindow.Top = rectWindow.Top; + _overlayWindow.Width = rectWindow.Width; + _overlayWindow.Height = rectWindow.Height; + } + + private void DestroyOverlayWindow() + { + if (_overlayWindow != null) + { + _overlayWindow.Close(); + _overlayWindow = null; + } + } + + private void AttachDocumentsSource(LayoutRoot layout, IEnumerable documentsSource) + { + if (documentsSource == null) + return; + + if (layout == null) + return; + + //if (layout.Descendents().OfType().Any()) + // throw new InvalidOperationException("Unable to set the DocumentsSource property if LayoutDocument objects are already present in the model"); + var documentsImported = layout.Descendents().OfType().Select(d => d.Content).ToArray(); + var documents = documentsSource as IEnumerable; + var listOfDocumentsToImport = new List(documents.OfType()); + + foreach (var document in listOfDocumentsToImport.ToArray()) + { + if (documentsImported.Contains(document)) + listOfDocumentsToImport.Remove(document); + } + + + LayoutDocumentPane documentPane = null; + if (layout.LastFocusedDocument != null) + { + documentPane = layout.LastFocusedDocument.Parent as LayoutDocumentPane; + } + + if (documentPane == null) + { + documentPane = layout.Descendents().OfType().FirstOrDefault(); + } + + //if (documentPane == null) + // throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); + + _suspendLayoutItemCreation = true; + foreach (var documentContentToImport in listOfDocumentsToImport) + { + + //documentPane.Children.Add(new LayoutDocument() { Content = documentToImport }); + + var documentToImport = new LayoutDocument() + { + Content = documentContentToImport + }; + + bool added = false; + if (LayoutUpdateStrategy != null) + { + added = LayoutUpdateStrategy.BeforeInsertDocument(layout, documentToImport, documentPane); + } + + if (!added) + { + if (documentPane == null) + throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); + + documentPane.Children.Add(documentToImport); + added = true; + } + + if (LayoutUpdateStrategy != null) + LayoutUpdateStrategy.AfterInsertDocument(layout, documentToImport); + + + CreateDocumentLayoutItem(documentToImport); + + } + _suspendLayoutItemCreation = false; + + + var documentsSourceAsNotifier = documentsSource as INotifyCollectionChanged; + if (documentsSourceAsNotifier != null) + documentsSourceAsNotifier.CollectionChanged += new NotifyCollectionChangedEventHandler(documentsSourceElementsChanged); + } + + private void documentsSourceElementsChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (Layout == null) + return; + + //When deserializing documents are created automatically by the deserializer + if (SuspendDocumentsSourceBinding) + return; + + //handle remove + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace) + { + if (e.OldItems != null) + { + var documentsToRemove = Layout.Descendents().OfType().Where(d => e.OldItems.Contains(d.Content)).ToArray(); + foreach (var documentToRemove in documentsToRemove) + { + (documentToRemove.Parent as ILayoutContainer).RemoveChild( + documentToRemove); + this.RemoveViewFromLogicalChild(documentToRemove); + } + } + } + + //handle add + if (e.NewItems != null && + (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)) + { + if (e.NewItems != null) + { + LayoutDocumentPane documentPane = null; + if (Layout.LastFocusedDocument != null) + { + documentPane = Layout.LastFocusedDocument.Parent as LayoutDocumentPane; + } + + if (documentPane == null) + { + documentPane = Layout.Descendents().OfType().FirstOrDefault(); + } + + //if (documentPane == null) + // throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); + + _suspendLayoutItemCreation = true; + + foreach (var documentContentToImport in e.NewItems) + { + var documentToImport = new LayoutDocument() + { + Content = documentContentToImport + }; + + bool added = false; + if (LayoutUpdateStrategy != null) + { + added = LayoutUpdateStrategy.BeforeInsertDocument(Layout, documentToImport, documentPane); + } + + if (!added) + { + if (documentPane == null) + throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); + + documentPane.Children.Add(documentToImport); + added = true; + } + + if (LayoutUpdateStrategy != null) + { + LayoutUpdateStrategy.AfterInsertDocument(Layout, documentToImport); + } + + + var root = documentToImport.Root; + + if (root != null && root.Manager == this) + { + CreateDocumentLayoutItem(documentToImport); + } + } + _suspendLayoutItemCreation = false; + } + } + + if (e.Action == NotifyCollectionChangedAction.Reset) + { + //NOTE: I'm going to clear every document present in layout but + //some documents may have been added directly to the layout, for now I clear them too + var documentsToRemove = Layout.Descendents().OfType().ToArray(); + foreach (var documentToRemove in documentsToRemove) + { + (documentToRemove.Parent as ILayoutContainer).RemoveChild( + documentToRemove); + this.RemoveViewFromLogicalChild(documentToRemove); + } + } + + if (Layout != null) + { + Layout.CollectGarbage(); + } + } + + private void DetachDocumentsSource(LayoutRoot layout, IEnumerable documentsSource) + { + if (documentsSource == null) + return; + + if (layout == null) + return; + + var documentsToRemove = layout.Descendents().OfType() + .Where(d => documentsSource.Contains(d.Content)).ToArray(); + + foreach (var documentToRemove in documentsToRemove) + { + (documentToRemove.Parent as ILayoutContainer).RemoveChild( + documentToRemove); + this.RemoveViewFromLogicalChild(documentToRemove); + } + + var documentsSourceAsNotifier = documentsSource as INotifyCollectionChanged; + if (documentsSourceAsNotifier != null) + documentsSourceAsNotifier.CollectionChanged -= new NotifyCollectionChangedEventHandler(documentsSourceElementsChanged); + } + + private void Close(LayoutContent contentToClose) + { + if (!contentToClose.CanClose) + return; + + var layoutItem = GetLayoutItemFromModel(contentToClose); + if (layoutItem.CloseCommand != null) + { + if (layoutItem.CloseCommand.CanExecute(null)) + layoutItem.CloseCommand.Execute(null); + } + else + { + if (contentToClose is LayoutDocument) + _ExecuteCloseCommand(contentToClose as LayoutDocument); + else if (contentToClose is LayoutAnchorable) + _ExecuteCloseCommand(contentToClose as LayoutAnchorable); + } + } + + private void AttachAnchorablesSource(LayoutRoot layout, IEnumerable anchorablesSource) + { + if (anchorablesSource == null) + return; + + if (layout == null) + return; + + //if (layout.Descendents().OfType().Any()) + // throw new InvalidOperationException("Unable to set the AnchorablesSource property if LayoutAnchorable objects are already present in the model"); + var anchorablesImported = layout.Descendents().OfType().Select(d => d.Content).ToArray(); + var anchorables = anchorablesSource as IEnumerable; + var listOfAnchorablesToImport = new List(anchorables.OfType()); + + foreach (var document in listOfAnchorablesToImport.ToArray()) + { + if (anchorablesImported.Contains(document)) + listOfAnchorablesToImport.Remove(document); + } + + LayoutAnchorablePane anchorablePane = null; + if (layout.ActiveContent != null) + { + //look for active content parent pane + anchorablePane = layout.ActiveContent.Parent as LayoutAnchorablePane; + } + + if (anchorablePane == null) + { + //look for a pane on the right side + anchorablePane = layout.Descendents().OfType().Where(pane => !pane.IsHostedInFloatingWindow && pane.GetSide() == AnchorSide.Right).FirstOrDefault(); + } + + if (anchorablePane == null) + { + //look for an available pane + anchorablePane = layout.Descendents().OfType().FirstOrDefault(); + } + + _suspendLayoutItemCreation = true; + foreach (var anchorableContentToImport in listOfAnchorablesToImport) + { + var anchorableToImport = new LayoutAnchorable() + { + Content = anchorableContentToImport + }; + + bool added = false; + if (LayoutUpdateStrategy != null) + { + added = LayoutUpdateStrategy.BeforeInsertAnchorable(layout, anchorableToImport, anchorablePane); + } + + if (!added) + { + if (anchorablePane == null) + { + var mainLayoutPanel = new LayoutPanel() { Orientation = Orientation.Horizontal }; + if (layout.RootPanel != null) + { + mainLayoutPanel.Children.Add(layout.RootPanel); + } + + layout.RootPanel = mainLayoutPanel; + anchorablePane = new LayoutAnchorablePane() { DockWidth = new GridLength(200.0, GridUnitType.Pixel) }; + mainLayoutPanel.Children.Add(anchorablePane); + } + + anchorablePane.Children.Add(anchorableToImport); + added = true; + } + + if (LayoutUpdateStrategy != null) + LayoutUpdateStrategy.AfterInsertAnchorable(layout, anchorableToImport); + + + CreateAnchorableLayoutItem(anchorableToImport); + + } + + _suspendLayoutItemCreation = false; + + var anchorablesSourceAsNotifier = anchorablesSource as INotifyCollectionChanged; + if (anchorablesSourceAsNotifier != null) + anchorablesSourceAsNotifier.CollectionChanged += new NotifyCollectionChangedEventHandler(anchorablesSourceElementsChanged); + } + + private void anchorablesSourceElementsChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (Layout == null) + return; + + //When deserializing documents are created automatically by the deserializer + if (SuspendAnchorablesSourceBinding) + return; + + //handle remove + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace) + { + if (e.OldItems != null) + { + var anchorablesToRemove = Layout.Descendents().OfType().Where(d => e.OldItems.Contains(d.Content)).ToArray(); + foreach (var anchorableToRemove in anchorablesToRemove) + { + anchorableToRemove.Content = null; + (anchorableToRemove.Parent as ILayoutContainer).RemoveChild( + anchorableToRemove); + this.RemoveViewFromLogicalChild(anchorableToRemove); + } + } + } + + //handle add + if (e.NewItems != null && + (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)) + { + if (e.NewItems != null) + { + LayoutAnchorablePane anchorablePane = null; + + if (Layout.ActiveContent != null) + { + //look for active content parent pane + anchorablePane = Layout.ActiveContent.Parent as LayoutAnchorablePane; + } + + if (anchorablePane == null) + { + //look for a pane on the right side + anchorablePane = Layout.Descendents().OfType().Where(pane => !pane.IsHostedInFloatingWindow && pane.GetSide() == AnchorSide.Right).FirstOrDefault(); + } + + if (anchorablePane == null) + { + //look for an available pane + anchorablePane = Layout.Descendents().OfType().FirstOrDefault(); + } + + _suspendLayoutItemCreation = true; + foreach (var anchorableContentToImport in e.NewItems) + { + var anchorableToImport = new LayoutAnchorable() + { + Content = anchorableContentToImport + }; + + bool added = false; + if (LayoutUpdateStrategy != null) + { + added = LayoutUpdateStrategy.BeforeInsertAnchorable(Layout, anchorableToImport, anchorablePane); + } + + if (!added) + { + if (anchorablePane == null) + { + var mainLayoutPanel = new LayoutPanel() { Orientation = Orientation.Horizontal }; + if (Layout.RootPanel != null) + { + mainLayoutPanel.Children.Add(Layout.RootPanel); + } + + Layout.RootPanel = mainLayoutPanel; + anchorablePane = new LayoutAnchorablePane() { DockWidth = new GridLength(200.0, GridUnitType.Pixel) }; + mainLayoutPanel.Children.Add(anchorablePane); + } + + anchorablePane.Children.Add(anchorableToImport); + added = true; + } + + if (LayoutUpdateStrategy != null) + { + LayoutUpdateStrategy.AfterInsertAnchorable(Layout, anchorableToImport); + } + + var root = anchorableToImport.Root; + + if (root != null && root.Manager == this) + { + CreateAnchorableLayoutItem(anchorableToImport); + } + + } + _suspendLayoutItemCreation = false; + } + } + + if (e.Action == NotifyCollectionChangedAction.Reset) + { + //NOTE: I'm going to clear every anchorable present in layout but + //some anchorable may have been added directly to the layout, for now I clear them too + var anchorablesToRemove = Layout.Descendents().OfType().ToArray(); + foreach (var anchorableToRemove in anchorablesToRemove) + { + (anchorableToRemove.Parent as ILayoutContainer).RemoveChild( + anchorableToRemove); + this.RemoveViewFromLogicalChild(anchorableToRemove); + } + } + + if (Layout != null) + Layout.CollectGarbage(); + } + + private void DetachAnchorablesSource(LayoutRoot layout, IEnumerable anchorablesSource) + { + if (anchorablesSource == null) + return; + + if (layout == null) + return; + + var anchorablesToRemove = layout.Descendents().OfType() + .Where(d => anchorablesSource.Contains(d.Content)).ToArray(); + + foreach (var anchorableToRemove in anchorablesToRemove) + { + (anchorableToRemove.Parent as ILayoutContainer).RemoveChild( + anchorableToRemove); + this.RemoveViewFromLogicalChild(anchorableToRemove); + } + + var anchorablesSourceAsNotifier = anchorablesSource as INotifyCollectionChanged; + if (anchorablesSourceAsNotifier != null) + anchorablesSourceAsNotifier.CollectionChanged -= new NotifyCollectionChangedEventHandler(anchorablesSourceElementsChanged); + } + + private void RemoveViewFromLogicalChild(LayoutContent layoutContent) + { + if (layoutContent == null) + return; + + var layoutItem = this.GetLayoutItemFromModel(layoutContent); + if (layoutItem != null) + { + if (layoutItem.IsViewExists()) + { + this.InternalRemoveLogicalChild(layoutItem.View); + } + } + } + + private void InternalSetActiveContent(object contentObject) + { + var layoutContent = Layout.Descendents().OfType().FirstOrDefault(lc => lc == contentObject || lc.Content == contentObject); + _insideInternalSetActiveContent = true; + Layout.ActiveContent = layoutContent; + _insideInternalSetActiveContent = false; + } + + private void DetachLayoutItems() + { + if (Layout != null) + { + _layoutItems.ForEach(i => i.Detach()); + _layoutItems.Clear(); + Layout.ElementAdded -= new EventHandler(Layout_ElementAdded); + Layout.ElementRemoved -= new EventHandler(Layout_ElementRemoved); + } + } + + private void Layout_ElementRemoved(object sender, LayoutElementEventArgs e) + { + if (_suspendLayoutItemCreation) + return; + + CollectLayoutItemsDeleted(); + } + + private void Layout_ElementAdded(object sender, LayoutElementEventArgs e) + { + if (_suspendLayoutItemCreation) + return; + + foreach (var content in Layout.Descendents().OfType()) + { + if (content is LayoutDocument) + CreateDocumentLayoutItem(content as LayoutDocument); + else //if (content is LayoutAnchorable) + CreateAnchorableLayoutItem(content as LayoutAnchorable); + } + + CollectLayoutItemsDeleted(); + } + + private void CollectLayoutItemsDeleted() + { + if (_collectLayoutItemsOperations != null) + return; + _collectLayoutItemsOperations = Dispatcher.BeginInvoke(new Action(() => + { + _collectLayoutItemsOperations = null; + foreach (var itemToRemove in _layoutItems.Where(item => item.LayoutElement.Root != Layout).ToArray()) + { + + if (itemToRemove != null && + itemToRemove.Model != null && + itemToRemove.Model is UIElement) + { + //((ILogicalChildrenContainer)this).InternalRemoveLogicalChild(itemToRemove.Model as UIElement); + } + + itemToRemove.Detach(); + _layoutItems.Remove(itemToRemove); + + } + })); + } + + private void AttachLayoutItems() + { + if (Layout != null) + { + foreach (var document in Layout.Descendents().OfType().ToArray()) + { + CreateDocumentLayoutItem(document); + //var documentItem = new LayoutDocumentItem(); + //documentItem.Attach(document); + //ApplyStyleToLayoutItem(documentItem); + //_layoutItems.Add(documentItem); + } + foreach (var anchorable in Layout.Descendents().OfType().ToArray()) + { + CreateAnchorableLayoutItem(anchorable); + //var anchorableItem = new LayoutAnchorableItem(); + //anchorableItem.Attach(anchorable); + //ApplyStyleToLayoutItem(anchorableItem); + //_layoutItems.Add(anchorableItem); + } + + Layout.ElementAdded += new EventHandler(Layout_ElementAdded); + Layout.ElementRemoved += new EventHandler(Layout_ElementRemoved); + } + } + + private void ApplyStyleToLayoutItem(LayoutItem layoutItem) + { + layoutItem._ClearDefaultBindings(); + if (LayoutItemContainerStyle != null) + layoutItem.Style = LayoutItemContainerStyle; + else if (LayoutItemContainerStyleSelector != null) + layoutItem.Style = LayoutItemContainerStyleSelector.SelectStyle(layoutItem.Model, layoutItem); + layoutItem._SetDefaultBindings(); + } + + private void CreateAnchorableLayoutItem(LayoutAnchorable contentToAttach) + { + if (_layoutItems.Any(item => item.LayoutElement == contentToAttach)) + { + foreach (var item in _layoutItems) + { + ApplyStyleToLayoutItem(item); + } + return; + } + + var layoutItem = new LayoutAnchorableItem(); + layoutItem.Attach(contentToAttach); + _layoutItems.Add(layoutItem); + ApplyStyleToLayoutItem(layoutItem); + + if (contentToAttach != null && + contentToAttach.Content != null && + contentToAttach.Content is UIElement) + { + InternalAddLogicalChild(contentToAttach.Content); + } + + } + + private void CreateDocumentLayoutItem(LayoutDocument contentToAttach) + { + if (_layoutItems.Any(item => item.LayoutElement == contentToAttach)) + { + foreach (var item in _layoutItems) + { + ApplyStyleToLayoutItem(item); + } + return; + } + + var layoutItem = new LayoutDocumentItem(); + layoutItem.Attach(contentToAttach); + _layoutItems.Add(layoutItem); + ApplyStyleToLayoutItem(layoutItem); + + if (contentToAttach != null && + contentToAttach.Content != null && + contentToAttach.Content is UIElement) + { + InternalAddLogicalChild(contentToAttach.Content); + } + + } + + private void ShowNavigatorWindow() + { + if (_navigatorWindow == null) + { + _navigatorWindow = new NavigatorWindow(this) + { + Owner = Window.GetWindow(this), + WindowStartupLocation = WindowStartupLocation.CenterOwner + }; + } + + _navigatorWindow.ShowDialog(); + _navigatorWindow = null; + } + + private LayoutFloatingWindowControl CreateFloatingWindowForLayoutAnchorableWithoutParent(LayoutAnchorablePane paneModel, bool isContentImmutable) + { + if (paneModel.Children.Any(c => !c.CanFloat)) + return null; + var paneAsPositionableElement = paneModel as ILayoutPositionableElement; + var paneAsWithActualSize = paneModel as ILayoutPositionableElementWithActualSize; + + double fwWidth = paneAsPositionableElement.FloatingWidth; + double fwHeight = paneAsPositionableElement.FloatingHeight; + double fwLeft = paneAsPositionableElement.FloatingLeft; + double fwTop = paneAsPositionableElement.FloatingTop; + + if (fwWidth == 0.0) + fwWidth = paneAsWithActualSize.ActualWidth + 10; //10 includes BorderThickness and Margins inside LayoutAnchorableFloatingWindowControl. + if (fwHeight == 0.0) + fwHeight = paneAsWithActualSize.ActualHeight + 10; //10 includes BorderThickness and Margins inside LayoutAnchorableFloatingWindowControl. + + var destPane = new LayoutAnchorablePane() + { + DockWidth = paneAsPositionableElement.DockWidth, + DockHeight = paneAsPositionableElement.DockHeight, + DockMinHeight = paneAsPositionableElement.DockMinHeight, + DockMinWidth = paneAsPositionableElement.DockMinWidth, + FloatingLeft = paneAsPositionableElement.FloatingLeft, + FloatingTop = paneAsPositionableElement.FloatingTop, + FloatingWidth = paneAsPositionableElement.FloatingWidth, + FloatingHeight = paneAsPositionableElement.FloatingHeight, + }; + + bool savePreviousContainer = paneModel.FindParent() == null; + int currentSelectedContentIndex = paneModel.SelectedContentIndex; + while (paneModel.Children.Count > 0) + { + var contentModel = paneModel.Children[paneModel.Children.Count - 1] as LayoutAnchorable; + + if (savePreviousContainer) + { + var contentModelAsPreviousContainer = contentModel as ILayoutPreviousContainer; + contentModelAsPreviousContainer.PreviousContainer = paneModel; + contentModel.PreviousContainerIndex = paneModel.Children.Count - 1; + } + + paneModel.RemoveChildAt(paneModel.Children.Count - 1); + destPane.Children.Insert(0, contentModel); + } + + if (destPane.Children.Count > 0) + { + destPane.SelectedContentIndex = currentSelectedContentIndex; + } + + + LayoutFloatingWindow fw; + LayoutFloatingWindowControl fwc; + fw = new LayoutAnchorableFloatingWindow() + { + RootPanel = new LayoutAnchorablePaneGroup( + destPane) + { + DockHeight = destPane.DockHeight, + DockWidth = destPane.DockWidth, + DockMinHeight = destPane.DockMinHeight, + DockMinWidth = destPane.DockMinWidth, + } + }; + + Layout.FloatingWindows.Add(fw); + + fwc = new LayoutAnchorableFloatingWindowControl( + fw as LayoutAnchorableFloatingWindow, isContentImmutable) + { + Width = fwWidth, + Height = fwHeight, + Top = fwTop, + Left = fwLeft + }; + + + + //fwc.Owner = Window.GetWindow(this); + //fwc.SetParentToMainWindowOf(this); + + + _fwList.Add(fwc); + + Layout.CollectGarbage(); + + InvalidateArrange(); + + return fwc; + } + + private LayoutFloatingWindowControl CreateFloatingWindowCore(LayoutContent contentModel, bool isContentImmutable) + { + if (!contentModel.CanFloat) + return null; + var contentModelAsAnchorable = contentModel as LayoutAnchorable; + if (contentModelAsAnchorable != null && + contentModelAsAnchorable.IsAutoHidden) + contentModelAsAnchorable.ToggleAutoHide(); + + var parentPane = contentModel.Parent as ILayoutPane; + var parentPaneAsPositionableElement = contentModel.Parent as ILayoutPositionableElement; + var parentPaneAsWithActualSize = contentModel.Parent as ILayoutPositionableElementWithActualSize; + var contentModelParentChildrenIndex = parentPane.Children.ToList().IndexOf(contentModel); + + if (contentModel.FindParent() == null) + { + ((ILayoutPreviousContainer)contentModel).PreviousContainer = parentPane; + contentModel.PreviousContainerIndex = contentModelParentChildrenIndex; + } + + parentPane.RemoveChildAt(contentModelParentChildrenIndex); + + double fwWidth = contentModel.FloatingWidth; + double fwHeight = contentModel.FloatingHeight; + + if (fwWidth == 0.0) + fwWidth = parentPaneAsPositionableElement.FloatingWidth; + if (fwHeight == 0.0) + fwHeight = parentPaneAsPositionableElement.FloatingHeight; + + if (fwWidth == 0.0) + fwWidth = parentPaneAsWithActualSize.ActualWidth + 10; //10 includes BorderThickness and Margins inside LayoutDocumentFloatingWindowControl. + if (fwHeight == 0.0) + fwHeight = parentPaneAsWithActualSize.ActualHeight + 10; //10 includes BorderThickness and Margins inside LayoutDocumentFloatingWindowControl. + + LayoutFloatingWindow fw; + LayoutFloatingWindowControl fwc; + if (contentModel is LayoutAnchorable) + { + var anchorableContent = contentModel as LayoutAnchorable; + fw = new LayoutAnchorableFloatingWindow() + { + RootPanel = new LayoutAnchorablePaneGroup( + new LayoutAnchorablePane(anchorableContent) + { + DockWidth = parentPaneAsPositionableElement.DockWidth, + DockHeight = parentPaneAsPositionableElement.DockHeight, + DockMinHeight = parentPaneAsPositionableElement.DockMinHeight, + DockMinWidth = parentPaneAsPositionableElement.DockMinWidth, + FloatingLeft = parentPaneAsPositionableElement.FloatingLeft, + FloatingTop = parentPaneAsPositionableElement.FloatingTop, + FloatingWidth = parentPaneAsPositionableElement.FloatingWidth, + FloatingHeight = parentPaneAsPositionableElement.FloatingHeight, + }) + }; + + Layout.FloatingWindows.Add(fw); + + fwc = new LayoutAnchorableFloatingWindowControl( + fw as LayoutAnchorableFloatingWindow, isContentImmutable) + { + Width = fwWidth, + Height = fwHeight, + Left = contentModel.FloatingLeft, + Top = contentModel.FloatingTop + }; + } + else + { + var anchorableDocument = contentModel as LayoutDocument; + fw = new LayoutDocumentFloatingWindow() + { + RootPanel = new LayoutDocumentPaneGroup( + new LayoutDocumentPane(anchorableDocument) + { + DockWidth = parentPaneAsPositionableElement.DockWidth, + DockHeight = parentPaneAsPositionableElement.DockHeight, + DockMinHeight = parentPaneAsPositionableElement.DockMinHeight, + DockMinWidth = parentPaneAsPositionableElement.DockMinWidth, + FloatingLeft = parentPaneAsPositionableElement.FloatingLeft, + FloatingTop = parentPaneAsPositionableElement.FloatingTop, + FloatingWidth = parentPaneAsPositionableElement.FloatingWidth, + FloatingHeight = parentPaneAsPositionableElement.FloatingHeight, + }) + }; + + Layout.FloatingWindows.Add(fw); + + fwc = new LayoutDocumentFloatingWindowControl( + fw as LayoutDocumentFloatingWindow, isContentImmutable) + { + Width = fwWidth, + Height = fwHeight, + Left = contentModel.FloatingLeft, + Top = contentModel.FloatingTop + }; + } + + //fwc.Owner = Window.GetWindow(this); + //fwc.SetParentToMainWindowOf(this); + + _fwList.Add(fwc); + + Layout.CollectGarbage(); + + UpdateLayout(); + + return fwc; + } + + #endregion + + #region Events + + /// + /// Event fired when property changes + /// + public event EventHandler LayoutChanged; + + /// + /// Event fired when property is about to be changed + /// + public event EventHandler LayoutChanging; + + /// + /// Event fired when a document is about to be closed + /// + /// Subscribers have the opportuniy to cancel the operation. + public event EventHandler DocumentClosing; + + /// + /// Event fired after a document is closed + /// + public event EventHandler DocumentClosed; + + public event EventHandler ActiveContentChanged; + + #endregion + + #region IOverlayWindowHost Interface + + bool IOverlayWindowHost.HitTest(Point dragPoint) + { + Rect detectionRect = new Rect(this.PointToScreenDPIWithoutFlowDirection(new Point()), this.TransformActualSizeToAncestor()); + return detectionRect.Contains(dragPoint); + } + + DockingManager IOverlayWindowHost.Manager + { + get + { + return this; + } + } + + IOverlayWindow IOverlayWindowHost.ShowOverlayWindow(LayoutFloatingWindowControl draggingWindow) + { + CreateOverlayWindow(); + _overlayWindow.Owner = draggingWindow; + _overlayWindow.EnableDropTargets(); + _overlayWindow.Show(); + return _overlayWindow; + } + + void IOverlayWindowHost.HideOverlayWindow() + { + _areas = null; + _overlayWindow.Owner = null; + _overlayWindow.HideDropTargets(); + } + + IEnumerable IOverlayWindowHost.GetDropAreas(LayoutFloatingWindowControl draggingWindow) + { + if (_areas != null) + return _areas; + + bool isDraggingDocuments = draggingWindow.Model is LayoutDocumentFloatingWindow; + + _areas = new List(); + + if (!isDraggingDocuments) + { + _areas.Add(new DropArea( + this, + DropAreaType.DockingManager)); + + foreach (var areaHost in this.FindVisualChildren()) + { + if (areaHost.Model.Descendents().Any()) + { + _areas.Add(new DropArea( + areaHost, + DropAreaType.AnchorablePane)); + } + } + } + + // Determine if floatingWindow is configured to dock as document or not + bool dockAsDocument = true; + if (isDraggingDocuments == false) + { + var toolWindow = draggingWindow.Model as LayoutAnchorableFloatingWindow; + if (toolWindow != null) + { + foreach (var item in GetAnchorableInFloatingWindow(draggingWindow)) + { + if (item.CanDockAsTabbedDocument == false) + { + dockAsDocument = false; + break; + } + } + } + } + + // Dock only documents and tools in DocumentPane if configuration does allow that + if (dockAsDocument == true) + { + foreach (var areaHost in this.FindVisualChildren()) + { + _areas.Add(new DropArea( + areaHost, + DropAreaType.DocumentPane)); + } + } + + foreach (var areaHost in this.FindVisualChildren()) + { + var documentGroupModel = areaHost.Model as LayoutDocumentPaneGroup; + if (documentGroupModel.Children.Where(c => c.IsVisible).Count() == 0) + { + _areas.Add(new DropArea( + areaHost, + DropAreaType.DocumentPaneGroup)); + } + } + + return _areas; + } + + /// + /// Finds all objects (toolwindows) within a + /// (if any) and return them. + /// + /// + /// + private IEnumerable GetAnchorableInFloatingWindow(LayoutFloatingWindowControl draggingWindow) + { + var layoutAnchorableFloatingWindow = draggingWindow.Model as LayoutAnchorableFloatingWindow; + if (layoutAnchorableFloatingWindow != null) + { + //big part of code for getting type + var layoutAnchorablePane = layoutAnchorableFloatingWindow.SinglePane as LayoutAnchorablePane; + + if (layoutAnchorablePane != null + && (layoutAnchorableFloatingWindow.IsSinglePane + && layoutAnchorablePane.SelectedContent != null)) + { + var layoutAnchorable = ((LayoutAnchorablePane)layoutAnchorableFloatingWindow.SinglePane).SelectedContent as LayoutAnchorable; + yield return layoutAnchorable; + } + else + { + foreach (var item in GetLayoutAnchorable(layoutAnchorableFloatingWindow.RootPanel)) + { + yield return item; + } + } + } + } + + /// + /// Finds all objects (toolwindows) within a + /// (if any) and return them. + /// + /// + /// + internal IEnumerable GetLayoutAnchorable(LayoutAnchorablePaneGroup layoutAnchPaneGroup) + { + if (layoutAnchPaneGroup != null) + { + foreach (var anchorable in layoutAnchPaneGroup.Descendents().OfType()) + { + yield return anchorable; + } + } + } + #endregion + } } From c5401c482a8cc0c31afef96d3eab828e24c687b0 Mon Sep 17 00:00:00 2001 From: amolf-se <56731291+amolf-se@users.noreply.github.com> Date: Wed, 30 Oct 2019 08:57:33 +0100 Subject: [PATCH 4/5] Added support for close button on floating document window. Reinstated highlight when window is active. --- .../LayoutDocumentFloatingWindowControl.cs | 68 ++++++++++++++----- .../Xceed.Wpf.AvalonDock/Themes/generic.xaml | 10 +-- 2 files changed, 55 insertions(+), 23 deletions(-) diff --git a/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs b/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs index 558cf800..0c394db3 100644 --- a/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs +++ b/source/Components/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs @@ -46,6 +46,8 @@ internal LayoutDocumentFloatingWindowControl( LayoutDocumentFloatingWindow model { _model = model; HideWindowCommand = new RelayCommand((p) => OnExecuteHideWindowCommand(p), (p) => CanExecuteHideWindowCommand(p)); + CloseWindowCommand = new RelayCommand( ( p ) => OnExecuteCloseWindowCommand( p ), ( p ) => CanExecuteCloseWindowCommand( p ) ); + Closed += (sender, args) => { Owner?.Focus(); }; UpdateThemeResources(); } @@ -56,18 +58,6 @@ internal LayoutDocumentFloatingWindowControl( LayoutDocumentFloatingWindow model #endregion - #region Properties - - //public LayoutItem RootDocumentLayoutItem - //{ - // get - // { - // return _model.Root.Manager.GetLayoutItemFromModel( _model.RootPanel ); - // } - //} - - #endregion - #region Overrides public override ILayoutElement Model @@ -90,7 +80,7 @@ public override ILayoutElement Model /// /// Gets or sets the SingleContentLayoutItem property. This dependency property - /// indicates the layout item of the selected content when is shown a single anchorable pane. + /// indicates the layout item of the selected content when is shown a single document pane. /// public LayoutItem SingleContentLayoutItem { @@ -99,7 +89,7 @@ public LayoutItem SingleContentLayoutItem } /// - /// Handles changes to the SingleContentLayoutItem property. + /// Handles changes to the property. /// private static void OnSingleContentLayoutItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { @@ -107,7 +97,7 @@ private static void OnSingleContentLayoutItemChanged(DependencyObject d, Depende } /// - /// Provides derived classes an opportunity to handle changes to the SingleContentLayoutItem property. + /// Provides derived classes an opportunity to handle changes to the property. /// protected virtual void OnSingleContentLayoutItemChanged(DependencyPropertyChangedEventArgs e) { @@ -192,7 +182,7 @@ protected override void OnClosed( EventArgs e ) private void RootPanelOnChildrenCollectionChanged(object sender, EventArgs e) { - if( _model.RootPanel.Children.Count == 0) + if( _model.RootPanel == null ||_model.RootPanel.Children.Count == 0) { InternalClose(); } @@ -356,6 +346,52 @@ private void OnExecuteHideWindowCommand(object parameter) } #endregion + #region CloseWindowCommand + public ICommand CloseWindowCommand + { + get; + private set; + } + + private bool CanExecuteCloseWindowCommand( object parameter ) + { + var manager = Model?.Root?.Manager; + if( manager == null ) + return false; + + var canExecute = false; + foreach( var document in this.Model.Descendents().OfType().ToArray() ) + { + if( !document.CanClose ) + { + canExecute = false; + break; + } + + if( !(manager.GetLayoutItemFromModel( document ) is LayoutDocumentItem documentLayoutItem) || + documentLayoutItem.CloseCommand == null || + !documentLayoutItem.CloseCommand.CanExecute( parameter ) ) + { + canExecute = false; + break; + } + canExecute = true; + } + + return canExecute; + } + + private void OnExecuteCloseWindowCommand( object parameter ) + { + var manager = Model.Root.Manager; + foreach( var document in this.Model.Descendents().OfType().ToArray() ) + { + var documentLayoutItem = manager.GetLayoutItemFromModel( document ) as LayoutDocumentItem; + documentLayoutItem?.CloseCommand.Execute(parameter); + } + } + + #endregion #endregion } diff --git a/source/Components/Xceed.Wpf.AvalonDock/Themes/generic.xaml b/source/Components/Xceed.Wpf.AvalonDock/Themes/generic.xaml index bbb2b526..df098f0b 100644 --- a/source/Components/Xceed.Wpf.AvalonDock/Themes/generic.xaml +++ b/source/Components/Xceed.Wpf.AvalonDock/Themes/generic.xaml @@ -1062,18 +1062,16 @@ - @@ -1087,14 +1085,12 @@ Value="3" TargetName="WindowBorder" /> - From 49274532eb8d642b0877e96cff43fbb399d5dc8a Mon Sep 17 00:00:00 2001 From: Marco Konijnenburg Date: Fri, 24 Jan 2020 14:16:01 +0100 Subject: [PATCH 5/5] Fixed drag last document floating window placement. Added check for Model.Root not null, or should it always be set somewhere. --- .../Controls/AnchorablePaneDropTarget.cs | 5 - .../Controls/DocumentPaneDropTarget.cs | 271 ++++++++-------- .../Controls/DocumentPaneGroupDropTarget.cs | 4 +- .../AvalonDock/Controls/DragService.cs | 1 + .../LayoutDocumentFloatingWindowControl.cs | 298 ++++++++++++++++-- .../Controls/LayoutDocumentPaneControl.cs | 17 - .../Controls/LayoutFloatingWindowControl.cs | 2 - .../Components/AvalonDock/DockingManager.cs | 43 ++- .../Layout/LayoutDocumentFloatingWindow.cs | 127 ++++++-- .../AvalonDock/Layout/LayoutDocumentPane.cs | 123 +++++--- .../AvalonDock/Layout/LayoutRoot.cs | 15 + 11 files changed, 639 insertions(+), 267 deletions(-) diff --git a/source/Components/AvalonDock/Controls/AnchorablePaneDropTarget.cs b/source/Components/AvalonDock/Controls/AnchorablePaneDropTarget.cs index 00f8372c..3e531140 100644 --- a/source/Components/AvalonDock/Controls/AnchorablePaneDropTarget.cs +++ b/source/Components/AvalonDock/Controls/AnchorablePaneDropTarget.cs @@ -253,11 +253,6 @@ protected override void Drop(LayoutAnchorableFloatingWindow floatingWindow) public override System.Windows.Media.Geometry GetPreviewPath(OverlayWindow overlayWindow, LayoutFloatingWindow floatingWindowModel) { - //var anchorablePaneDropTarget = target as AnchorablePaneDropTarget; - var anchorableFloatingWindowModel = floatingWindowModel as LayoutAnchorableFloatingWindow; - var layoutAnchorablePane = anchorableFloatingWindowModel.RootPanel as ILayoutPositionableElement; - var layoutAnchorablePaneWithActualSize = anchorableFloatingWindowModel.RootPanel as ILayoutPositionableElementWithActualSize; - switch (Type) { case DropTargetType.AnchorablePaneDockBottom: diff --git a/source/Components/AvalonDock/Controls/DocumentPaneDropTarget.cs b/source/Components/AvalonDock/Controls/DocumentPaneDropTarget.cs index 4df1b3df..c5dafede 100644 --- a/source/Components/AvalonDock/Controls/DocumentPaneDropTarget.cs +++ b/source/Components/AvalonDock/Controls/DocumentPaneDropTarget.cs @@ -45,185 +45,206 @@ internal DocumentPaneDropTarget(LayoutDocumentPaneControl paneControl, Rect dete protected override void Drop(LayoutDocumentFloatingWindow floatingWindow) { ILayoutDocumentPane targetModel = _targetPane.Model as ILayoutDocumentPane; + LayoutDocument documentActive = floatingWindow.Descendents().OfType().FirstOrDefault(); switch (Type) { case DropTargetType.DocumentPaneDockBottom: #region DropTargetType.DocumentPaneDockBottom - { - var newLayoutDocumentPane = new LayoutDocumentPane(floatingWindow.RootDocument); - var parentModel = targetModel.Parent as LayoutDocumentPaneGroup; + { + var parentModel = targetModel.Parent as ILayoutGroup; + var parentModelOrientable = targetModel.Parent as ILayoutOrientableGroup; + int insertToIndex = parentModel.IndexOfChild(targetModel); - if (parentModel == null) + if (parentModelOrientable.Orientation != System.Windows.Controls.Orientation.Vertical && + parentModel.ChildrenCount == 1) + parentModelOrientable.Orientation = System.Windows.Controls.Orientation.Vertical; + + if (parentModelOrientable.Orientation == System.Windows.Controls.Orientation.Vertical) + { + var layoutDocumentPaneGroup = floatingWindow.RootPanel as LayoutDocumentPaneGroup; + if (layoutDocumentPaneGroup != null && + (layoutDocumentPaneGroup.Children.Count == 1 || + layoutDocumentPaneGroup.Orientation == System.Windows.Controls.Orientation.Vertical)) { - var parentContainer = targetModel.Parent as ILayoutContainer; - var newParentModel = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Vertical }; - parentContainer.ReplaceChild(targetModel, newParentModel); - newParentModel.Children.Add(targetModel as LayoutDocumentPane); - newParentModel.Children.Add(newLayoutDocumentPane); + var documentsToMove = layoutDocumentPaneGroup.Children.ToArray(); + for (int i = 0; i < documentsToMove.Length; i++) + parentModel.InsertChildAt(insertToIndex + 1 + i, documentsToMove[i]); } else + parentModel.InsertChildAt(insertToIndex + 1, floatingWindow.RootPanel); + } + else + { + var targetModelAsPositionableElement = targetModel as ILayoutPositionableElement; + var newOrientedPanel = new LayoutDocumentPaneGroup() { - var manager = parentModel.Root.Manager; - if (!manager.AllowMixedOrientation || parentModel.Orientation == System.Windows.Controls.Orientation.Vertical) - { - parentModel.Orientation = System.Windows.Controls.Orientation.Vertical; - int targetPaneIndex = parentModel.IndexOfChild(targetModel); - parentModel.Children.Insert(targetPaneIndex + 1, newLayoutDocumentPane); - } - else - { - LayoutDocumentPaneGroup newChildGroup = new LayoutDocumentPaneGroup(); - newChildGroup.Orientation = System.Windows.Controls.Orientation.Vertical; - parentModel.ReplaceChild(targetModel, newChildGroup); - newChildGroup.Children.Add(targetModel); - newChildGroup.Children.Add(newLayoutDocumentPane); - } + Orientation = System.Windows.Controls.Orientation.Vertical, + DockWidth = targetModelAsPositionableElement.DockWidth, + DockHeight = targetModelAsPositionableElement.DockHeight, + }; + + parentModel.InsertChildAt(insertToIndex, newOrientedPanel); + newOrientedPanel.Children.Add(targetModel); + newOrientedPanel.Children.Add(floatingWindow.RootPanel); - } } + } break; + #endregion case DropTargetType.DocumentPaneDockTop: #region DropTargetType.DocumentPaneDockTop - { - var newLayoutDocumentPane = new LayoutDocumentPane(floatingWindow.RootDocument); - var parentModel = targetModel.Parent as LayoutDocumentPaneGroup; + { + var parentModel = targetModel.Parent as ILayoutGroup; + var parentModelOrientable = targetModel.Parent as ILayoutOrientableGroup; + int insertToIndex = parentModel.IndexOfChild(targetModel); - if (parentModel == null) + if (parentModelOrientable.Orientation != System.Windows.Controls.Orientation.Vertical && + parentModel.ChildrenCount == 1) + parentModelOrientable.Orientation = System.Windows.Controls.Orientation.Vertical; + + if (parentModelOrientable.Orientation == System.Windows.Controls.Orientation.Vertical) + { + var layoutDocumentPaneGroup = floatingWindow.RootPanel as LayoutDocumentPaneGroup; + if (layoutDocumentPaneGroup != null && + (layoutDocumentPaneGroup.Children.Count == 1 || + layoutDocumentPaneGroup.Orientation == System.Windows.Controls.Orientation.Vertical)) { - var parentContainer = targetModel.Parent as ILayoutContainer; - var newParentModel = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Vertical }; - parentContainer.ReplaceChild(targetModel, newParentModel); - newParentModel.Children.Add(targetModel as LayoutDocumentPane); - newParentModel.Children.Insert(0, newLayoutDocumentPane); + var documentsToMove = layoutDocumentPaneGroup.Children.ToArray(); + for (int i = 0; i < documentsToMove.Length; i++) + parentModel.InsertChildAt(insertToIndex + i, documentsToMove[i]); } else + parentModel.InsertChildAt(insertToIndex, floatingWindow.RootPanel); + } + else + { + var targetModelAsPositionableElement = targetModel as ILayoutPositionableElement; + var newOrientedPanel = new LayoutDocumentPaneGroup() { - var manager = parentModel.Root.Manager; - if (!manager.AllowMixedOrientation || parentModel.Orientation == System.Windows.Controls.Orientation.Vertical) - { - parentModel.Orientation = System.Windows.Controls.Orientation.Vertical; - int targetPaneIndex = parentModel.IndexOfChild(targetModel); - parentModel.Children.Insert(targetPaneIndex, newLayoutDocumentPane); - } - else - { - LayoutDocumentPaneGroup newChildGroup = new LayoutDocumentPaneGroup(); - newChildGroup.Orientation = System.Windows.Controls.Orientation.Vertical; - parentModel.ReplaceChild(targetModel, newChildGroup); - newChildGroup.Children.Add(newLayoutDocumentPane); - newChildGroup.Children.Add(targetModel); - } + Orientation = System.Windows.Controls.Orientation.Vertical, + DockWidth = targetModelAsPositionableElement.DockWidth, + DockHeight = targetModelAsPositionableElement.DockHeight, + }; + + parentModel.InsertChildAt(insertToIndex, newOrientedPanel); + //the floating window must be added after the target modal as it could be raise a CollectGarbage call + newOrientedPanel.Children.Add(targetModel); + newOrientedPanel.Children.Insert(0, floatingWindow.RootPanel); - } } + } break; #endregion case DropTargetType.DocumentPaneDockLeft: #region DropTargetType.DocumentPaneDockLeft - { - var newLayoutDocumentPane = new LayoutDocumentPane(floatingWindow.RootDocument); - var parentModel = targetModel.Parent as LayoutDocumentPaneGroup; + { + var parentModel = targetModel.Parent as ILayoutGroup; + var parentModelOrientable = targetModel.Parent as ILayoutOrientableGroup; + int insertToIndex = parentModel.IndexOfChild(targetModel); - if (parentModel == null) + if (parentModelOrientable.Orientation != System.Windows.Controls.Orientation.Horizontal && + parentModel.ChildrenCount == 1) + parentModelOrientable.Orientation = System.Windows.Controls.Orientation.Horizontal; + + if (parentModelOrientable.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + var layoutDocumentPaneGroup = floatingWindow.RootPanel as LayoutDocumentPaneGroup; + if (layoutDocumentPaneGroup != null && + (layoutDocumentPaneGroup.Children.Count == 1 || + layoutDocumentPaneGroup.Orientation == System.Windows.Controls.Orientation.Horizontal)) { - var parentContainer = targetModel.Parent as ILayoutContainer; - var newParentModel = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Horizontal }; - parentContainer.ReplaceChild(targetModel, newParentModel); - newParentModel.Children.Add(targetModel); - newParentModel.Children.Insert(0, newLayoutDocumentPane); + var documentsToMove = layoutDocumentPaneGroup.Children.ToArray(); + for (int i = 0; i < documentsToMove.Length; i++) + parentModel.InsertChildAt(insertToIndex + i, documentsToMove[i]); } else + parentModel.InsertChildAt(insertToIndex, floatingWindow.RootPanel); + } + else + { + var targetModelAsPositionableElement = targetModel as ILayoutPositionableElement; + var newOrientedPanel = new LayoutDocumentPaneGroup() { - var manager = parentModel.Root.Manager; - if (!manager.AllowMixedOrientation || parentModel.Orientation == System.Windows.Controls.Orientation.Horizontal) - { - parentModel.Orientation = System.Windows.Controls.Orientation.Horizontal; - int targetPaneIndex = parentModel.IndexOfChild(targetModel); - parentModel.Children.Insert(targetPaneIndex, newLayoutDocumentPane); - } - else - { - LayoutDocumentPaneGroup newChildGroup = new LayoutDocumentPaneGroup(); - newChildGroup.Orientation = System.Windows.Controls.Orientation.Horizontal; - parentModel.ReplaceChild(targetModel, newChildGroup); - newChildGroup.Children.Add(newLayoutDocumentPane); - newChildGroup.Children.Add(targetModel); - } - } + Orientation = System.Windows.Controls.Orientation.Horizontal, + DockWidth = targetModelAsPositionableElement.DockWidth, + DockHeight = targetModelAsPositionableElement.DockHeight, + }; + + parentModel.InsertChildAt(insertToIndex, newOrientedPanel); + //the floating window must be added after the target modal as it could be raise a CollectGarbage call + newOrientedPanel.Children.Add(targetModel); + newOrientedPanel.Children.Insert(0, floatingWindow.RootPanel); + } + } break; #endregion case DropTargetType.DocumentPaneDockRight: #region DropTargetType.DocumentPaneDockRight - { - var newLayoutDocumentPane = new LayoutDocumentPane(floatingWindow.RootDocument); - var parentModel = targetModel.Parent as LayoutDocumentPaneGroup; + { + var parentModel = targetModel.Parent as ILayoutGroup; + var parentModelOrientable = targetModel.Parent as ILayoutOrientableGroup; + int insertToIndex = parentModel.IndexOfChild(targetModel); - if (parentModel == null) + if (parentModelOrientable.Orientation != System.Windows.Controls.Orientation.Horizontal && + parentModel.ChildrenCount == 1) + parentModelOrientable.Orientation = System.Windows.Controls.Orientation.Horizontal; + + if (parentModelOrientable.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + var layoutDocumentPaneGroup = floatingWindow.RootPanel as LayoutDocumentPaneGroup; + if (layoutDocumentPaneGroup != null && + (layoutDocumentPaneGroup.Children.Count == 1 || + layoutDocumentPaneGroup.Orientation == System.Windows.Controls.Orientation.Horizontal)) { - var parentContainer = targetModel.Parent as ILayoutContainer; - var newParentModel = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Horizontal }; - parentContainer.ReplaceChild(targetModel, newParentModel); - newParentModel.Children.Add(targetModel as LayoutDocumentPane); - newParentModel.Children.Add(newLayoutDocumentPane); + var documentToMove = layoutDocumentPaneGroup.Children.ToArray(); + for (int i = 0; i < documentToMove.Length; i++) + parentModel.InsertChildAt(insertToIndex + 1 + i, documentToMove[i]); } else + parentModel.InsertChildAt(insertToIndex + 1, floatingWindow.RootPanel); + } + else + { + var targetModelAsPositionableElement = targetModel as ILayoutPositionableElement; + var newOrientedPanel = new LayoutDocumentPaneGroup() { - var manager = parentModel.Root.Manager; - if (!manager.AllowMixedOrientation || parentModel.Orientation == System.Windows.Controls.Orientation.Horizontal) - { - parentModel.Orientation = System.Windows.Controls.Orientation.Horizontal; - int targetPaneIndex = parentModel.IndexOfChild(targetModel); - parentModel.Children.Insert(targetPaneIndex + 1, newLayoutDocumentPane); - } - else - { - LayoutDocumentPaneGroup newChildGroup = new LayoutDocumentPaneGroup(); - newChildGroup.Orientation = System.Windows.Controls.Orientation.Horizontal; - parentModel.ReplaceChild(targetModel, newChildGroup); - newChildGroup.Children.Add(targetModel); - newChildGroup.Children.Add(newLayoutDocumentPane); - } + Orientation = System.Windows.Controls.Orientation.Horizontal, + DockWidth = targetModelAsPositionableElement.DockWidth, + DockHeight = targetModelAsPositionableElement.DockHeight, + }; + + parentModel.InsertChildAt(insertToIndex, newOrientedPanel); + newOrientedPanel.Children.Add(targetModel); + newOrientedPanel.Children.Add(floatingWindow.RootPanel); - } } + } break; #endregion case DropTargetType.DocumentPaneDockInside: #region DropTargetType.DocumentPaneDockInside - { - var paneModel = targetModel as LayoutDocumentPane; - var sourceModel = floatingWindow.RootDocument; + { + var paneModel = targetModel as LayoutDocumentPane; + var layoutDocumentPaneGroup = floatingWindow.RootPanel as LayoutDocumentPaneGroup; - int i = 0; - if (_tabIndex != -1) - { - i = _tabIndex; - } - else - { - var previousIndex = 0; - var previousContainer = ((ILayoutPreviousContainer)sourceModel).PreviousContainer; - if (object.ReferenceEquals(previousContainer, targetModel) && (sourceModel.PreviousContainerIndex != -1)) - { - previousIndex = sourceModel.PreviousContainerIndex; - } - - i = previousIndex; - } - sourceModel.IsActive = false; - paneModel.Children.Insert(System.Math.Min(paneModel.Children.Count, i), sourceModel); - sourceModel.IsActive = true; + int i = _tabIndex == -1 ? 0 : _tabIndex; + foreach (var anchorableToImport in + layoutDocumentPaneGroup.Descendents().OfType().ToArray()) + { + paneModel.Children.Insert(i, anchorableToImport); + i++; } + } break; - #endregion - - + #endregion } + documentActive.IsActive = true; + base.Drop(floatingWindow); } diff --git a/source/Components/AvalonDock/Controls/DocumentPaneGroupDropTarget.cs b/source/Components/AvalonDock/Controls/DocumentPaneGroupDropTarget.cs index 5e249d76..7a41da17 100644 --- a/source/Components/AvalonDock/Controls/DocumentPaneGroupDropTarget.cs +++ b/source/Components/AvalonDock/Controls/DocumentPaneGroupDropTarget.cs @@ -44,8 +44,8 @@ protected override void Drop(LayoutDocumentFloatingWindow floatingWindow) #region DropTargetType.DocumentPaneGroupDockInside { var paneGroupModel = targetModel as LayoutDocumentPaneGroup; - var paneModel = paneGroupModel.Children[0] as LayoutDocumentPane; - var sourceModel = floatingWindow.RootDocument; + var paneModel = paneGroupModel as LayoutDocumentPaneGroup; + var sourceModel = floatingWindow.RootPanel as LayoutDocumentPaneGroup; paneModel.Children.Insert(0, sourceModel); } diff --git a/source/Components/AvalonDock/Controls/DragService.cs b/source/Components/AvalonDock/Controls/DragService.cs index cfc0f1f9..4ed0c635 100644 --- a/source/Components/AvalonDock/Controls/DragService.cs +++ b/source/Components/AvalonDock/Controls/DragService.cs @@ -186,6 +186,7 @@ internal void Abort() private void GetOverlayWindowHosts() { _overlayWindowHosts.AddRange(_manager.GetFloatingWindowsByZOrder().OfType().Where(fw => fw != _floatingWindow && fw.IsVisible)); + _overlayWindowHosts.AddRange(_manager.GetFloatingWindowsByZOrder().OfType().Where(fw => fw != _floatingWindow && fw.IsVisible)); _overlayWindowHosts.Add(_manager); } diff --git a/source/Components/AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs b/source/Components/AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs index f2c981c8..bbd210af 100644 --- a/source/Components/AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs +++ b/source/Components/AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs @@ -8,14 +8,18 @@ This program is provided to you under the terms of the Microsoft Public ************************************************************************/ using System; +using System.Collections.Generic; +using System.Linq; using AvalonDock.Layout; using System.Windows; using System.Windows.Controls.Primitives; +using System.Windows.Input; +using AvalonDock.Commands; using Microsoft.Windows.Shell; namespace AvalonDock.Controls { - public class LayoutDocumentFloatingWindowControl : LayoutFloatingWindowControl + public class LayoutDocumentFloatingWindowControl : LayoutFloatingWindowControl, IOverlayWindowHost { #region Members @@ -34,6 +38,9 @@ internal LayoutDocumentFloatingWindowControl(LayoutDocumentFloatingWindow model, : base(model, isContentImmutable) { _model = model; + HideWindowCommand = new RelayCommand((p) => OnExecuteHideWindowCommand(p), (p) => CanExecuteHideWindowCommand(p)); + CloseWindowCommand = new RelayCommand((p) => OnExecuteCloseWindowCommand(p), (p) => CanExecuteCloseWindowCommand(p)); + Closed += (sender, args) => { Owner?.Focus(); }; UpdateThemeResources(); } @@ -44,43 +51,72 @@ internal LayoutDocumentFloatingWindowControl(LayoutDocumentFloatingWindow model) #endregion - #region Properties + #region Overrides - public LayoutItem RootDocumentLayoutItem + public override ILayoutElement Model { get { - return _model.Root.Manager.GetLayoutItemFromModel(_model.RootDocument); + return _model; } } - #endregion + #region SingleContentLayoutItem + + /// + /// SingleContentLayoutItem Dependency Property + /// + public static readonly DependencyProperty SingleContentLayoutItemProperty = + DependencyProperty.Register("SingleContentLayoutItem", typeof(LayoutItem), typeof(LayoutDocumentFloatingWindowControl), + new FrameworkPropertyMetadata((LayoutItem)null, + new PropertyChangedCallback(OnSingleContentLayoutItemChanged))); + + /// + /// Gets or sets the SingleContentLayoutItem property. This dependency property + /// indicates the layout item of the selected content when is shown a single document pane. + /// + public LayoutItem SingleContentLayoutItem + { + get { return (LayoutItem)GetValue(SingleContentLayoutItemProperty); } + set { SetValue(SingleContentLayoutItemProperty, value); } + } - #region Overrides + /// + /// Handles changes to the property. + /// + private static void OnSingleContentLayoutItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutDocumentFloatingWindowControl)d).OnSingleContentLayoutItemChanged(e); + } - public override ILayoutElement Model + /// + /// Provides derived classes an opportunity to handle changes to the property. + /// + protected virtual void OnSingleContentLayoutItemChanged(DependencyPropertyChangedEventArgs e) { - get - { - return _model; - } } + #endregion + protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); - if (_model.RootDocument == null) - { - InternalClose(); - } - else - { - var manager = _model.Root.Manager; + var manager = _model.Root.Manager; - Content = manager.CreateUIElementForModel(_model.RootDocument); + Content = manager.CreateUIElementForModel(_model.RootPanel); + // TODO IsVisibleChanged + //SetBinding(SingleContentLayoutItemProperty, new Binding("Model.SinglePane.SelectedContent") { Source = this, Converter = new LayoutItemFromLayoutModelConverter() }); - _model.RootDocumentChanged += new EventHandler(_model_RootDocumentChanged); + _model.RootPanel.ChildrenCollectionChanged += RootPanelOnChildrenCollectionChanged; + } + + void _model_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (e.PropertyName == "RootPanel" && + _model.RootPanel == null) + { + InternalClose(); } } @@ -91,8 +127,8 @@ protected override IntPtr FilterMessage(IntPtr hwnd, int msg, IntPtr wParam, Int case Win32Helper.WM_NCLBUTTONDOWN: //Left button down on title -> start dragging over docking manager if (wParam.ToInt32() == Win32Helper.HT_CAPTION) { - if (_model.RootDocument != null) - _model.RootDocument.IsActive = true; + _model.Descendents().OfType().First(p => p.ChildrenCount > 0 && p.SelectedContent != null).SelectedContent.IsActive = true; + handled = true; } break; case Win32Helper.WM_NCRBUTTONUP: @@ -115,26 +151,36 @@ protected override IntPtr FilterMessage(IntPtr hwnd, int msg, IntPtr wParam, Int protected override void OnClosed(EventArgs e) { var root = Model.Root; - root.Manager.RemoveFloatingWindow(this); - root.CollectGarbage(); + // MK sometimes root is null, prevent crash, or should it always be set?? + if (root != null) + { + root.Manager.RemoveFloatingWindow(this); + root.CollectGarbage(); + } + + if (_overlayWindow != null) + { + _overlayWindow.Close(); + _overlayWindow = null; + } base.OnClosed(e); if (!CloseInitiatedByUser) { - root.FloatingWindows.Remove(_model); + root?.FloatingWindows.Remove(_model); } - _model.RootDocumentChanged -= new EventHandler(_model_RootDocumentChanged); + _model.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler(_model_PropertyChanged); } #endregion #region Private Methods - private void _model_RootDocumentChanged(object sender, EventArgs e) + private void RootPanelOnChildrenCollectionChanged(object sender, EventArgs e) { - if (_model.RootDocument == null) + if( _model.RootPanel == null ||_model.RootPanel.Children.Count == 0) { InternalClose(); } @@ -143,11 +189,11 @@ private void _model_RootDocumentChanged(object sender, EventArgs e) private bool OpenContextMenu() { var ctxMenu = _model.Root.Manager.DocumentContextMenu; - if (ctxMenu != null && RootDocumentLayoutItem != null) + if (ctxMenu != null && SingleContentLayoutItem != null) { ctxMenu.PlacementTarget = null; ctxMenu.Placement = PlacementMode.MousePoint; - ctxMenu.DataContext = RootDocumentLayoutItem; + ctxMenu.DataContext = SingleContentLayoutItem; ctxMenu.IsOpen = true; return true; } @@ -155,6 +201,196 @@ private bool OpenContextMenu() return false; } + protected override void OnClosing(System.ComponentModel.CancelEventArgs e) + { + // TODO + if (CloseInitiatedByUser && !KeepContentVisibleOnClose) + { + e.Cancel = true; + //_model.Descendents().OfType().ToArray().ForEach((a) => a.Hide()); + } + + base.OnClosing(e); + } + + bool IOverlayWindowHost.HitTest(Point dragPoint) + { + Rect detectionRect = new Rect(this.PointToScreenDPIWithoutFlowDirection(new Point()), this.TransformActualSizeToAncestor()); + return detectionRect.Contains(dragPoint); + } + + DockingManager IOverlayWindowHost.Manager + { + get { return _model.Root.Manager; } + } + + OverlayWindow _overlayWindow = null; + + void CreateOverlayWindow() + { + if (_overlayWindow == null) + _overlayWindow = new OverlayWindow(this); + Rect rectWindow = new Rect(this.PointToScreenDPIWithoutFlowDirection(new Point()), this.TransformActualSizeToAncestor()); + _overlayWindow.Left = rectWindow.Left; + _overlayWindow.Top = rectWindow.Top; + _overlayWindow.Width = rectWindow.Width; + _overlayWindow.Height = rectWindow.Height; + } + + IOverlayWindow IOverlayWindowHost.ShowOverlayWindow(LayoutFloatingWindowControl draggingWindow) + { + CreateOverlayWindow(); + _overlayWindow.Owner = draggingWindow; + _overlayWindow.EnableDropTargets(); + _overlayWindow.Show(); + + return _overlayWindow; + } + + public void HideOverlayWindow() + { + _dropAreas = null; + _overlayWindow.Owner = null; + _overlayWindow.HideDropTargets(); + } + + List _dropAreas = null; + public IEnumerable GetDropAreas(LayoutFloatingWindowControl draggingWindow) + { + if (_dropAreas != null) + return _dropAreas; + + _dropAreas = new List(); + + var rootVisual = (Content as FloatingWindowContentHost).RootVisual; + + foreach (var areaHost in rootVisual.FindVisualChildren()) + { + _dropAreas.Add(new DropArea( + areaHost, + DropAreaType.AnchorablePane)); + } + foreach (var areaHost in rootVisual.FindVisualChildren()) + { + _dropAreas.Add(new DropArea( + areaHost, + DropAreaType.DocumentPane)); + } + + return _dropAreas; + } + + #region HideWindowCommand + public ICommand HideWindowCommand + { + get; + private set; + } + + private bool CanExecuteHideWindowCommand(object parameter) + { + if (Model == null) + return false; + + var root = Model.Root; + if (root == null) + return false; + + var manager = root.Manager; + if (manager == null) + return false; + + // TODO check CanHide of anchorables + bool canExecute = false; + foreach (var content in this.Model.Descendents().OfType().ToArray()) + { + if ((content is LayoutAnchorable anchorable && !anchorable.CanHide) || + !content.CanClose) + { + canExecute = false; + break; + } + + //if (!(manager.GetLayoutItemFromModel(content) is LayoutAnchorableItem layoutAnchorableItem) || + // layoutAnchorableItem.HideCommand == null || + // !layoutAnchorableItem.HideCommand.CanExecute(parameter)) + //{ + // canExecute = false; + // break; + //} + if (!(manager.GetLayoutItemFromModel(content) is LayoutItem layoutItem) || + layoutItem.CloseCommand == null || + !layoutItem.CloseCommand.CanExecute(parameter)) + { + canExecute = false; + break; + } + + canExecute = true; + } + + return canExecute; + } + + private void OnExecuteHideWindowCommand(object parameter) + { + var manager = Model.Root.Manager; + foreach (var anchorable in this.Model.Descendents().OfType().ToArray()) + { + //if (manager.GetLayoutItemFromModel(anchorable) is LayoutAnchorableItem layoutAnchorableItem) layoutAnchorableItem.HideCommand.Execute(parameter); + //else + if (manager.GetLayoutItemFromModel(anchorable) is LayoutItem layoutItem) layoutItem.CloseCommand.Execute(parameter); + } + } + #endregion + + #region CloseWindowCommand + public ICommand CloseWindowCommand + { + get; + private set; + } + + private bool CanExecuteCloseWindowCommand( object parameter ) + { + var manager = Model?.Root?.Manager; + if( manager == null ) + return false; + + var canExecute = false; + foreach( var document in this.Model.Descendents().OfType().ToArray() ) + { + if( !document.CanClose ) + { + canExecute = false; + break; + } + + if( !(manager.GetLayoutItemFromModel( document ) is LayoutDocumentItem documentLayoutItem) || + documentLayoutItem.CloseCommand == null || + !documentLayoutItem.CloseCommand.CanExecute( parameter ) ) + { + canExecute = false; + break; + } + canExecute = true; + } + + return canExecute; + } + + private void OnExecuteCloseWindowCommand( object parameter ) + { + var manager = Model.Root.Manager; + foreach( var document in this.Model.Descendents().OfType().ToArray() ) + { + var documentLayoutItem = manager.GetLayoutItemFromModel( document ) as LayoutDocumentItem; + documentLayoutItem?.CloseCommand.Execute(parameter); + } + } + #endregion - } + + #endregion + } } diff --git a/source/Components/AvalonDock/Controls/LayoutDocumentPaneControl.cs b/source/Components/AvalonDock/Controls/LayoutDocumentPaneControl.cs index 293d51aa..4e7563b4 100644 --- a/source/Components/AvalonDock/Controls/LayoutDocumentPaneControl.cs +++ b/source/Components/AvalonDock/Controls/LayoutDocumentPaneControl.cs @@ -20,7 +20,6 @@ public class LayoutDocumentPaneControl : TabControl, ILayoutControl//, ILogicalC { #region Members - private List _logicalChildren = new List(); private LayoutDocumentPane _model; #endregion @@ -62,22 +61,6 @@ public ILayoutElement Model #region Overrides - protected override System.Collections.IEnumerator LogicalChildren - { - get - { - return _logicalChildren.GetEnumerator(); - } - } - - protected override void OnSelectionChanged(SelectionChangedEventArgs e) - { - base.OnSelectionChanged(e); - - if (_model.SelectedContent != null) - _model.SelectedContent.IsActive = true; - } - protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); diff --git a/source/Components/AvalonDock/Controls/LayoutFloatingWindowControl.cs b/source/Components/AvalonDock/Controls/LayoutFloatingWindowControl.cs index 5a5ea4dd..34c17b60 100644 --- a/source/Components/AvalonDock/Controls/LayoutFloatingWindowControl.cs +++ b/source/Components/AvalonDock/Controls/LayoutFloatingWindowControl.cs @@ -483,8 +483,6 @@ private void OnActivated(object sender, EventArgs e) { IntPtr windowHandle = new WindowInteropHelper(this).Handle; var mousePosition = this.PointToScreenDPI(Mouse.GetPosition(this)); - var clientArea = Win32Helper.GetClientRect(windowHandle); - var windowArea = Win32Helper.GetWindowRect(windowHandle); // BugFix Issue #6 // This code is initializes the drag when content (document or toolwindow) is dragged diff --git a/source/Components/AvalonDock/DockingManager.cs b/source/Components/AvalonDock/DockingManager.cs index cf6155e8..18ba44d2 100644 --- a/source/Components/AvalonDock/DockingManager.cs +++ b/source/Components/AvalonDock/DockingManager.cs @@ -2132,7 +2132,7 @@ internal UIElement CreateUIElementForModel(ILayoutElement model) }; newFW.SetParentToMainWindowOf(this); - var paneForExtensions = modelFW.RootDocument; + var paneForExtensions = modelFW.RootPanel; if (paneForExtensions != null) { //ensure that floating window position is inside current (or nearest) monitor @@ -2201,15 +2201,31 @@ internal void StartDraggingFloatingWindowForContent(LayoutContent contentModel, if (contentModel.CanFloat == false) return; - var fwc = this.CreateFloatingWindow(contentModel, false); + LayoutFloatingWindowControl fwc = null; + + // For last document re-use floating window + if (contentModel.Parent.ChildrenCount == 1) + { + foreach (var fw in _fwList) + foreach (var layoutElement in ((LayoutDocumentFloatingWindow)fw.Model).Children) + foreach (var pane in ((LayoutDocumentPaneGroup)layoutElement).Children) + foreach (var layoutDoc in ((LayoutDocumentPane)pane).Children) + if (layoutDoc == contentModel) + fwc = fw; + } + + var show = fwc == null; // Do not show already visible floating window + if (fwc == null) + fwc = this.CreateFloatingWindow(contentModel, false); + if (fwc != null) { Dispatcher.BeginInvoke(new Action(() => - { - if (startDrag) - fwc.AttachDrag(); - fwc.Show(); - }), DispatcherPriority.Send); + { + // Activate only inactive document + if (startDrag) fwc.AttachDrag(); + if (show) fwc.Show(); + }), DispatcherPriority.Send); } } @@ -3330,7 +3346,18 @@ private LayoutFloatingWindowControl CreateFloatingWindowCore(LayoutContent conte var anchorableDocument = contentModel as LayoutDocument; fw = new LayoutDocumentFloatingWindow() { - RootDocument = anchorableDocument + RootPanel = new LayoutDocumentPaneGroup( + new LayoutDocumentPane(anchorableDocument) + { + DockWidth = parentPaneAsPositionableElement.DockWidth, + DockHeight = parentPaneAsPositionableElement.DockHeight, + DockMinHeight = parentPaneAsPositionableElement.DockMinHeight, + DockMinWidth = parentPaneAsPositionableElement.DockMinWidth, + FloatingLeft = parentPaneAsPositionableElement.FloatingLeft, + FloatingTop = parentPaneAsPositionableElement.FloatingTop, + FloatingWidth = parentPaneAsPositionableElement.FloatingWidth, + FloatingHeight = parentPaneAsPositionableElement.FloatingHeight, + }) }; Layout.FloatingWindows.Add(fw); diff --git a/source/Components/AvalonDock/Layout/LayoutDocumentFloatingWindow.cs b/source/Components/AvalonDock/Layout/LayoutDocumentFloatingWindow.cs index a85ac2d6..a67e1ec8 100644 --- a/source/Components/AvalonDock/Layout/LayoutDocumentFloatingWindow.cs +++ b/source/Components/AvalonDock/Layout/LayoutDocumentFloatingWindow.cs @@ -11,14 +11,15 @@ This program is provided to you under the terms of the Microsoft Public using System.Collections.Generic; using System.Windows.Markup; using System.Diagnostics; +using System.Linq; using System.Xml.Serialization; using System.Xml; namespace AvalonDock.Layout { - [ContentProperty("RootDocument")] + [ContentProperty("RootPanel")] [Serializable] - public class LayoutDocumentFloatingWindow : LayoutFloatingWindow + public class LayoutDocumentFloatingWindow : LayoutFloatingWindow, ILayoutElementWithVisibility { #region Constructors @@ -30,31 +31,68 @@ public LayoutDocumentFloatingWindow() #region Properties - #region RootDocument + #region RootPanel - private LayoutDocument _rootDocument = null; - public LayoutDocument RootDocument + private LayoutDocumentPaneGroup _rootPanel = null; + public LayoutDocumentPaneGroup RootPanel { get { - return _rootDocument; + return _rootPanel; } set { - if (_rootDocument != value) + if( _rootPanel != value ) { - RaisePropertyChanging("RootDocument"); - _rootDocument = value; - if (_rootDocument != null) - _rootDocument.Parent = this; - RaisePropertyChanged("RootDocument"); - - if (RootDocumentChanged != null) - RootDocumentChanged(this, EventArgs.Empty); + if (_rootPanel != null) + _rootPanel.ChildrenTreeChanged -= new EventHandler(_rootPanel_ChildrenTreeChanged); + + _rootPanel = value; + if (_rootPanel != null) + _rootPanel.Parent = this; + + if (_rootPanel != null) + _rootPanel.ChildrenTreeChanged += new EventHandler(_rootPanel_ChildrenTreeChanged); + + RaisePropertyChanged("RootPanel"); + RaisePropertyChanged("IsSinglePane"); + RaisePropertyChanged("SinglePane"); + RaisePropertyChanged("Children"); + RaisePropertyChanged("ChildrenCount"); + ((ILayoutElementWithVisibility)this).ComputeVisibility(); } } } + void _rootPanel_ChildrenTreeChanged(object sender, ChildrenTreeChangedEventArgs e) + { + RaisePropertyChanged("IsSinglePane"); + RaisePropertyChanged("SinglePane"); + + } + + public bool IsSinglePane + { + get + { + return RootPanel != null && RootPanel.Descendents().OfType().Where(p => p.IsVisible).Count() == 1; + } + } + + public ILayoutDocumentPane SinglePane + { + get + { + if (!IsSinglePane) + return null; + + var singlePane = RootPanel.Descendents().OfType().Single(p => p.IsVisible); + //singlePane.UpdateIsDirectlyHostedInFloatingWindow(); + return singlePane; + } + } + + #endregion #endregion @@ -65,38 +103,67 @@ public override IEnumerable Children { get { - if (RootDocument == null) - yield break; - - yield return RootDocument; + if (ChildrenCount == 1) + yield return RootPanel; } } public override void RemoveChild(ILayoutElement element) { - Debug.Assert(element == RootDocument && element != null); - RootDocument = null; + Debug.Assert( element == RootPanel && element != null ); + RootPanel = null; } public override void ReplaceChild(ILayoutElement oldElement, ILayoutElement newElement) { - Debug.Assert(oldElement == RootDocument && oldElement != null); - RootDocument = newElement as LayoutDocument; + Debug.Assert( oldElement == RootPanel && oldElement != null ); + RootPanel = newElement as LayoutDocumentPaneGroup; } public override int ChildrenCount { get { - return RootDocument != null ? 1 : 0; + return RootPanel == null ? 0 : 1; } } + #region IsVisible + [NonSerialized] + private bool _isVisible = true; + + [XmlIgnore] + public bool IsVisible + { + get { return _isVisible; } + private set + { + if (_isVisible != value) + { + RaisePropertyChanging("IsVisible"); + _isVisible = value; + RaisePropertyChanged("IsVisible"); + if (IsVisibleChanged != null) + IsVisibleChanged(this, EventArgs.Empty); + } + } + } + + public event EventHandler IsVisibleChanged; + + #endregion + + void ILayoutElementWithVisibility.ComputeVisibility() + { + IsVisible = RootPanel != null && RootPanel.IsVisible; + } + + public override bool IsValid { get { - return RootDocument != null; + return RootPanel != null; } } @@ -140,7 +207,7 @@ public override void ReadXml(XmlReader reader) serializer = new XmlSerializer(type); } - RootDocument = (LayoutDocument)serializer.Deserialize(reader); + RootPanel = (LayoutDocumentPaneGroup)serializer.Deserialize(reader); } reader.ReadEndElement(); @@ -152,16 +219,10 @@ public override void ConsoleDump(int tab) System.Diagnostics.Trace.Write(new string(' ', tab * 4)); System.Diagnostics.Trace.WriteLine("FloatingDocumentWindow()"); - RootDocument.ConsoleDump(tab + 1); + RootPanel.ConsoleDump(tab + 1); } #endif #endregion - - #region Events - - public event EventHandler RootDocumentChanged; - - #endregion } } diff --git a/source/Components/AvalonDock/Layout/LayoutDocumentPane.cs b/source/Components/AvalonDock/Layout/LayoutDocumentPane.cs index 838597cd..1436101b 100644 --- a/source/Components/AvalonDock/Layout/LayoutDocumentPane.cs +++ b/source/Components/AvalonDock/Layout/LayoutDocumentPane.cs @@ -11,6 +11,7 @@ This program is provided to you under the terms of the Microsoft Public using System.Collections.Generic; using System.Linq; using System.Windows.Markup; +using System.Xml.Serialization; namespace AvalonDock.Layout { @@ -102,20 +103,6 @@ public LayoutContent SelectedContent #endregion - #region ChildrenSorted - - public IEnumerable ChildrenSorted - { - get - { - var listSorted = this.Children.ToList(); - listSorted.Sort(); - return listSorted; - } - } - - #endregion - #endregion #region Overrides @@ -143,41 +130,49 @@ protected override void ChildMoved(int oldIndex, int newIndex) protected override void OnChildrenCollectionChanged() { - if (this.SelectedContentIndex >= this.ChildrenCount) - this.SelectedContentIndex = this.Children.Count - 1; - if (this.SelectedContentIndex == -1) + AutoFixSelectedContent(); + for (int i = 0; i < Children.Count; i++) { - if (this.ChildrenCount > 0) + if (Children[i].IsSelected) { - if (this.Root == null) - { - this.SetNextSelectedIndex(); - } - else - { - var childrenToSelect = this.Children.OrderByDescending(c => c.LastActivationTimeStamp.GetValueOrDefault()).First(); - this.SelectedContentIndex = this.Children.IndexOf(childrenToSelect); - childrenToSelect.IsActive = true; - } - } - else - { - if (this.Root != null) - { - this.Root.ActiveContent = null; - } + SelectedContentIndex = i; + break; } } + RaisePropertyChanged("CanClose"); + RaisePropertyChanged("CanHide"); + RaisePropertyChanged("IsDirectlyHostedInFloatingWindow"); base.OnChildrenCollectionChanged(); - RaisePropertyChanged("ChildrenSorted"); + RaisePropertyChanged( "ChildrenSorted" ); + } + + [XmlIgnore] + bool _autoFixSelectedContent = true; + void AutoFixSelectedContent() + { + if (_autoFixSelectedContent) + { + if (SelectedContentIndex >= ChildrenCount) + SelectedContentIndex = Children.Count - 1; + + if (SelectedContentIndex == -1 && ChildrenCount > 0) + SetNextSelectedIndex(); + } } - protected override void OnIsVisibleChanged() + public bool IsDirectlyHostedInFloatingWindow { - this.UpdateParentVisibility(); - base.OnIsVisibleChanged(); + get + { + var parentFloatingWindow = this.FindParent(); + if (parentFloatingWindow != null) + return parentFloatingWindow.IsSinglePane; + + return false; + //return Parent != null && Parent.ChildrenCount == 1 && Parent.Parent is LayoutFloatingWindow; + } } public override void WriteXml(System.Xml.XmlWriter writer) @@ -219,7 +214,10 @@ public override void ConsoleDump(int tab) public int IndexOf(LayoutContent content) { - return Children.IndexOf(content); + var documentChild = content as LayoutDocument; + if (documentChild == null) + return -1; + return Children.IndexOf(documentChild); } #endregion @@ -243,13 +241,50 @@ internal void SetNextSelectedIndex() #region Private Methods - private void UpdateParentVisibility() + internal void UpdateIsDirectlyHostedInFloatingWindow() { - var parentPane = this.Parent as ILayoutElementWithVisibility; - if (parentPane != null) - parentPane.ComputeVisibility(); + RaisePropertyChanged("IsDirectlyHostedInFloatingWindow"); } + public bool IsHostedInFloatingWindow + { + get + { + return this.FindParent() != null; + } + } + + public IEnumerable ChildrenSorted + { + get + { + var listSorted = Children.ToList(); + listSorted.Sort(); + return listSorted; + } + } + + protected override void OnParentChanged(ILayoutContainer oldValue, ILayoutContainer newValue) + { + var oldGroup = oldValue as ILayoutGroup; + if (oldGroup != null) + oldGroup.ChildrenCollectionChanged -= new EventHandler(OnParentChildrenCollectionChanged); + + RaisePropertyChanged("IsDirectlyHostedInFloatingWindow"); + + var newGroup = newValue as ILayoutGroup; + if (newGroup != null) + newGroup.ChildrenCollectionChanged += new EventHandler(OnParentChildrenCollectionChanged); + + base.OnParentChanged(oldValue, newValue); + } + + void OnParentChildrenCollectionChanged(object sender, EventArgs e) + { + RaisePropertyChanged("IsDirectlyHostedInFloatingWindow"); + } + + #endregion #region ILayoutPaneSerializable Interface diff --git a/source/Components/AvalonDock/Layout/LayoutRoot.cs b/source/Components/AvalonDock/Layout/LayoutRoot.cs index baceeafa..4d7fdc30 100644 --- a/source/Components/AvalonDock/Layout/LayoutRoot.cs +++ b/source/Components/AvalonDock/Layout/LayoutRoot.cs @@ -482,6 +482,21 @@ public void CollectGarbage() exitFlag = false; break; } + foreach (var emptyPaneGroup in this.Descendents().OfType().Where(p => p.ChildrenCount == 0)) + { + var parentGroup = emptyPaneGroup.Parent as ILayoutContainer; + if (!(parentGroup.Parent is LayoutDocumentFloatingWindow)) continue; + var index = RootPanel.IndexOfChild(this.Descendents().OfType().First()); + parentGroup.RemoveChild(emptyPaneGroup); + if (!this.Descendents().OfType().Any()) + { + // Now the last Pane container is deleted, at least one is required for documents to be added. + // We did not want to keep an empty window floating, but add a new one to the main window + RootPanel.Children.Insert(index < 0 ? 0 : index, emptyPaneGroup); + } + exitFlag = false; + break; + } } if (!exitFlag)