protected virtual void HandlePageDownKey(KeyEventArgs e) { // Ensure to at least process the PageDown as Key.Down // to avoid the TableViewScrollViewer to process the key // directly without moving the focus. e.Handled = DataGridItemsHost.ProcessMoveFocus(Key.Down); // We were not able to move focus out of the // SynchronizedScrollViewer but the focus is still inside. // Mark the key as handled to avoid the DataGridScrollViewer // to process the PageDown. if (!e.Handled && this.IsKeyboardFocusWithin) { e.Handled = true; } }
protected virtual void HandlePreviewTabKey(KeyEventArgs e) { if (e.Handled) { return; } var dataGridControl = this.ParentDataGridControl; if (dataGridControl == null) { return; } var dataGridContext = dataGridControl.CurrentContext; if (dataGridContext == null) { return; } var container = dataGridContext.GetContainerFromItem(dataGridContext.InternalCurrentItem); if (container == null) { return; } var tabbingMode = KeyboardNavigation.GetTabNavigation(container); if (tabbingMode == KeyboardNavigationMode.None) { return; } if ((Keyboard.Modifiers == ModifierKeys.None) || (Keyboard.Modifiers == ModifierKeys.Shift)) { DataGridItemsHost.BringIntoViewKeyboardFocusedElement(); //Force the "inline" relayout of the panel //This has no effect if the panel do not have to be updated. this.UpdateLayout(); } }
protected virtual void HandleRightKey(KeyEventArgs e) { e.Handled = DataGridItemsHost.ProcessMoveFocus(e.Key); }
protected virtual void HandlePreviewDownKey(KeyEventArgs e) { DataGridItemsHost.BringIntoViewKeyboardFocusedElement(); this.UpdateLayout(); }
internal static void ProcessRequestBringIntoView( DataGridItemsHost itemsHost, Orientation orientation, double stableScrollingProportion, RequestBringIntoViewEventArgs e ) { IScrollInfo scrollInfo = itemsHost as IScrollInfo; if( scrollInfo == null ) return; // Only perform this if we are virtualizing. // If not, the ScrollViewer will take care of bringing the item into view. if( ( scrollInfo.ScrollOwner == null ) || ( !scrollInfo.ScrollOwner.CanContentScroll ) ) return; // If we are explicitly setting the focus on a cell, we don't want to bring it into view. // A bringIntoView would cause the HorizontalOffset to change is not a wanted behavior. // Therefore, flag the Request as handled and do nothing. DataGridContext dataGridContext = DataGridControl.GetDataGridContext( itemsHost ); DataGridControl dataGridControl = ( dataGridContext != null ) ? dataGridContext.DataGridControl : null; if( ( dataGridControl != null ) && ( dataGridControl.SettingFocusOnCell ) ) { e.Handled = true; return; } // Only perform this if the object is NOT a Cell and was not passed a specific rectangle. if( ( e.TargetObject is Cell ) || ( e.TargetRect != Rect.Empty ) ) return; // Before performing calculations, ensure that the element is a FrameworkElement. FrameworkElement target = e.TargetObject as FrameworkElement; if( ( target == null ) || ( !target.IsDescendantOf( itemsHost ) ) ) return; // Mark the routed event as handled, since under even the worst circumstances, // a new event will be raised. e.Handled = true; // Ensure to get the offset of the target visual element // according to its Container when it is not directly // a Container. This is to avoid horizontal scrolling when // the NavigationBehavior is None and that the CellsHost // request the focus when there are HierarchicalGroupLevelIndicators // and/or GroupLevelIndicators present in the Container. // This extra space must be taken into consideration, not // only the offset between the target and the ItemsHost. Point targetToParentContainer = TableViewItemsHost.OriginPoint; FrameworkElement targetParentContainer = DataGridItemsHost.GetItemsHostContainerFromElement( itemsHost, target ) as FrameworkElement; if( ( targetParentContainer != null ) && ( target != targetParentContainer ) ) { targetToParentContainer = target.TranslatePoint( TableViewItemsHost.OriginPoint, targetParentContainer ); } Point targetToItemsHostPosition = target.TranslatePoint( TableViewItemsHost.OriginPoint, itemsHost ); double acceptableThreshold; double actualVisibleValue; //Calculate the VisibleWidth/Height of the object within the Viewport. if( orientation == Orientation.Vertical ) { acceptableThreshold = scrollInfo.ViewportWidth * stableScrollingProportion; actualVisibleValue = TableViewItemsHost.GetVisibleDimensionForRequestBringIntoViewTarget( target.ActualWidth, targetToItemsHostPosition.X, scrollInfo.ViewportWidth ); } else { acceptableThreshold = scrollInfo.ViewportHeight * stableScrollingProportion; actualVisibleValue = TableViewItemsHost.GetVisibleDimensionForRequestBringIntoViewTarget( target.ActualHeight, targetToItemsHostPosition.Y, scrollInfo.ViewportHeight ); } Rect newRect = newRect = new Rect( 0, 0, target.ActualWidth, target.ActualHeight ); // After the visible proportion of the object is calculated, compare it with threshold if( actualVisibleValue < acceptableThreshold ) { // The required threshold is not visible, modify the bounds of the rectangle // to bring the desired threshold. if( orientation == Orientation.Vertical ) { if( targetToItemsHostPosition.X >= 0 ) { newRect.Width = Math.Min( acceptableThreshold, target.ActualWidth ); } else { newRect.X = Math.Max( 0, target.ActualWidth - acceptableThreshold ); } } else { if( targetToItemsHostPosition.Y >= 0 ) { newRect.Height = Math.Min( acceptableThreshold, target.ActualHeight ); } else { newRect.Y = Math.Max( 0, target.ActualHeight - acceptableThreshold ); } } target.BringIntoView( newRect ); return; } bool needBringIntoView = false; // Determine if the item is totally or partially visible on the main scrolling axis. if( orientation == Orientation.Vertical ) { needBringIntoView = TableViewItemsHost.TargetRequiresBringIntoView( targetToItemsHostPosition.Y, target.DesiredSize.Height, itemsHost.RenderSize.Height ); } else { needBringIntoView = TableViewItemsHost.TargetRequiresBringIntoView( targetToItemsHostPosition.X, target.DesiredSize.Width, itemsHost.RenderSize.Width ); } // Extra properties that must be verified to conclude // the container must be put into view or not if( itemsHost is TableflowViewItemsHost ) { // TableflowViewItemsHost must take Clip into consideration // since this means the container is not fully visible // and maybe under a Sticky container needBringIntoView |= ( target.GetValue( UIElement.ClipProperty ) != null ); if( !needBringIntoView ) { // If the container is sticky, we must ensure all subsequent containers // wil be correctly layouted and visible. e.g.: the GroupHeaderControl // hides the 1st group value and the 2nd one is partially visible. // If the container to bring into view is the sticky GroupHeaderControl, // the 1st and 2nd group values must be completely visible needBringIntoView |= TableflowViewItemsHost.GetIsSticky( target ); } } if( !needBringIntoView ) return; // The goal is to preserve the actual opposed axis scrolling if( orientation == Orientation.Vertical ) { //if the item to be brough into view is part of the elements in a TableView that do no scroll if( ( dataGridControl != null ) && ( dataGridControl.GetView() is TableView ) && ( !TableViewItemsHost.ComputedCanScrollHorizontally( target, itemsHost ) ) ) { // Nothing to do since the item can't scroll horizontally, use 0 as newRect.X // and ensure to use the container as BringIntoView target since it can't // scroll horizontally if( targetToParentContainer != null ) { target = targetParentContainer; // Ensure that the offset to bring into view // is the HorizontalOffset since it does not // scroll Horizontally. newRect.X = scrollInfo.HorizontalOffset; } } else { newRect.X = TableViewItemsHost.CorrectBringIntoViewRectFromVisibleDimensionAndAcceptableThreshold( actualVisibleValue, acceptableThreshold, targetToItemsHostPosition.X, targetToParentContainer.X, scrollInfo.HorizontalOffset ); } // If the rectangle of the object goes beyond the Viewport if( newRect.Right > scrollInfo.ViewportWidth ) { // Subtract what goes beyond! newRect.Width = newRect.Width - ( newRect.Width - scrollInfo.ViewportWidth ) - Math.Max( targetToItemsHostPosition.X, 0 ); } } else { newRect.Y = TableViewItemsHost.CorrectBringIntoViewRectFromVisibleDimensionAndAcceptableThreshold( actualVisibleValue, acceptableThreshold, targetToItemsHostPosition.Y, targetToParentContainer.Y, scrollInfo.VerticalOffset ); // If the rectangle of the object goes beyond the Viewport if( newRect.Bottom > scrollInfo.ViewportHeight ) { // Subtract what goes beyond! newRect.Height = newRect.Height - ( newRect.Height - scrollInfo.ViewportHeight ) - Math.Max( targetToItemsHostPosition.Y, 0 ); } } target.BringIntoView( newRect ); }
internal static bool ComputedCanScrollHorizontally( FrameworkElement target, DataGridItemsHost itemsHost ) { Debug.Assert( target != null ); bool retval = true; DependencyObject visual = target; do { retval = TableView.GetCanScrollHorizontally( visual ); if( retval ) { visual = TreeHelper.GetParent( visual ); } } while( ( visual != null ) && ( visual != itemsHost ) && ( retval ) ); return retval; }