private int GetChildIndexForHeader(MultiPanel.HeaderRenderInformation child, List<MultiPanel.HeaderRenderInformation> headerRenderAreas) { var index = -1; foreach (var area in headerRenderAreas) { index++; if (area == child) break; } return index; }
/// <summary> /// Invoked when an unhandled System.Windows.Input.Mouse.MouseUp routed event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. /// </summary> /// <param name="multiPanel">The multi panel.</param> /// <param name="e">The <see cref="T:System.Windows.Input.MouseButtonEventArgs" /> that contains the event data. The event data reports that the mouse button was released.</param> /// <param name="headerRenderAreas"></param> public void OnMouseUp(MultiPanel multiPanel, MouseButtonEventArgs e, List<MultiPanel.HeaderRenderInformation> headerRenderAreas) { if (e.ChangedButton != MouseButton.Left) return; if (_lastLeftMouseDownPosition.X < 0 || _lastLeftMouseDownPosition.Y < 0) return; var position = e.GetPosition(multiPanel); var overClose = false; var lastLeftMouseDownPosition = new Point(_lastLeftMouseDownPosition.X, _lastLeftMouseDownPosition.Y); _lastLeftMouseDownPosition = new Point(-1, -1); // Since we are now in up-state again, we wipe out the last info foreach (var child in headerRenderAreas.Where(area => area.TotalArea.Contains(lastLeftMouseDownPosition) && SimpleView.GetClosable(area.Child))) { var clientArea = GetClientArea(child.TotalArea); if (Orientation == Orientation.Horizontal) { var headerHeight = clientArea.Top - child.TotalArea.Top; overClose = (lastLeftMouseDownPosition.Y <= clientArea.Top && lastLeftMouseDownPosition.X >= child.TotalArea.Width - headerHeight); } else { var headerWidth = clientArea.Left - child.TotalArea.Left; overClose = (lastLeftMouseDownPosition.X <= clientArea.Left && lastLeftMouseDownPosition.Y <= child.TotalArea.Top + headerWidth); } } if (!overClose) return; // The down-click didn't happen over a close button, so we are already done MultiPanel.HeaderRenderInformation elementInfo = null; foreach (var child in headerRenderAreas.Where(area => area.TotalArea.Contains(position) && SimpleView.GetClosable(area.Child))) { var clientArea = GetClientArea(child.TotalArea); if (Orientation == Orientation.Horizontal) { var headerHeight = clientArea.Top - child.TotalArea.Top; if (position.Y <= clientArea.Top && position.X >= child.TotalArea.Width - headerHeight) { elementInfo = child; break; } } else { var headerWidth = clientArea.Left - child.TotalArea.Left; if (position.X <= clientArea.Left && position.Y <= child.TotalArea.Top + headerWidth) { elementInfo = child; break; } } } if (elementInfo == null) return; // The up-click wasn't over a close button, so we ignore it var action = SimpleView.GetCloseAction(elementInfo.Child); if (action == null) elementInfo.Child.Visibility = Visibility.Collapsed; else if (action.CanExecute(elementInfo.Child)) action.Execute(elementInfo.Child); multiPanel.InvalidateArrange(); multiPanel.InvalidateMeasure(); multiPanel.InvalidateVisual(); }
/// <summary> /// Invoked when an unhandled System.Windows.Input.Mouse.MouseMove attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. /// </summary> /// <param name="multiPanel">The multi panel.</param> /// <param name="e">The <see cref="T:System.Windows.Input.MouseEventArgs" /> that contains the event data.</param> /// <param name="headerRenderAreas"></param> public void OnMouseMove(MultiPanel multiPanel, MouseEventArgs e, List<MultiPanel.HeaderRenderInformation> headerRenderAreas) { var position = e.GetPosition(multiPanel); if (e.LeftButton == MouseButtonState.Pressed) foreach (var child in headerRenderAreas.Where(area => area.TotalArea.Contains(position) && SimpleView.GetSupportsDocking(area.Child))) { var clientArea = GetClientArea(child.TotalArea); if (Orientation == Orientation.Horizontal) { if (position.Y > clientArea.Top) continue; } else { if (position.X > clientArea.Left) continue; } var floatWindow = new FloatingDockWindow(multiPanel, SimpleView.GetTitle(child.Child), GetChildIndexForHeader(child, headerRenderAreas)) { Height = child.TotalArea.Height + 25, Width = child.TotalArea.Width + 10 }; if (FloatWindowStyle != null) floatWindow.Style = FloatWindowStyle; try { if (TemplatedParent == null) { if (multiPanel.Children.Contains(child.Child)) multiPanel.Children.Remove(child.Child); } else { var itemsControl = TemplatedParent as ItemsControl; if (itemsControl != null) { if (itemsControl.Items.Contains(child.Child)) itemsControl.Items.Remove(child.Child); } else { var itemsPresenter = TemplatedParent as ItemsPresenter; if (itemsPresenter != null) { var itemsControl2 = ElementHelper.FindVisualTreeParent<ItemsControl>(itemsPresenter) as ItemsControl; if (itemsControl2 != null) { if (itemsControl2.Items.Contains(child.Child)) itemsControl2.Items.Remove(child.Child); } } } } floatWindow.Content = child.Child; } catch { } var absolutePosition = multiPanel.PointToScreen(position); floatWindow.Top = absolutePosition.Y - 10; floatWindow.Left = absolutePosition.X - 20; floatWindow.Show(); multiPanel.InvalidateArrange(); multiPanel.InvalidateMeasure(); multiPanel.InvalidateVisual(); e.Handled = true; floatWindow.DragMove(); return; } // We check whether we need to show a special cursor if (e.LeftButton == MouseButtonState.Released) { var overClose = false; foreach (var child in headerRenderAreas.Where(area => area.TotalArea.Contains(position) && SimpleView.GetClosable(area.Child))) { var clientArea = GetClientArea(child.TotalArea); if (Orientation == Orientation.Horizontal) { var headerHeight = clientArea.Top - child.TotalArea.Top; overClose = (position.Y <= clientArea.Top && position.X >= child.TotalArea.Width - headerHeight); } else { var headerWidth = clientArea.Left - child.TotalArea.Left; overClose = (position.X <= clientArea.Left && position.Y <= child.TotalArea.Top + headerWidth); } } Mouse.SetCursor(overClose ? Cursors.Hand : Cursors.Arrow); if (overClose) e.Handled = true; } }
/// <summary> /// Invoked when an unhandled System.Windows.Input.Mouse.MouseLeave attached event is raised on this element. Implement this method to add class handling for this event. /// </summary> /// <param name="multiPanel">The multi panel.</param> /// <param name="e">The <see cref="T:System.Windows.Input.MouseEventArgs" /> that contains the event data.</param> /// <param name="headerRenderAreas"></param> public void OnMouseLeave(MultiPanel multiPanel, MouseEventArgs e, List<MultiPanel.HeaderRenderInformation> headerRenderAreas) { }
/// <summary> /// Invoked when an unhandled System.Windows.Input.Mouse.MouseDown attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. /// </summary> /// <param name="multiPanel">The multi panel.</param> /// <param name="e">The <see cref="T:System.Windows.Input.MouseButtonEventArgs" /> that contains the event data. This event data reports details about the mouse button that was pressed and the handled state.</param> /// <param name="headerRenderAreas"></param> public void OnMouseDown(MultiPanel multiPanel, MouseButtonEventArgs e, List<MultiPanel.HeaderRenderInformation> headerRenderAreas) { if (e.ChangedButton != MouseButton.Left) return; _lastLeftMouseDownPosition = e.GetPosition(multiPanel); }
/// <summary> /// Initializes a new instance of the <see cref="FloatingDockWindow" /> class. /// </summary> /// <param name="multiPanel">The multi panel parent container.</param> /// <param name="title">The title.</param> /// <param name="oldChildIndex">Old index of the child in the multi panel.</param> public FloatingDockWindow(MultiPanel multiPanel, string title, int oldChildIndex) { DataContext = multiPanel.DataContext; Title = title; Closing += (o, e) => { if (AutoDockOnClose) { var content = Content as UIElement; Content = null; if (content != null) { multiPanel.Children.Insert(oldChildIndex, content); multiPanel.InvalidateArrange(); multiPanel.InvalidateMeasure(); multiPanel.InvalidateVisual(); } } }; }