Как сделать прокрутку Silverlight ScrollViewer для отображения дочернего элемента управления с фокусом? - PullRequest
13 голосов
/ 04 августа 2009

У меня есть ScrollViewer, который содержит сетку с несколькими элементами управления. Пользователь может перемещаться по элементам управления, но в конечном итоге они переходят к элементу управления, который не отображается, поэтому ему приходится вручную прокручивать, чтобы снова сделать элемент управления видимым.

Есть ли способ сделать прокрутку ScrollViewer автоматически, чтобы сфокусированный элемент управления всегда был виден. Если это не удастся, есть ли способ заставить эту работу работать, кроме прослушивания события GotFocus на каждом элементе управления, а затем прокрутки ScrollViewer для отображения элемента управления?

В настоящее время я использую Silverlight 2.

Ответы [ 4 ]

12 голосов
/ 04 августа 2009

Я проверял это с помощью Silverlight 3. Я не уверен насчет SL2.

Это мой XAML:

<ScrollViewer Height="200" Width="200" KeyUp="ScrollViewer_KeyUp">
    <StackPanel>
        <Button Content="1" Height="20" />
        <Button Content="2" Height="20" />
        <Button Content="3" Height="20" />
        <Button Content="4" Height="20" />
        <Button Content="5" Height="20" />
        <Button Content="6" Height="20" />
        <Button Content="7" Height="20" />
        <Button Content="8" Height="20" />
        <Button Content="9" Height="20" />
    <Button Content="10" Height="20" />
        <Button Content="11" Height="20" />
        <Button Content="12" Height="20" />
        <Button Content="13" Height="20" />
        <Button Content="14" Height="20" />
        <Button Content="15" Height="20" />
        <Button Content="16" Height="20" />
        <Button Content="17" Height="20" />
        <Button Content="18" Height="20" />
        <Button Content="19" Height="20" />
        <Button Content="20" Height="20" />
    </StackPanel>
</ScrollViewer>

А это код позади:

private void ScrollViewer_KeyUp(object sender, KeyEventArgs e)
{
    ScrollViewer scrollViewer = sender as ScrollViewer;
    FrameworkElement focusedElement = FocusManager.GetFocusedElement() as FrameworkElement;
    GeneralTransform focusedVisualTransform = focusedElement.TransformToVisual(scrollViewer);
    Rect rectangle = focusedVisualTransform.TransformBounds(new Rect(new Point(focusedElement.Margin.Left, focusedElement.Margin.Top), focusedElement.RenderSize));
    double newOffset = scrollViewer.VerticalOffset + (rectangle.Bottom - scrollViewer.ViewportHeight);
    scrollViewer.ScrollToVerticalOffset(newOffset);
}

Что я сделал, так это нажал на кнопку № 1 и вкладку, пока не доберусь до кнопки № 20. Это сработало для меня. Попробуйте и дайте мне знать, как это работает для вас.

11 голосов
/ 16 ноября 2010

Набор инструментов silverlight содержит метод "ScrollIntoView".

Добавьте ссылку на System.Windows.Controls.Toolkit.dll и вы сможете использовать приведенный ниже код.

scrollViewer.ScrollIntoView(control);

3 голосов
/ 08 июля 2010

Просто небольшое улучшение. Кстати, сделать это для Silverlight 4 еще нужно. Вместо GotFocus для каждого элемента управления вы можете обрабатывать GotFocus самого прокрутки и реализовывать его только один раз.

 private void _ScrollViewer_GotFocus(object sender, RoutedEventArgs e)
        {
            FrameworkElement element = e.OriginalSource as FrameworkElement;

            if (element != null)
            {
                ScrollViewer scrollViewer = sender as ScrollViewer;
                scrollViewer.ScrollToVerticalOffset(GetVerticalOffset(element, scrollViewer));
            }

        }

        private double GetVerticalOffset(FrameworkElement child, ScrollViewer scrollViewer)
        {
            // Ensure the control is scrolled into view in the ScrollViewer. 
            GeneralTransform focusedVisualTransform = child.TransformToVisual(scrollViewer);
            Point topLeft = focusedVisualTransform.Transform(new Point(child.Margin.Left, child.Margin.Top));
            Rect rectangle = new Rect(topLeft, child.RenderSize);
            double newOffset = scrollViewer.VerticalOffset + (rectangle.Bottom - scrollViewer.ViewportHeight);
            return newOffset < 0 ? 0 : newOffset; // no use returning negative offset
        }
1 голос
/ 05 августа 2009

Я получил это на работу, с помощью ответа Кирилла выше. Общий контекст этого заключается в том, что в моем приложении есть определяемые пользователем формы, и этот код используется для визуализации элементов управления в форме.

Моя общая стратегия состояла в том, чтобы добавить свои элементы управления в Grid, затем найти всех потомков ScrollViewer с помощью VisualTreeHelper и добавить обработчик событий GotFocus для каждого элемента управления.

Когда элемент управления получает фокус, снова используя VisualTreeHelper, я ищу в визуальном дереве элемент управления, чьим родителем является Grid, который прокручивается ScrollViewer. Затем я прокручиваю ScrollViewer, чтобы сделать элемент управления видимым.

Вот код (gridRender - это Сетка, к которой добавляются элементы управления):

private void AfterFormRendered()
{
    var controls = VisualTreeHelperUtil.FindChildren<Control>(gridRender);
    foreach (var ctrl in controls)
    {
        ctrl.GotFocus += CtrlGotFocus;
    }
}

private void CtrlGotFocus(object sender, RoutedEventArgs e)
{
    var ctrl = sender as Control;
    var gridChildControl = VisualTreeHelperUtil.FindParentWithParent(ctrl, gridRender) as FrameworkElement;

    if (gridChildControl != null)
    {
        // Ensure the control is scrolled into view in the ScrollViewer.
        GeneralTransform focusedVisualTransform = gridChildControl.TransformToVisual(scrollViewer);
        Point topLeft = focusedVisualTransform.Transform(new Point(gridChildControl.Margin.Left, gridChildControl.Margin.Top));
        Rect rectangle = new Rect(topLeft, gridChildControl.RenderSize);
        double newOffset = scrollViewer.VerticalOffset + (rectangle.Bottom - scrollViewer.ViewportHeight);    

        scrollViewer.ScrollToVerticalOffset(newOffset);
    }
}

Примечание. Класс VisualTreeHelperUtil - это мой собственный класс, который добавляет некоторые полезные функции поиска в класс VisualTreeHelper.

...