Example #1
0
        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();
            }
        }
Example #3
0
 protected virtual void HandleRightKey(KeyEventArgs e)
 {
     e.Handled = DataGridItemsHost.ProcessMoveFocus(e.Key);
 }
Example #4
0
 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;
    }