Como posso fazer a rolagem Silverlight ScrollViewer para mostrar um controle filho com o foco?

StackOverflow https://stackoverflow.com/questions/1225318

  •  22-07-2019
  •  | 
  •  

Pergunta

Eu tenho um ScrollViewer que contém uma grade com vários controles na mesma. A guia usuário pode através dos controles, mas, eventualmente, eles guia para um controle que não está em vista -. Então eles têm que percorrer manully para fazer o controle visível novamente

Existe alguma maneira de fazer o ScrollViewer rolar automaticamente para que o controle focalizada é sempre visível. Falhando isso, existe alguma maneira eu posso fazer este trabalho, falta de ouvir um evento GotFocus em cada controle e, em seguida, rolar a ScrollViewer para tornar o controle visível?

No momento eu estou usando Silverlight 2.

Foi útil?

Solução

Eu testei isso usando Silverlight 3. Eu não estou certo sobre SL2.

Este é o meu 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>

E este é o código-behind:

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

O que fiz foi a clicar no botão # 1 e guia até eu chegar ao botão # 20. Ela trabalhou para mim. Dê-lhe uma tentativa e deixe-me saber como ele funciona para você.

Outras dicas

O kit de ferramentas Silverlight contém um método "ScrollIntoView".

Adicione uma referência para System.Windows.Controls.Toolkit.dll ans você deve ser capaz de usar o código abaixo.

scrollViewer.ScrollIntoView(control);

Apenas uma ligeira melhoria. Ainda precisa fazer isso para Silverlight 4 pelo caminho. Em vez de GotFocus para cada controle que você pode lidar com o GotFocus do próprio scrollviewer e implementá-lo apenas uma vez.

 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
        }

Eu tenho essa para o trabalho, com a ajuda da resposta de Kiril acima. O contexto geral deste é que eu tenho formas defineable pelo usuário no meu aplicativo, e este código é utilizado para tornar os controles em um formulário.

A minha estratégia geral foi adicionar meus controles a uma grade, em seguida, encontrar todos os filhos do ScrollViewer usando VisualTreeHelper, e adicionar um manipulador de eventos GotFocus para cada controle.

Quando o controle recebe o foco, novamente usando VisualTreeHelper, eu procurar-se a árvore visual para encontrar o controle cujo pai é a grade que está sendo rolada pelo ScrollViewer. Então eu rolar a ScrollViewer para tornar o controle visível.

Aqui está o código (gridRender é a grade que os controles são adicionados):

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

Nota:. A classe VisualTreeHelperUtil é a minha própria classe que adiciona algumas funcionalidades pesquisa útil para a classe VisualTreeHelper

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top