1

FlowDocument内部には多くのコンテンツがあります。現在表示領域にあるコントロールを取得する必要があります。

次のコードで、現在のスクロール位置を取得できました。

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;

可視領域内にコントロールを配置するにはどうすればよいですか?

4

2 に答える 2

0

答えてくれてありがとうレイ。昨日いくつかの点であなたのヒントに従いましたが、それが私の問題の作業コードです:

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;
                            }
        );
    }
}

関心のある要素に対して登録機能を使用し、それらに対してのみ作業します。ズームは、私が思う FlowDocument にのみ必要です。このコードは、ScrollViewer を使用するすべてのコントロールで機能するはずです。これが実用的な解決策である場合、誰かがこれにコメントしていただければ幸いです。

于 2009-11-17T12:07:02.970 に答える
0

VisualTreeHelper.GetChildrenCount1 つの方法は、 andを使用して Visual ツリーを再帰的に下降し、次のVisualTreeHelper.GetChild()手順を使用して各 Visual をチェックすることです。

  1. コードに関係のないビジュアルは破棄します (たとえば、コントロールのみを気にする場合があります)。
  2. を使用して、各ビジュアルの境界ボックスを取得しますnew Rect(0, 0, visual.ActualWidth, visual.ActualHeight)。これにより、ビジュアルの座標系でバウンディング ボックスが得られます。
  3. によって返される変換を使用してvisual.TransformToAncestor(viewer)、境界ボックスをビューアーの座標系に変換します。
  4. 変換されたビジュアルの境界ボックスがビューアーの境界ボックスと交差するかどうかを確認します。大まかなチェックは、ビジュアル バウンディング ボックスのコーナーの X と Y の最小値と最大値を取得し、一度に 1 つの軸を比較するだけで実行できます。これは、完全な長方形の交差よりも簡単で、ほとんどの目的に役立つはずです。

これにより、可視領域内のすべてのビジュアルが表示されます。FrameworkContentElementなどのにマップする場合は、ツリー ウォークで遭遇し<Paragraph>た の Content プロパティを確認してください。ContentPresenter

于 2009-11-16T17:51:55.033 に答える