/************************************************************************************* Extended WPF Toolkit Copyright (C) 2007-2013 Xceed Software Inc. This program is provided to you under the terms of the Microsoft Public License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license For more features, controls, and fast professional support, pick up the Plus Edition at http://xceed.com/wpf_toolkit Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids ***********************************************************************************/ using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Markup; using System.Windows.Threading; using Xceed.Wpf.AvalonDock.Controls; using Xceed.Wpf.AvalonDock.Layout; using Xceed.Wpf.AvalonDock.Themes; namespace Xceed.Wpf.AvalonDock { [ContentProperty("Layout")] [TemplatePart(Name = "PART_AutoHideArea")] public class DockingManager : Control, IOverlayWindowHost//, ILogicalChildrenContainer { private ResourceDictionary currentThemeResourceDictionary; // = null static DockingManager() { DefaultStyleKeyProperty.OverrideMetadata(typeof(DockingManager), new FrameworkPropertyMetadata(typeof(DockingManager))); FocusableProperty.OverrideMetadata(typeof(DockingManager), new FrameworkPropertyMetadata(false)); HwndSource.DefaultAcquireHwndFocusInMenuMode = false; } public DockingManager() { Layout = new LayoutRoot() { RootPanel = new LayoutPanel(new LayoutDocumentPaneGroup(new LayoutDocumentPane())) }; this.Loaded += new RoutedEventHandler(DockingManager_Loaded); this.Unloaded += new RoutedEventHandler(DockingManager_Unloaded); } #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); } } /// /// 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(); 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) { //fw.Owner = Window.GetWindow(this); //fw.SetParentToMainWindowOf(this); } } 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(); } DispatcherOperation _setFocusAsyncOperation = null; 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) { //Debug.WriteLine(new StackTrace().ToString()); //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.Background); } } if (!_insideInternalSetActiveContent) ActiveContent = Layout.ActiveContent != null ? Layout.ActiveContent.Content : null; } } void OnLayoutRootUpdated(object sender, EventArgs e) { CommandManager.InvalidateRequerySuggested(); } /// /// Event fired when property changes /// public event EventHandler LayoutChanged; /// /// 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; } /// /// Event fired when property is about to be changed /// public event EventHandler LayoutChanging; void OnLayoutChanging(LayoutRoot newLayout) { if (LayoutChanging != null) LayoutChanging(this, EventArgs.Empty); } #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 #endregion public override void OnApplyTemplate() { base.OnApplyTemplate(); SetupAutoHideWindow(); } protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); } 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; } //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); } } void DockingManager_Unloaded(object sender, RoutedEventArgs e) { if (!DesignerProperties.GetIsInDesignMode(this)) { if (_autoHideWindowManager != null) { _autoHideWindowManager.HideAutoWindow(); } foreach (var fw in _fwList.ToArray()) { //fw.Owner = null; fw.SetParentWindowToNull(); fw.KeepContentVisibleOnClose = true; fw.Close(); } DestroyOverlayWindow(); FocusElementManager.FinalizeFocusManagement(this); } } 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("AnchorSideTemplate") { Source = this }); return templateModelView; } if (model is LayoutAnchorGroup) { var templateModelView = new LayoutAnchorGroupControl(model as LayoutAnchorGroup); templateModelView.SetBinding(LayoutAnchorGroupControl.TemplateProperty, new Binding("AnchorGroupTemplate") { Source = this }); return templateModelView; } if (model is LayoutDocumentPane) { var templateModelView = new LayoutDocumentPaneControl(model as LayoutDocumentPane); templateModelView.SetBinding(LayoutDocumentPaneControl.StyleProperty, new Binding("DocumentPaneControlStyle") { Source = this }); return templateModelView; } if (model is LayoutAnchorablePane) { var templateModelView = new LayoutAnchorablePaneControl(model as LayoutAnchorablePane); templateModelView.SetBinding(LayoutAnchorablePaneControl.StyleProperty, new Binding("AnchorablePaneControlStyle") { 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); var paneForExtensions = modelFW.RootPanel.Children.OfType().FirstOrDefault(); 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 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.RootDocument; 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; } #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 protected override void OnGotKeyboardFocus(System.Windows.Input.KeyboardFocusChangedEventArgs e) { //if (e.NewFocus is Grid) // Trace.WriteLine(string.Format("DockingManager.OnGotKeyboardFocus({0})", e.NewFocus)); base.OnGotKeyboardFocus(e); } protected override void OnPreviewGotKeyboardFocus(System.Windows.Input.KeyboardFocusChangedEventArgs e) { Trace.WriteLine(string.Format("DockingManager.OnPreviewGotKeyboardFocus({0})", e.NewFocus)); base.OnPreviewGotKeyboardFocus(e); } protected override void OnPreviewLostKeyboardFocus(KeyboardFocusChangedEventArgs e) { Trace.WriteLine(string.Format("DockingManager.OnPreviewLostKeyboardFocus({0})", e.OldFocus)); base.OnPreviewLostKeyboardFocus(e); } protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e) { Trace.WriteLine(string.Format("DockingManager.OnMouseLeftButtonDown([{0}])", e.GetPosition(this))); base.OnMouseLeftButtonDown(e); } protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e) { //Trace.WriteLine(string.Format("DockingManager.OnMouseMove([{0}])", e.GetPosition(this))); base.OnMouseMove(e); } #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(); } } internal void InternalAddLogicalChild(object element) { //System.Diagnostics.Trace.WriteLine("[{0}]InternalAddLogicalChild({1})", this, element); #if DEBUG 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) { //System.Diagnostics.Trace.WriteLine("[{0}]InternalRemoveLogicalChild({1})", this, element); var wrToRemove = _logicalChildren.FirstOrDefault(ch => ch.GetValueOrDefault() == element); if (wrToRemove != null) _logicalChildren.Remove(wrToRemove); RemoveLogicalChild(element); } void ClearLogicalChildrenList() { foreach (var child in _logicalChildren.Select(ch => ch.GetValueOrDefault()).ToArray()) RemoveLogicalChild(child); _logicalChildren.Clear(); } #endregion #region AutoHide window 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); } void SetupAutoHideWindow() { _autohideArea = GetTemplateChild("PART_AutoHideArea") as FrameworkElement; if (_autoHideWindowManager != null) _autoHideWindowManager.HideAutoWindow(); else _autoHideWindowManager = new AutoHideWindowManager(this); if (AutoHideWindow != null) AutoHideWindow.Dispose(); SetAutoHideWindow(new LayoutAutoHideWindowControl()); } AutoHideWindowManager _autoHideWindowManager; FrameworkElement _autohideArea; internal FrameworkElement GetAutoHideAreaElement() { return _autohideArea; } #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 #endregion // #region AutoHide window //WeakReference _currentAutohiddenAnchor = null; //internal void ShowAutoHideWindow(LayoutAnchorControl 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)); //} //internal void HideAutoHideWindow(LayoutAnchorControl anchor) //{ // if (AutoHideWindow != null) // { // if (anchor == _currentAutohiddenAnchor.GetValueOrDefault()) // { // Trace.WriteLine("AutoHideWindow()"); // AutoHideWindow.Dispose(); // SetAutoHideWindow(null); // } // } //} //FrameworkElement _autohideArea; //internal FrameworkElement GetAutoHideAreaElement() //{ // return _autohideArea; //} //void SetupAutoHideArea() //{ // _autohideArea = GetTemplateChild("PART_AutoHideArea") as FrameworkElement; //} // #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) // ((ILogicalChildrenContainer)this).InternalRemoveLogicalChild(e.OldValue); // if (e.NewValue != null) // ((ILogicalChildrenContainer)this).InternalAddLogicalChild(e.NewValue); //} // #endregion // #endregion #region Floating Windows List _fwList = new List(); internal void StartDraggingFloatingWindowForContent(LayoutContent contentModel, bool startDrag = true) { if (!contentModel.CanFloat) return; 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; if (fwHeight == 0.0) fwHeight = parentPaneAsWithActualSize.ActualHeight; 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) { Width = fwWidth, Height = fwHeight, Left = contentModel.FloatingLeft, Top = contentModel.FloatingTop }; } else { var anchorableDocument = contentModel as LayoutDocument; fw = new LayoutDocumentFloatingWindow() { RootDocument = anchorableDocument }; Layout.FloatingWindows.Add(fw); fwc = new LayoutDocumentFloatingWindowControl( fw as LayoutDocumentFloatingWindow) { Width = fwWidth, Height = fwHeight, Left = contentModel.FloatingLeft, Top = contentModel.FloatingTop }; } //fwc.Owner = Window.GetWindow(this); //fwc.SetParentToMainWindowOf(this); _fwList.Add(fwc); Layout.CollectGarbage(); UpdateLayout(); Dispatcher.BeginInvoke(new Action(() => { if (startDrag) fwc.AttachDrag(); fwc.Show(); }), DispatcherPriority.Send); } internal void StartDraggingFloatingWindowForPane(LayoutAnchorablePane paneModel) { if (paneModel.Children.Any(c => !c.CanFloat)) return; 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; if (fwHeight == 0.0) fwHeight = paneAsWithActualSize.ActualHeight; 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) { Width = fwWidth, Height = fwHeight }; //fwc.Owner = Window.GetWindow(this); //fwc.SetParentToMainWindowOf(this); _fwList.Add(fwc); Layout.CollectGarbage(); InvalidateArrange(); fwc.AttachDrag(); fwc.Show(); } internal IEnumerable GetFloatingWindowsByZOrder() { var parentWindow = Window.GetWindow(this); if (parentWindow == null) yield break; IntPtr windowParentHanlde = new WindowInteropHelper(parentWindow).Handle; 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.Manager == this) yield return ctrl; currentHandle = Win32Helper.GetWindow(currentHandle, (uint)Win32Helper.GetWindow_Cmd.GW_HWNDNEXT); } } internal void RemoveFloatingWindow(LayoutFloatingWindowControl floatingWindow) { _fwList.Remove(floatingWindow); } public IEnumerable FloatingWindows { get { return _fwList; } } #endregion #region OverlayWindow 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; } } 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; } void DestroyOverlayWindow() { if (_overlayWindow != null) { _overlayWindow.Close(); _overlayWindow = null; } } IOverlayWindow IOverlayWindowHost.ShowOverlayWindow(LayoutFloatingWindowControl draggingWindow) { //Trace.WriteLine("ShowOverlayWindow"); CreateOverlayWindow(); _overlayWindow.Owner = draggingWindow; _overlayWindow.EnableDropTargets(); _overlayWindow.Show(); return _overlayWindow; } void IOverlayWindowHost.HideOverlayWindow() { //Trace.WriteLine("HideOverlayWindow"); _areas = null; _overlayWindow.Owner = null; _overlayWindow.HideDropTargets(); } List _areas = null; 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)); } } } 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; } protected override Size ArrangeOverride(Size arrangeBounds) { _areas = null; return base.ArrangeOverride(arrangeBounds); } #endregion #region LayoutDocument & LayoutAnchorable Templates #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 #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); } 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 = true; var documentsSourceAsNotifier = documentsSource as INotifyCollectionChanged; if (documentsSourceAsNotifier != null) documentsSourceAsNotifier.CollectionChanged += new NotifyCollectionChangedEventHandler(documentsSourceElementsChanged); } internal bool SuspendDocumentsSourceBinding = false; 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); } } } //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); } } if (Layout != null) { Layout.CollectGarbage(); } } 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); } var documentsSourceAsNotifier = documentsSource as INotifyCollectionChanged; if (documentsSourceAsNotifier != null) documentsSourceAsNotifier.CollectionChanged -= new NotifyCollectionChangedEventHandler(documentsSourceElementsChanged); } #endregion #region DocumentCloseCommand internal void _ExecuteCloseCommand(LayoutDocument document) { if (DocumentClosing != null) { var evargs = new DocumentClosingEventArgs(document); DocumentClosing(this, evargs); if (evargs.Cancel) return; } if (!document.TestCanClose()) return; document.CloseInternal(); if (DocumentClosed != null) { var evargs = new DocumentClosedEventArgs(document); DocumentClosed(this, evargs); } } /// /// 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; #endregion 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()) { if (!contentToClose.CanClose) continue; 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); } } } #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); } 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); } internal bool SuspendAnchorablesSourceBinding = false; 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.Parent as ILayoutContainer).RemoveChild( 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); } } if (Layout != null) Layout.CollectGarbage(); } 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); } var anchorablesSourceAsNotifier = anchorablesSource as INotifyCollectionChanged; if (anchorablesSourceAsNotifier != null) anchorablesSourceAsNotifier.CollectionChanged -= new NotifyCollectionChangedEventHandler(anchorablesSourceElementsChanged); } #endregion internal void _ExecuteCloseCommand(LayoutAnchorable anchorable) { var model = anchorable as LayoutAnchorable; if (model != null && model.TestCanClose()) { if (model.IsAutoHidden) model.ToggleAutoHide(); //Daniel-调Close()会死循环 //model.Close(); model.CloseInternal(); return; } } internal void _ExecuteHideCommand(LayoutAnchorable anchorable) { var model = anchorable as LayoutAnchorable; if (model != null) { //by default hide the anchorable 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(); } #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); } bool _insideInternalSetActiveContent = false; void InternalSetActiveContent(object contentObject) { var layoutContent = Layout.Descendents().OfType().FirstOrDefault(lc => lc == contentObject || lc.Content == contentObject); _insideInternalSetActiveContent = true; Layout.ActiveContent = layoutContent; _insideInternalSetActiveContent = false; } public event EventHandler ActiveContentChanged; #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 internal void _ExecuteContentActivateCommand(LayoutContent content) { content.IsActive = true; } #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 LayoutItems List _layoutItems = new List(); bool _suspendLayoutItemCreation = false; void DetachLayoutItems() { if (Layout != null) { _layoutItems.ForEach(i => i.Detach()); _layoutItems.Clear(); Layout.ElementAdded -= new EventHandler(Layout_ElementAdded); Layout.ElementRemoved -= new EventHandler(Layout_ElementRemoved); } } void Layout_ElementRemoved(object sender, LayoutElementEventArgs e) { if (_suspendLayoutItemCreation) return; CollectLayoutItemsDeleted(); } 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(); } DispatcherOperation _collectLayoutItemsOperations = null; 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); } })); } 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); } } 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(); } void CreateAnchorableLayoutItem(LayoutAnchorable contentToAttach) { if (_layoutItems.Any(item => item.LayoutElement == contentToAttach)) return; var layoutItem = new LayoutAnchorableItem(); layoutItem.Attach(contentToAttach); ApplyStyleToLayoutItem(layoutItem); _layoutItems.Add(layoutItem); if (contentToAttach != null && contentToAttach.Content != null && contentToAttach.Content is UIElement) { InternalAddLogicalChild(contentToAttach.Content); } } void CreateDocumentLayoutItem(LayoutDocument contentToAttach) { if (_layoutItems.Any(item => item.LayoutElement == contentToAttach)) return; var layoutItem = new LayoutDocumentItem(); layoutItem.Attach(contentToAttach); ApplyStyleToLayoutItem(layoutItem); _layoutItems.Add(layoutItem); if (contentToAttach != null && contentToAttach.Content != null && contentToAttach.Content is UIElement) { InternalAddLogicalChild(contentToAttach.Content); } } #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 /// /// 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); } #endregion #region NavigatorWindow NavigatorWindow _navigatorWindow = null; void ShowNavigatorWindow() { if (_navigatorWindow == null) { _navigatorWindow = new NavigatorWindow(this) { Owner = Window.GetWindow(this), WindowStartupLocation = WindowStartupLocation.CenterOwner }; } _navigatorWindow.ShowDialog(); _navigatorWindow = null; Trace.WriteLine("ShowNavigatorWindow()"); } bool IsNavigatorWindowActive { get { return _navigatorWindow != null; } } protected override void OnPreviewKeyDown(KeyEventArgs e) { Trace.WriteLine(string.Format("OnPreviewKeyDown({0})", e.Key)); 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 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 } }