/************************************************************************************* 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.Linq; using System.Windows; using Xceed.Wpf.AvalonDock.Layout; using System.Windows.Input; using Xceed.Wpf.AvalonDock.Commands; using System.Windows.Data; using System.Windows.Media; using System.Windows.Controls; namespace Xceed.Wpf.AvalonDock.Controls { public abstract class LayoutItem : FrameworkElement { #region Members private ICommand _defaultCloseCommand; private ICommand _defaultFloatCommand; private ICommand _defaultDockAsDocumentCommand; private ICommand _defaultCloseAllButThisCommand; private ICommand _defaultCloseAllCommand; private ICommand _defaultActivateCommand; private ICommand _defaultNewVerticalTabGroupCommand; private ICommand _defaultNewHorizontalTabGroupCommand; private ICommand _defaultMoveToNextTabGroupCommand; private ICommand _defaultMoveToPreviousTabGroupCommand; private ContentPresenter _view = null; private ReentrantFlag _isSelectedReentrantFlag = new ReentrantFlag(); private ReentrantFlag _isActiveReentrantFlag = new ReentrantFlag(); #endregion #region Constructors static LayoutItem() { ToolTipProperty.OverrideMetadata( typeof( LayoutItem ), new FrameworkPropertyMetadata( null, ( s, e ) => OnToolTipChanged( s, e ) ) ); VisibilityProperty.OverrideMetadata( typeof( LayoutItem ), new FrameworkPropertyMetadata( Visibility.Visible, ( s, e ) => OnVisibilityChanged( s, e ) ) ); } internal LayoutItem() { } #endregion #region Properties #region LayoutElement public LayoutContent LayoutElement { get; private set; } #endregion #region Model public object Model { get; private set; } #endregion #region View public ContentPresenter View { get { if( _view == null ) { _view = new ContentPresenter(); _view.SetBinding( ContentPresenter.ContentProperty, new Binding( "Content" ) { Source = LayoutElement } ); if( ( LayoutElement != null ) && ( LayoutElement.Root != null ) ) { _view.SetBinding( ContentPresenter.ContentTemplateProperty, new Binding( "LayoutItemTemplate" ) { Source = LayoutElement.Root.Manager } ); _view.SetBinding( ContentPresenter.ContentTemplateSelectorProperty, new Binding( "LayoutItemTemplateSelector" ) { Source = LayoutElement.Root.Manager } ); if( LayoutElement.Root.Manager != null ) { LayoutElement.Root.Manager.InternalAddLogicalChild( _view ); } } } return _view; } } #endregion #region Title /// /// Title Dependency Property /// public static readonly DependencyProperty TitleProperty = DependencyProperty.Register( "Title", typeof( string ), typeof( LayoutItem ), new FrameworkPropertyMetadata( ( string )null, new PropertyChangedCallback( OnTitleChanged ) ) ); /// /// Gets or sets the Title property. This dependency property /// indicates the title of the element. /// public string Title { get { return ( string )GetValue( TitleProperty ); } set { SetValue( TitleProperty, value ); } } /// /// Handles changes to the Title property. /// private static void OnTitleChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnTitleChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the Title property. /// protected virtual void OnTitleChanged( DependencyPropertyChangedEventArgs e ) { if( LayoutElement != null ) LayoutElement.Title = ( string )e.NewValue; } #endregion #region IconSource /// /// IconSource Dependency Property /// public static readonly DependencyProperty IconSourceProperty = DependencyProperty.Register( "IconSource", typeof( ImageSource ), typeof( LayoutItem ), new FrameworkPropertyMetadata( ( ImageSource )null, new PropertyChangedCallback( OnIconSourceChanged ) ) ); /// /// Gets or sets the IconSource property. This dependency property /// indicates icon associated with the item. /// public ImageSource IconSource { get { return ( ImageSource )GetValue( IconSourceProperty ); } set { SetValue( IconSourceProperty, value ); } } /// /// Handles changes to the IconSource property. /// private static void OnIconSourceChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnIconSourceChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the IconSource property. /// protected virtual void OnIconSourceChanged( DependencyPropertyChangedEventArgs e ) { if( LayoutElement != null ) LayoutElement.IconSource = IconSource; } #endregion #region ContentId /// /// ContentId Dependency Property /// public static readonly DependencyProperty ContentIdProperty = DependencyProperty.Register( "ContentId", typeof( string ), typeof( LayoutItem ), new FrameworkPropertyMetadata( ( string )null, new PropertyChangedCallback( OnContentIdChanged ) ) ); /// /// Gets or sets the ContentId property. This dependency property /// indicates the content id used to retrive content when deserializing layouts. /// public string ContentId { get { return ( string )GetValue( ContentIdProperty ); } set { SetValue( ContentIdProperty, value ); } } /// /// Handles changes to the ContentId property. /// private static void OnContentIdChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnContentIdChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the ContentId property. /// protected virtual void OnContentIdChanged( DependencyPropertyChangedEventArgs e ) { if( LayoutElement != null ) LayoutElement.ContentId = ( string )e.NewValue; } #endregion #region IsSelected /// /// IsSelected Dependency Property /// public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register( "IsSelected", typeof( bool ), typeof( LayoutItem ), new FrameworkPropertyMetadata( ( bool )false, new PropertyChangedCallback( OnIsSelectedChanged ) ) ); /// /// Gets or sets the IsSelected property. This dependency property /// indicates if the item is selected inside its container. /// public bool IsSelected { get { return ( bool )GetValue( IsSelectedProperty ); } set { SetValue( IsSelectedProperty, value ); } } /// /// Handles changes to the IsSelected property. /// private static void OnIsSelectedChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnIsSelectedChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the IsSelected property. /// protected virtual void OnIsSelectedChanged( DependencyPropertyChangedEventArgs e ) { if( _isSelectedReentrantFlag.CanEnter ) { using( _isSelectedReentrantFlag.Enter() ) { if( LayoutElement != null ) LayoutElement.IsSelected = ( bool )e.NewValue; } } } #endregion #region IsActive /// /// IsActive Dependency Property /// public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register( "IsActive", typeof( bool ), typeof( LayoutItem ), new FrameworkPropertyMetadata( ( bool )false, new PropertyChangedCallback( OnIsActiveChanged ) ) ); /// /// Gets or sets the IsActive property. This dependency property /// indicates if the item is active in the UI. /// public bool IsActive { get { return ( bool )GetValue( IsActiveProperty ); } set { SetValue( IsActiveProperty, value ); } } /// /// Handles changes to the IsActive property. /// private static void OnIsActiveChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnIsActiveChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the IsActive property. /// protected virtual void OnIsActiveChanged( DependencyPropertyChangedEventArgs e ) { if( _isActiveReentrantFlag.CanEnter ) { using( _isActiveReentrantFlag.Enter() ) { if( LayoutElement != null ) LayoutElement.IsActive = ( bool )e.NewValue; } } } #endregion #region CanClose /// /// CanClose Dependency Property /// public static readonly DependencyProperty CanCloseProperty = DependencyProperty.Register( "CanClose", typeof( bool ), typeof( LayoutItem ), new FrameworkPropertyMetadata( ( bool )true, new PropertyChangedCallback( OnCanCloseChanged ) ) ); /// /// Gets or sets the CanClose property. This dependency property /// indicates if the item can be closed. /// public bool CanClose { get { return ( bool )GetValue( CanCloseProperty ); } set { SetValue( CanCloseProperty, value ); } } /// /// Handles changes to the CanClose property. /// private static void OnCanCloseChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnCanCloseChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the CanClose property. /// protected virtual void OnCanCloseChanged( DependencyPropertyChangedEventArgs e ) { if( LayoutElement != null ) LayoutElement.CanClose = ( bool )e.NewValue; } #endregion #region CanFloat /// /// CanFloat Dependency Property /// public static readonly DependencyProperty CanFloatProperty = DependencyProperty.Register( "CanFloat", typeof( bool ), typeof( LayoutItem ), new FrameworkPropertyMetadata( ( bool )true, new PropertyChangedCallback( OnCanFloatChanged ) ) ); /// /// Gets or sets the CanFloat property. This dependency property /// indicates if user can move the layout element dragging it to another position. /// public bool CanFloat { get { return ( bool )GetValue( CanFloatProperty ); } set { SetValue( CanFloatProperty, value ); } } /// /// Handles changes to the CanFloat property. /// private static void OnCanFloatChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnCanFloatChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the CanFloat property. /// protected virtual void OnCanFloatChanged( DependencyPropertyChangedEventArgs e ) { if( LayoutElement != null ) LayoutElement.CanFloat = ( bool )e.NewValue; } #endregion #region CloseCommand /// /// CloseCommand Dependency Property /// public static readonly DependencyProperty CloseCommandProperty = DependencyProperty.Register( "CloseCommand", typeof( ICommand ), typeof( LayoutItem ), new FrameworkPropertyMetadata( null, new PropertyChangedCallback( OnCloseCommandChanged ), new CoerceValueCallback( CoerceCloseCommandValue ) ) ); /// /// Gets or sets the CloseCommand property. This dependency property /// indicates the command to execute when user click the document close button. /// public ICommand CloseCommand { get { return ( ICommand )GetValue( CloseCommandProperty ); } set { SetValue( CloseCommandProperty, value ); } } /// /// Handles changes to the CloseCommand property. /// private static void OnCloseCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnCloseCommandChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the CloseCommand property. /// protected virtual void OnCloseCommandChanged( DependencyPropertyChangedEventArgs e ) { } /// /// Coerces the CloseCommand value. /// private static object CoerceCloseCommandValue( DependencyObject d, object value ) { return value; } private bool CanExecuteCloseCommand( object parameter ) { return LayoutElement != null && LayoutElement.CanClose; } private void ExecuteCloseCommand( object parameter ) { Close(); } protected abstract void Close(); #endregion #region FloatCommand /// /// FloatCommand Dependency Property /// public static readonly DependencyProperty FloatCommandProperty = DependencyProperty.Register( "FloatCommand", typeof( ICommand ), typeof( LayoutItem ), new FrameworkPropertyMetadata( null, new PropertyChangedCallback( OnFloatCommandChanged ), new CoerceValueCallback( CoerceFloatCommandValue ) ) ); /// /// Gets or sets the FloatCommand property. This dependency property /// indicates the command to execute when user click the float button. /// /// By default this command move the anchorable inside new floating window. public ICommand FloatCommand { get { return ( ICommand )GetValue( FloatCommandProperty ); } set { SetValue( FloatCommandProperty, value ); } } /// /// Handles changes to the FloatCommand property. /// private static void OnFloatCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnFloatCommandChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the FloatCommand property. /// protected virtual void OnFloatCommandChanged( DependencyPropertyChangedEventArgs e ) { } /// /// Coerces the FloatCommand value. /// private static object CoerceFloatCommandValue( DependencyObject d, object value ) { return value; } private bool CanExecuteFloatCommand( object anchorable ) { return LayoutElement != null && LayoutElement.CanFloat && LayoutElement.FindParent() == null; } private void ExecuteFloatCommand( object parameter ) { LayoutElement.Root.Manager._ExecuteFloatCommand( LayoutElement ); } protected virtual void Float() { } #endregion #region DockAsDocumentCommand /// /// DockAsDocumentCommand Dependency Property /// public static readonly DependencyProperty DockAsDocumentCommandProperty = DependencyProperty.Register( "DockAsDocumentCommand", typeof( ICommand ), typeof( LayoutItem ), new FrameworkPropertyMetadata( null, new PropertyChangedCallback( OnDockAsDocumentCommandChanged ), new CoerceValueCallback( CoerceDockAsDocumentCommandValue ) ) ); /// /// Gets or sets the DockAsDocumentCommand property. This dependency property /// indicates the command to execute when user click the DockAsDocument button. /// /// By default this command move the anchorable inside the last focused document pane. public ICommand DockAsDocumentCommand { get { return ( ICommand )GetValue( DockAsDocumentCommandProperty ); } set { SetValue( DockAsDocumentCommandProperty, value ); } } /// /// Handles changes to the DockAsDocumentCommand property. /// private static void OnDockAsDocumentCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnDockAsDocumentCommandChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the DockAsDocumentCommand property. /// protected virtual void OnDockAsDocumentCommandChanged( DependencyPropertyChangedEventArgs e ) { } /// /// Coerces the DockAsDocumentCommand value. /// private static object CoerceDockAsDocumentCommandValue( DependencyObject d, object value ) { return value; } private bool CanExecuteDockAsDocumentCommand( object parameter ) { return LayoutElement != null && LayoutElement.FindParent() == null; } private void ExecuteDockAsDocumentCommand( object parameter ) { LayoutElement.Root.Manager._ExecuteDockAsDocumentCommand( LayoutElement ); } #endregion #region CloseAllButThisCommand /// /// CloseAllButThisCommand Dependency Property /// public static readonly DependencyProperty CloseAllButThisCommandProperty = DependencyProperty.Register( "CloseAllButThisCommand", typeof( ICommand ), typeof( LayoutItem ), new FrameworkPropertyMetadata( null, new PropertyChangedCallback( OnCloseAllButThisCommandChanged ), new CoerceValueCallback( CoerceCloseAllButThisCommandValue ) ) ); /// /// Gets or sets the CloseAllButThisCommand property. This dependency property /// indicates the 'Close All But This' command. /// public ICommand CloseAllButThisCommand { get { return ( ICommand )GetValue( CloseAllButThisCommandProperty ); } set { SetValue( CloseAllButThisCommandProperty, value ); } } /// /// Handles changes to the CloseAllButThisCommand property. /// private static void OnCloseAllButThisCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnCloseAllButThisCommandChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the CloseAllButThisCommand property. /// protected virtual void OnCloseAllButThisCommandChanged( DependencyPropertyChangedEventArgs e ) { } /// /// Coerces the CloseAllButThisCommand value. /// private static object CoerceCloseAllButThisCommandValue( DependencyObject d, object value ) { return value; } private bool CanExecuteCloseAllButThisCommand( object parameter ) { if( LayoutElement == null ) return false; var root = LayoutElement.Root; if( root == null ) return false; return LayoutElement.Root.Manager.Layout. Descendents().OfType().Where( d => d != LayoutElement && ( d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow ) ).Any(); } private void ExecuteCloseAllButThisCommand( object parameter ) { LayoutElement.Root.Manager._ExecuteCloseAllButThisCommand( LayoutElement ); } #endregion #region CloseAllCommand /// /// CloseAllCommand Dependency Property /// public static readonly DependencyProperty CloseAllCommandProperty = DependencyProperty.Register( "CloseAllCommand", typeof( ICommand ), typeof( LayoutItem ), new FrameworkPropertyMetadata( null, new PropertyChangedCallback( OnCloseAllCommandChanged ), new CoerceValueCallback( CoerceCloseAllCommandValue ) ) ); /// /// Gets or sets the CloseAllCommand property. This dependency property /// indicates the 'Close All' command. /// public ICommand CloseAllCommand { get { return ( ICommand )GetValue( CloseAllCommandProperty ); } set { SetValue( CloseAllCommandProperty, value ); } } /// /// Handles changes to the CloseAllCommand property. /// private static void OnCloseAllCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnCloseAllCommandChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the CloseAllCommand property. /// protected virtual void OnCloseAllCommandChanged( DependencyPropertyChangedEventArgs e ) { } /// /// Coerces the CloseAllCommand value. /// private static object CoerceCloseAllCommandValue( DependencyObject d, object value ) { return value; } private bool CanExecuteCloseAllCommand( object parameter ) { if( LayoutElement == null ) return false; var root = LayoutElement.Root; if( root == null ) return false; return LayoutElement.Root.Manager.Layout. Descendents().OfType().Where( d => ( d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow ) ).Any(); } private void ExecuteCloseAllCommand( object parameter ) { LayoutElement.Root.Manager._ExecuteCloseAllCommand( LayoutElement ); } #endregion #region ActivateCommand /// /// ActivateCommand Dependency Property /// public static readonly DependencyProperty ActivateCommandProperty = DependencyProperty.Register( "ActivateCommand", typeof( ICommand ), typeof( LayoutItem ), new FrameworkPropertyMetadata( null, new PropertyChangedCallback( OnActivateCommandChanged ), new CoerceValueCallback( CoerceActivateCommandValue ) ) ); /// /// Gets or sets the ActivateCommand property. This dependency property /// indicates the command to execute when user wants to activate a content (either a Document or an Anchorable). /// public ICommand ActivateCommand { get { return ( ICommand )GetValue( ActivateCommandProperty ); } set { SetValue( ActivateCommandProperty, value ); } } /// /// Handles changes to the ActivateCommand property. /// private static void OnActivateCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnActivateCommandChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the ActivateCommand property. /// protected virtual void OnActivateCommandChanged( DependencyPropertyChangedEventArgs e ) { } /// /// Coerces the ActivateCommand value. /// private static object CoerceActivateCommandValue( DependencyObject d, object value ) { return value; } private bool CanExecuteActivateCommand( object parameter ) { return LayoutElement != null; } private void ExecuteActivateCommand( object parameter ) { LayoutElement.Root.Manager._ExecuteContentActivateCommand( LayoutElement ); } #endregion #region NewVerticalTabGroupCommand /// /// NewVerticalTabGroupCommand Dependency Property /// public static readonly DependencyProperty NewVerticalTabGroupCommandProperty = DependencyProperty.Register( "NewVerticalTabGroupCommand", typeof( ICommand ), typeof( LayoutItem ), new FrameworkPropertyMetadata( ( ICommand )null, new PropertyChangedCallback( OnNewVerticalTabGroupCommandChanged ) ) ); /// /// Gets or sets the NewVerticalTabGroupCommand property. This dependency property /// indicates the new vertical tab group command. /// public ICommand NewVerticalTabGroupCommand { get { return ( ICommand )GetValue( NewVerticalTabGroupCommandProperty ); } set { SetValue( NewVerticalTabGroupCommandProperty, value ); } } /// /// Handles changes to the NewVerticalTabGroupCommand property. /// private static void OnNewVerticalTabGroupCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnNewVerticalTabGroupCommandChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the NewVerticalTabGroupCommand property. /// protected virtual void OnNewVerticalTabGroupCommandChanged( DependencyPropertyChangedEventArgs e ) { } private bool CanExecuteNewVerticalTabGroupCommand( object parameter ) { if( LayoutElement == null ) return false; var parentDocumentGroup = LayoutElement.FindParent(); var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; return ( ( parentDocumentGroup == null || parentDocumentGroup.ChildrenCount == 1 || parentDocumentGroup.Root.Manager.AllowMixedOrientation || parentDocumentGroup.Orientation == System.Windows.Controls.Orientation.Horizontal ) && parentDocumentPane != null && parentDocumentPane.ChildrenCount > 1 ); } private void ExecuteNewVerticalTabGroupCommand( object parameter ) { var layoutElement = LayoutElement; var parentDocumentGroup = layoutElement.FindParent(); var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; if( parentDocumentGroup == null ) { var grandParent = parentDocumentPane.Parent as ILayoutContainer; parentDocumentGroup = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Horizontal }; grandParent.ReplaceChild( parentDocumentPane, parentDocumentGroup ); parentDocumentGroup.Children.Add( parentDocumentPane ); } parentDocumentGroup.Orientation = System.Windows.Controls.Orientation.Horizontal; int indexOfParentPane = parentDocumentGroup.IndexOfChild( parentDocumentPane ); parentDocumentGroup.InsertChildAt( indexOfParentPane + 1, new LayoutDocumentPane( layoutElement ) ); layoutElement.IsActive = true; layoutElement.Root.CollectGarbage(); } #endregion #region NewHorizontalTabGroupCommand /// /// NewHorizontalTabGroupCommand Dependency Property /// public static readonly DependencyProperty NewHorizontalTabGroupCommandProperty = DependencyProperty.Register( "NewHorizontalTabGroupCommand", typeof( ICommand ), typeof( LayoutItem ), new FrameworkPropertyMetadata( ( ICommand )null, new PropertyChangedCallback( OnNewHorizontalTabGroupCommandChanged ) ) ); /// /// Gets or sets the NewHorizontalTabGroupCommand property. This dependency property /// indicates the new horizontal tab group command. /// public ICommand NewHorizontalTabGroupCommand { get { return ( ICommand )GetValue( NewHorizontalTabGroupCommandProperty ); } set { SetValue( NewHorizontalTabGroupCommandProperty, value ); } } /// /// Handles changes to the NewHorizontalTabGroupCommand property. /// private static void OnNewHorizontalTabGroupCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnNewHorizontalTabGroupCommandChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the NewHorizontalTabGroupCommand property. /// protected virtual void OnNewHorizontalTabGroupCommandChanged( DependencyPropertyChangedEventArgs e ) { } private bool CanExecuteNewHorizontalTabGroupCommand( object parameter ) { if( LayoutElement == null ) return false; var parentDocumentGroup = LayoutElement.FindParent(); var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; return ( ( parentDocumentGroup == null || parentDocumentGroup.ChildrenCount == 1 || parentDocumentGroup.Root.Manager.AllowMixedOrientation || parentDocumentGroup.Orientation == System.Windows.Controls.Orientation.Vertical ) && parentDocumentPane != null && parentDocumentPane.ChildrenCount > 1 ); } private void ExecuteNewHorizontalTabGroupCommand( object parameter ) { var layoutElement = LayoutElement; var parentDocumentGroup = layoutElement.FindParent(); var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; if( parentDocumentGroup == null ) { var grandParent = parentDocumentPane.Parent as ILayoutContainer; parentDocumentGroup = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Vertical }; grandParent.ReplaceChild( parentDocumentPane, parentDocumentGroup ); parentDocumentGroup.Children.Add( parentDocumentPane ); } parentDocumentGroup.Orientation = System.Windows.Controls.Orientation.Vertical; int indexOfParentPane = parentDocumentGroup.IndexOfChild( parentDocumentPane ); parentDocumentGroup.InsertChildAt( indexOfParentPane + 1, new LayoutDocumentPane( layoutElement ) ); layoutElement.IsActive = true; layoutElement.Root.CollectGarbage(); } #endregion #region MoveToNextTabGroupCommand /// /// MoveToNextTabGroupCommand Dependency Property /// public static readonly DependencyProperty MoveToNextTabGroupCommandProperty = DependencyProperty.Register( "MoveToNextTabGroupCommand", typeof( ICommand ), typeof( LayoutItem ), new FrameworkPropertyMetadata( ( ICommand )null, new PropertyChangedCallback( OnMoveToNextTabGroupCommandChanged ) ) ); /// /// Gets or sets the MoveToNextTabGroupCommand property. This dependency property /// indicates move to next tab group command. /// public ICommand MoveToNextTabGroupCommand { get { return ( ICommand )GetValue( MoveToNextTabGroupCommandProperty ); } set { SetValue( MoveToNextTabGroupCommandProperty, value ); } } /// /// Handles changes to the MoveToNextTabGroupCommand property. /// private static void OnMoveToNextTabGroupCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnMoveToNextTabGroupCommandChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the MoveToNextTabGroupCommand property. /// protected virtual void OnMoveToNextTabGroupCommandChanged( DependencyPropertyChangedEventArgs e ) { } private bool CanExecuteMoveToNextTabGroupCommand( object parameter ) { if( LayoutElement == null ) return false; var parentDocumentGroup = LayoutElement.FindParent(); var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; return ( parentDocumentGroup != null && parentDocumentPane != null && parentDocumentGroup.ChildrenCount > 1 && parentDocumentGroup.IndexOfChild( parentDocumentPane ) < parentDocumentGroup.ChildrenCount - 1 && parentDocumentGroup.Children[ parentDocumentGroup.IndexOfChild( parentDocumentPane ) + 1 ] is LayoutDocumentPane ); } private void ExecuteMoveToNextTabGroupCommand( object parameter ) { var layoutElement = LayoutElement; var parentDocumentGroup = layoutElement.FindParent(); var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; int indexOfParentPane = parentDocumentGroup.IndexOfChild( parentDocumentPane ); var nextDocumentPane = parentDocumentGroup.Children[ indexOfParentPane + 1 ] as LayoutDocumentPane; nextDocumentPane.InsertChildAt( 0, layoutElement ); layoutElement.IsActive = true; layoutElement.Root.CollectGarbage(); } #endregion #region MoveToPreviousTabGroupCommand /// /// MoveToPreviousTabGroupCommand Dependency Property /// public static readonly DependencyProperty MoveToPreviousTabGroupCommandProperty = DependencyProperty.Register( "MoveToPreviousTabGroupCommand", typeof( ICommand ), typeof( LayoutItem ), new FrameworkPropertyMetadata( ( ICommand )null, new PropertyChangedCallback( OnMoveToPreviousTabGroupCommandChanged ) ) ); /// /// Gets or sets the MoveToPreviousTabGroupCommand property. This dependency property /// indicates move to rpevious tab group command. /// public ICommand MoveToPreviousTabGroupCommand { get { return ( ICommand )GetValue( MoveToPreviousTabGroupCommandProperty ); } set { SetValue( MoveToPreviousTabGroupCommandProperty, value ); } } /// /// Handles changes to the MoveToPreviousTabGroupCommand property. /// private static void OnMoveToPreviousTabGroupCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )d ).OnMoveToPreviousTabGroupCommandChanged( e ); } /// /// Provides derived classes an opportunity to handle changes to the MoveToPreviousTabGroupCommand property. /// protected virtual void OnMoveToPreviousTabGroupCommandChanged( DependencyPropertyChangedEventArgs e ) { } private bool CanExecuteMoveToPreviousTabGroupCommand( object parameter ) { if( LayoutElement == null ) return false; var parentDocumentGroup = LayoutElement.FindParent(); var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; return ( parentDocumentGroup != null && parentDocumentPane != null && parentDocumentGroup.ChildrenCount > 1 && parentDocumentGroup.IndexOfChild( parentDocumentPane ) > 0 && parentDocumentGroup.Children[ parentDocumentGroup.IndexOfChild( parentDocumentPane ) - 1 ] is LayoutDocumentPane ); } private void ExecuteMoveToPreviousTabGroupCommand( object parameter ) { var layoutElement = LayoutElement; var parentDocumentGroup = layoutElement.FindParent(); var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; int indexOfParentPane = parentDocumentGroup.IndexOfChild( parentDocumentPane ); var nextDocumentPane = parentDocumentGroup.Children[ indexOfParentPane - 1 ] as LayoutDocumentPane; nextDocumentPane.InsertChildAt( 0, layoutElement ); layoutElement.IsActive = true; layoutElement.Root.CollectGarbage(); } #endregion #endregion #region Internal Methods protected virtual void InitDefaultCommands() { _defaultCloseCommand = new RelayCommand( ( p ) => ExecuteCloseCommand( p ), ( p ) => CanExecuteCloseCommand( p ) ); _defaultFloatCommand = new RelayCommand( ( p ) => ExecuteFloatCommand( p ), ( p ) => CanExecuteFloatCommand( p ) ); _defaultDockAsDocumentCommand = new RelayCommand( ( p ) => ExecuteDockAsDocumentCommand( p ), ( p ) => CanExecuteDockAsDocumentCommand( p ) ); _defaultCloseAllButThisCommand = new RelayCommand( ( p ) => ExecuteCloseAllButThisCommand( p ), ( p ) => CanExecuteCloseAllButThisCommand( p ) ); _defaultCloseAllCommand = new RelayCommand( ( p ) => ExecuteCloseAllCommand( p ), ( p ) => CanExecuteCloseAllCommand( p ) ); _defaultActivateCommand = new RelayCommand( ( p ) => ExecuteActivateCommand( p ), ( p ) => CanExecuteActivateCommand( p ) ); _defaultNewVerticalTabGroupCommand = new RelayCommand( ( p ) => ExecuteNewVerticalTabGroupCommand( p ), ( p ) => CanExecuteNewVerticalTabGroupCommand( p ) ); _defaultNewHorizontalTabGroupCommand = new RelayCommand( ( p ) => ExecuteNewHorizontalTabGroupCommand( p ), ( p ) => CanExecuteNewHorizontalTabGroupCommand( p ) ); _defaultMoveToNextTabGroupCommand = new RelayCommand( ( p ) => ExecuteMoveToNextTabGroupCommand( p ), ( p ) => CanExecuteMoveToNextTabGroupCommand( p ) ); _defaultMoveToPreviousTabGroupCommand = new RelayCommand( ( p ) => ExecuteMoveToPreviousTabGroupCommand( p ), ( p ) => CanExecuteMoveToPreviousTabGroupCommand( p ) ); } protected virtual void ClearDefaultBindings() { if( CloseCommand == _defaultCloseCommand ) BindingOperations.ClearBinding( this, CloseCommandProperty ); if( FloatCommand == _defaultFloatCommand ) BindingOperations.ClearBinding( this, FloatCommandProperty ); if( DockAsDocumentCommand == _defaultDockAsDocumentCommand ) BindingOperations.ClearBinding( this, DockAsDocumentCommandProperty ); if( CloseAllButThisCommand == _defaultCloseAllButThisCommand ) BindingOperations.ClearBinding( this, CloseAllButThisCommandProperty ); if( CloseAllCommand == _defaultCloseAllCommand ) BindingOperations.ClearBinding( this, CloseAllCommandProperty ); if( ActivateCommand == _defaultActivateCommand ) BindingOperations.ClearBinding( this, ActivateCommandProperty ); if( NewVerticalTabGroupCommand == _defaultNewVerticalTabGroupCommand ) BindingOperations.ClearBinding( this, NewVerticalTabGroupCommandProperty ); if( NewHorizontalTabGroupCommand == _defaultNewHorizontalTabGroupCommand ) BindingOperations.ClearBinding( this, NewHorizontalTabGroupCommandProperty ); if( MoveToNextTabGroupCommand == _defaultMoveToNextTabGroupCommand ) BindingOperations.ClearBinding( this, MoveToNextTabGroupCommandProperty ); if( MoveToPreviousTabGroupCommand == _defaultMoveToPreviousTabGroupCommand ) BindingOperations.ClearBinding( this, MoveToPreviousTabGroupCommandProperty ); } protected virtual void SetDefaultBindings() { if( CloseCommand == null ) CloseCommand = _defaultCloseCommand; if( FloatCommand == null ) FloatCommand = _defaultFloatCommand; if( DockAsDocumentCommand == null ) DockAsDocumentCommand = _defaultDockAsDocumentCommand; if( CloseAllButThisCommand == null ) CloseAllButThisCommand = _defaultCloseAllButThisCommand; if( CloseAllCommand == null ) CloseAllCommand = _defaultCloseAllCommand; if( ActivateCommand == null ) ActivateCommand = _defaultActivateCommand; if( NewVerticalTabGroupCommand == null ) NewVerticalTabGroupCommand = _defaultNewVerticalTabGroupCommand; if( NewHorizontalTabGroupCommand == null ) NewHorizontalTabGroupCommand = _defaultNewHorizontalTabGroupCommand; if( MoveToNextTabGroupCommand == null ) MoveToNextTabGroupCommand = _defaultMoveToNextTabGroupCommand; if( MoveToPreviousTabGroupCommand == null ) MoveToPreviousTabGroupCommand = _defaultMoveToPreviousTabGroupCommand; IsSelected = LayoutElement.IsSelected; IsActive = LayoutElement.IsActive; CanClose = LayoutElement.CanClose; } protected virtual void OnVisibilityChanged() { if( LayoutElement != null && Visibility == System.Windows.Visibility.Collapsed ) LayoutElement.Close(); } internal virtual void Attach( LayoutContent model ) { LayoutElement = model; Model = model.Content; InitDefaultCommands(); LayoutElement.IsSelectedChanged += new EventHandler( LayoutElement_IsSelectedChanged ); LayoutElement.IsActiveChanged += new EventHandler( LayoutElement_IsActiveChanged ); DataContext = this; } internal virtual void Detach() { LayoutElement.IsSelectedChanged -= new EventHandler( LayoutElement_IsSelectedChanged ); LayoutElement.IsActiveChanged -= new EventHandler( LayoutElement_IsActiveChanged ); LayoutElement = null; Model = null; } internal void _ClearDefaultBindings() { ClearDefaultBindings(); } internal void _SetDefaultBindings() { SetDefaultBindings(); } internal bool IsViewExists() { return ( _view != null ); } #endregion #region Private Methods private void LayoutElement_IsActiveChanged( object sender, EventArgs e ) { if( _isActiveReentrantFlag.CanEnter ) { using( _isActiveReentrantFlag.Enter() ) { var bnd = BindingOperations.GetBinding( this, IsActiveProperty ); IsActive = LayoutElement.IsActive; var bnd2 = BindingOperations.GetBinding( this, IsActiveProperty ); } } } private void LayoutElement_IsSelectedChanged( object sender, EventArgs e ) { if( _isSelectedReentrantFlag.CanEnter ) { using( _isSelectedReentrantFlag.Enter() ) { IsSelected = LayoutElement.IsSelected; } } } private static void OnToolTipChanged( DependencyObject s, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )s ).OnToolTipChanged(); } private void OnToolTipChanged() { if( LayoutElement != null ) LayoutElement.ToolTip = ToolTip; } private static void OnVisibilityChanged( DependencyObject s, DependencyPropertyChangedEventArgs e ) { ( ( LayoutItem )s ).OnVisibilityChanged(); } #endregion } }