2009-11-16 10 views
1

J'ai un FlowDocument avec beaucoup de contenu à l'intérieur. Je dois obtenir les contrôles qui sont actuellement dans la zone visible.Obtenir les contrôles visibles par position

Avec le code suivant, j'ai pu obtenir la position de défilement actuelle.

DependencyObject obj = FlowDocumentScrollViewerCtrl; 

do 
{ 
    if (VisualTreeHelper.GetChildrenCount(obj) > 0) 
    { 
     obj = VisualTreeHelper.GetChild(obj as Visual, 0); 
    } 
} 
while (!(obj is ScrollViewer)); 

ScrollViewer sv = obj as ScrollViewer; 

Comment puis-je obtenir les contrôles dans la zone visible?

Répondre

0

Une façon est de descendre récursivement l'arbre à l'aide de Visual VisualTreeHelper.GetChildrenCount et VisualTreeHelper.GetChild() et vérifier chaque visuel en utilisant cette procédure:

  1. Throw toute visuelle qui n'est pas intéressant de votre code (par exemple, vous ne pouvez souciez Commandes)
  2. Récupère chaque boîte englobante de Visual en utilisant new Rect(0, 0, visual.ActualWidth, visual.ActualHeight). Cela vous donnera la boîte englobante dans le système de coordonnées du Visual.
  3. Utilisez la transformation renvoyée par visual.TransformToAncestor(viewer) pour transformer la zone de délimitation dans le système de coordonnées du visualiseur.
  4. Vérifiez si la boîte englobante du visuel transformé intersecte la boîte englobante du spectateur. Une vérification grossière peut être effectuée en prenant les X et Y minimum et maximum des coins de la boîte de délimitation visuelle et en comparant simplement un axe à la fois. C'est plus facile que l'intersection rectangle complet, et devrait servir à la plupart des fins.

Ceci vous dira tous les visuels dans la zone visible. Si vous souhaitez mapper vers FrameworkContentElement s comme <Paragraph>, consultez simplement la propriété Content du ContentPresenter que vous parcourez dans votre parcours.

0

Merci Ray pour votre réponse. J'ai suivi vos conseils sur certains points hier et c'est le code de travail pour mon problème:

public class FrameworkElementInfo 
{ 
    Point _position    = new Point(); 
    FrameworkElement _element = null; 

    public Point Position 
    { 
     get { return _position; } 
     set { _position = value; } 
    } 

    public FrameworkElement FrameworkElement 
    { 
     get { return _element; } 
     set { _element = value; } 
    } 
} 

public class ScrollViewPositionManager 
{ 
    ScrollViewer _scrollViewer    = null; 
    List<FrameworkElementInfo> _elements = new List<FrameworkElementInfo>(); 
    double _zoom       = 100.0; 

    public ScrollViewPositionManager(ScrollViewer scrollViewer, double zoom) 
    { 
     _scrollViewer = scrollViewer; 
     _zoom = zoom; 
    } 

    public void RegisterElement(FrameworkElement element, Boolean registerOnly) 
    { 
     FrameworkElementInfo info = new FrameworkElementInfo(); 

     if (!registerOnly) info.Position = CalculatePosition(element); 
     info.FrameworkElement = element; 

     _elements.Add(info); 
    } 

    public void RecalculatePositions() 
    { 
     int Counter = 0; 

     foreach(FrameworkElementInfo info in _elements) 
     { 
      Counter += 1; 
      info.Position = CalculatePosition(info.FrameworkElement); 
     } 
    } 

    public List<FrameworkElement> GetElementsInViewPort() 
    { 
     List<FrameworkElement> elements = new List<FrameworkElement>(); 

     double verticalOffsetHigh = _scrollViewer.ViewportHeight + _scrollViewer.VerticalOffset; 

     foreach (FrameworkElementInfo info in _elements) 
     { 
      Point point = info.Position; 

      if (point.Y >= _scrollViewer.VerticalOffset && 
       point.Y <= verticalOffsetHigh) 
      { 
       elements.Add(info.FrameworkElement); 
      } 
     } 

     return elements; 
    } 

    private Point CalculatePosition(FrameworkElement element) 
    { 
     GeneralTransform elementTransform = element.TransformToAncestor(_scrollViewer); 
     Point elementPoint = elementTransform.Transform(new Point(0, 0)); 
     Point transformedPoint = new Point(elementPoint.X, elementPoint.Y); 

     transformedPoint = GetZoomedPoint(elementPoint, _zoom, _scrollViewer.HorizontalOffset, _scrollViewer.VerticalOffset); 

     return transformedPoint; 
    } 

    static public Point GetZoomedPoint(Point unzoomedPoint, double zoom, double offsetX, double offsetY) 
    { 
     Point zoomedPoint = new Point(); 

     double zoomFactor = 100.0/zoom; 

     zoomedPoint.X = offsetX + unzoomedPoint.X * zoomFactor; 
     zoomedPoint.Y = offsetY + unzoomedPoint.Y * zoomFactor; 

     return zoomedPoint; 
    } 

    public int ElementCount 
    { 
     get { return _elements.Count; } 
    } 

    public FrameworkElement GetFirstElement() 
    { 
     FrameworkElement firstElement = null; 

     if(_elements.Count > 0) firstElement = _elements[0].FrameworkElement; 

     return firstElement; 
    } 

    public FrameworkElement GetLastElement() 
    { 
     FrameworkElement lastElement = null; 

     if (_elements.Count > 0) lastElement = _elements[_elements.Count-1].FrameworkElement; 

     return lastElement; 
    } 

    public FrameworkElement GetNextElement(FrameworkElement element) 
    { 
     FrameworkElement nextElement = null; 
     int index = GetElementIndex(element); 

     if(index != -1 && index != _elements.Count -1) 
     {   
      nextElement = _elements[index + 1].FrameworkElement; 
     } 

     return nextElement; 
    } 

    public FrameworkElement GetPreviousElement(FrameworkElement element) 
    { 
     FrameworkElement previousElement = null; 
     int index = GetElementIndex(element); 

     if (index > 1) 
     { 
      previousElement = _elements[index - 1].FrameworkElement; 
     } 

     return previousElement; 
    } 

    public int GetElementIndex(FrameworkElement element) 
    { 
     return _elements.FindIndex(
          delegate(FrameworkElementInfo currentElement) 
          { 
           if(currentElement.FrameworkElement == element) return true; 
           return false; 
          } 
     ); 
    } 
} 

J'utilise une fonction de registre pour les éléments d'intérêt et en travaillant uniquement sur eux. Le zoom est seulement nécessaire pour un FlowDocument je pense. Ce code devrait fonctionner sur chaque contrôle qui utilise un ScrollViewer. J'apprécierais que quelqu'un puisse le commenter s'il s'agit d'une solution pratique.

Questions connexes