/************************************************************************************* 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.Generic; using System.Linq; using System.Text; using System.Windows; using System.Runtime.InteropServices; using System.Windows.Interop; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; using System.Windows.Input; using Xceed.Wpf.AvalonDock.Layout; using Xceed.Wpf.AvalonDock.Converters; using System.Diagnostics; using System.Windows.Controls.Primitives; using Xceed.Wpf.AvalonDock.Commands; using Microsoft.Windows.Shell; namespace Xceed.Wpf.AvalonDock.Controls { public class LayoutAnchorableFloatingWindowControl : LayoutFloatingWindowControl, IOverlayWindowHost { static LayoutAnchorableFloatingWindowControl() { DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutAnchorableFloatingWindowControl), new FrameworkPropertyMetadata(typeof(LayoutAnchorableFloatingWindowControl))); } internal LayoutAnchorableFloatingWindowControl(LayoutAnchorableFloatingWindow model) :base(model) { _model = model; HideWindowCommand = new RelayCommand((p) => OnExecuteHideWindowCommand(p), (p) => CanExecuteHideWindowCommand(p)); } internal override void UpdateThemeResources( Xceed.Wpf.AvalonDock.Themes.Theme oldTheme = null ) { base.UpdateThemeResources(oldTheme); if (_overlayWindow != null) _overlayWindow.UpdateThemeResources(oldTheme); } LayoutAnchorableFloatingWindow _model; public override ILayoutElement Model { get { return _model; } } #region SingleContentLayoutItem /// /// SingleContentLayoutItem Dependency Property /// public static readonly DependencyProperty SingleContentLayoutItemProperty = DependencyProperty.Register("SingleContentLayoutItem", typeof(LayoutItem), typeof(LayoutAnchorableFloatingWindowControl), new FrameworkPropertyMetadata((LayoutItem)null, new PropertyChangedCallback(OnSingleContentLayoutItemChanged))); /// /// Gets or sets the SingleContentLayoutItem property. This dependency property /// indicates the layout item of the selected content when is shown a single anchorable pane. /// public LayoutItem SingleContentLayoutItem { get { return (LayoutItem)GetValue(SingleContentLayoutItemProperty); } set { SetValue(SingleContentLayoutItemProperty, value); } } /// /// Handles changes to the SingleContentLayoutItem property. /// private static void OnSingleContentLayoutItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((LayoutAnchorableFloatingWindowControl)d).OnSingleContentLayoutItemChanged(e); } /// /// Provides derived classes an opportunity to handle changes to the SingleContentLayoutItem property. /// protected virtual void OnSingleContentLayoutItemChanged(DependencyPropertyChangedEventArgs e) { } #endregion protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); var manager = _model.Root.Manager; Content = manager.CreateUIElementForModel(_model.RootPanel); //SetBinding(VisibilityProperty, new Binding("IsVisible") { Source = _model, Converter = new BoolToVisibilityConverter(), Mode = BindingMode.OneWay, ConverterParameter = Visibility.Hidden }); //Issue: http://avalondock.codeplex.com/workitem/15036 IsVisibleChanged += (s, args) => { var visibilityBinding = GetBindingExpression(VisibilityProperty); if (IsVisible && (visibilityBinding == null)) { SetBinding(VisibilityProperty, new Binding("IsVisible") { Source = _model, Converter = new BoolToVisibilityConverter(), Mode = BindingMode.OneWay, ConverterParameter = Visibility.Hidden }); } }; SetBinding(SingleContentLayoutItemProperty, new Binding("Model.SinglePane.SelectedContent") { Source = this, Converter = new LayoutItemFromLayoutModelConverter() }); _model.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(_model_PropertyChanged); } void _model_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (e.PropertyName == "RootPanel" && _model.RootPanel == null) { InternalClose(); } } bool IOverlayWindowHost.HitTest(Point dragPoint) { Rect detectionRect = new Rect(this.PointToScreenDPIWithoutFlowDirection(new Point()), this.TransformActualSizeToAncestor()); return detectionRect.Contains(dragPoint); } DockingManager IOverlayWindowHost.Manager { get { return _model.Root.Manager; } } OverlayWindow _overlayWindow = null; void CreateOverlayWindow() { if (_overlayWindow == null) _overlayWindow = new OverlayWindow(this); Rect rectWindow = new Rect(this.PointToScreenDPIWithoutFlowDirection(new Point()), this.TransformActualSizeToAncestor()); _overlayWindow.Left = rectWindow.Left; _overlayWindow.Top = rectWindow.Top; _overlayWindow.Width = rectWindow.Width; _overlayWindow.Height = rectWindow.Height; } IOverlayWindow IOverlayWindowHost.ShowOverlayWindow(LayoutFloatingWindowControl draggingWindow) { CreateOverlayWindow(); _overlayWindow.Owner = draggingWindow; _overlayWindow.EnableDropTargets(); _overlayWindow.Show(); return _overlayWindow; } void IOverlayWindowHost.HideOverlayWindow() { _dropAreas = null; _overlayWindow.Owner = null; _overlayWindow.HideDropTargets(); } List _dropAreas = null; IEnumerable IOverlayWindowHost.GetDropAreas(LayoutFloatingWindowControl draggingWindow) { if (_dropAreas != null) return _dropAreas; _dropAreas = new List(); if (draggingWindow.Model is LayoutDocumentFloatingWindow) return _dropAreas; var rootVisual = (Content as FloatingWindowContentHost).RootVisual; foreach (var areaHost in rootVisual.FindVisualChildren()) { _dropAreas.Add(new DropArea( areaHost, DropAreaType.AnchorablePane)); } foreach (var areaHost in rootVisual.FindVisualChildren()) { _dropAreas.Add(new DropArea( areaHost, DropAreaType.DocumentPane)); } return _dropAreas; } protected override void OnClosed(EventArgs e) { var root = Model.Root; root.Manager.RemoveFloatingWindow(this); root.CollectGarbage(); if (_overlayWindow != null) { _overlayWindow.Close(); _overlayWindow = null; } base.OnClosed(e); if (!CloseInitiatedByUser) { root.FloatingWindows.Remove(_model); } _model.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler(_model_PropertyChanged); } protected override void OnClosing(System.ComponentModel.CancelEventArgs e) { if (CloseInitiatedByUser && !KeepContentVisibleOnClose) { e.Cancel = true; _model.Descendents().OfType().ToArray().ForEach((a) => a.Hide()); } base.OnClosing(e); } protected override IntPtr FilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { case Win32Helper.WM_NCLBUTTONDOWN: //Left button down on title -> start dragging over docking manager if (wParam.ToInt32() == Win32Helper.HT_CAPTION) { _model.Descendents().OfType().First(p => p.ChildrenCount > 0 && p.SelectedContent != null).SelectedContent.IsActive = true; handled = true; } break; case Win32Helper.WM_NCRBUTTONUP: if (wParam.ToInt32() == Win32Helper.HT_CAPTION) { if (OpenContextMenu()) handled = true; if (_model.Root.Manager.ShowSystemMenu) WindowChrome.GetWindowChrome(this).ShowSystemMenu = !handled; else WindowChrome.GetWindowChrome(this).ShowSystemMenu = false; } break; } return base.FilterMessage(hwnd, msg, wParam, lParam, ref handled); } bool OpenContextMenu() { var ctxMenu = _model.Root.Manager.AnchorableContextMenu; if (ctxMenu != null && SingleContentLayoutItem != null) { ctxMenu.PlacementTarget = null; ctxMenu.Placement = PlacementMode.MousePoint; ctxMenu.DataContext = SingleContentLayoutItem; ctxMenu.IsOpen = true; return true; } return false; } bool IsContextMenuOpen() { var ctxMenu = _model.Root.Manager.AnchorableContextMenu; if (ctxMenu != null && SingleContentLayoutItem != null) { return ctxMenu.IsOpen; } return false; } #region HideWindowCommand public ICommand HideWindowCommand { get; private set; } private bool CanExecuteHideWindowCommand(object parameter) { if (Model == null) return false; var root = Model.Root; if (root == null) return false; var manager = root.Manager; if (manager == null) return false; bool canExecute = false; foreach (var anchorable in this.Model.Descendents().OfType().ToArray()) { if (!anchorable.CanHide) { canExecute = false; break; } var anchorableLayoutItem = manager.GetLayoutItemFromModel(anchorable) as LayoutAnchorableItem; if (anchorableLayoutItem == null || anchorableLayoutItem.HideCommand == null || !anchorableLayoutItem.HideCommand.CanExecute(parameter)) { canExecute = false; break; } canExecute = true; } return canExecute; } private void OnExecuteHideWindowCommand(object parameter) { var manager = Model.Root.Manager; foreach (var anchorable in this.Model.Descendents().OfType().ToArray()) { var anchorableLayoutItem = manager.GetLayoutItemFromModel(anchorable) as LayoutAnchorableItem; anchorableLayoutItem.HideCommand.Execute(parameter); } } #endregion } }