none
Percorrer TextBox de uma ChildWindow

    Pergunta

  • Bom Dia, Pessoal.

     

    Como posso percorrer todos os TextBox de uma ChildWindow silverlight, para modificar o TextChanged ?

     

    Att.

    quinta-feira, 28 de julho de 2011 12:56

Respostas

  • Manoel,

    As opções dadas pelo Américo e pelo E. Pacheco são simples e válidas, mas há uma forma um pouco mais genérica de fazer esse tipo de busca nos objetos da tela, usando uma classe chamada VisualTreeHelper. Essa classe permite que você faça buscas na árvore visual da aplicação, tanto pra cima quanto para baixo.

    Eu criei a função abaixo para facilitar ainda mais o uso dessa classe.

    public static T[] SearchUIElements<T>(UIElement root, int maxlevel = int.MaxValue, int level = 0) where T : UIElement {
        var result = new List<T>();
     
        if (root != null) {
            if (root is T) {
                result.Add(root as T);
            }
     
            if (level < maxlevel) {
                var childrencount = VisualTreeHelper.GetChildrenCount(root);
                DependencyObject child;
                for (var i = 0; i < childrencount; i++) {
                    child = VisualTreeHelper.GetChild(root, i);
                    if (child is UIElement) {
                        result.AddRange(SearchUIElements<T>(child as UIElement, maxlevel, level + 1));
                    }
                }
            }
        }
     
        return result.ToArray();
    }
    

    Suponhamos que você tenha o seguinte XAML:

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBox />
        <TextBox />
        <Grid>
            <TextBox />
            <TextBox />
            <Grid>
                <TextBox />
            </Grid>
        </Grid>
    </Grid>

    Podemos usar a função das seguintes formas:

    TextBox[] textboxes = SearchUIElements<TextBox>(LayoutRoot); //acha TODOS os 5 campos TextBox 
    textboxes = SearchUIElements<TextBox>(LayoutRoot, 1);        //acha apenas os 2 campos TextBox de LayoutRoot
    textboxes = SearchUIElements<TextBox>(LayoutRoot, 2);        //acha 4. Os 2 acima e os 2 que estão no primeiro Grid filho
    TextBlock[] textblocks = SearchUIElements<TextBlock>(LayoutRoot); //não acha nada, mas procura por TODOS campos TextBlock
    

    Essa é uma função genérica, capaz de achar qualquer tipo de controle na tela. Essa função é executada de forma recursiva até que não existam mais filhos na arvore visual ou até atingir o nível hierárquico máximo passado no segundo parâmetro (que é opcional). O resultado dessa função será um array do tipo de controle solicitado. Sempre será retornado um array, mesmo que seja vazio.

    Mas eu fiquei com uma dúvida: Para que você precisa achar todos os campos TextBox dessa ChildWindow? Qual é exatamente a sua necessidade? Estou perguntando isso pois se você estiver fazendo essa varredura para ler os valores dos campos, a melhor forma seria usar Binding e não manipular a tela. Quanto menos o seu código souber sobre a estrutura da tela, mais fácil será de dar manutenção na aplicação no futuro. Sim, há várias situações onde realmente é necessário fazer algum tipo de varredura na tela ou manipular os controles diretamente, mas quanto menos fizermos isso, melhor.

    Se voce quiser elaborar mais sobre o assunto, estou a disposição para ajudar a encontrar a melhor solução para o seu problema.


    Atenciosamente,

    Kelps Leite de Sousa | MVP Silverlight
    blog: http://kelps.net
    twitter : http://twitter.com/kelps

    Não se esqueça de "marcar como resposta" o ítem que lhe ajudou.


    sexta-feira, 29 de julho de 2011 13:35
    Moderador

Todas as Respostas

  • Cara, pegar o "LayoutRoot" da sua ChildWindow e percorre (com um foreach, por exemplo), os itens da propriedade Children dele.

    Ai uso o "is" pra saber se é TextBox, ou se é um item que contem itens, e se for o caso, faz o mesmo com esse itens ;}

    Quando vc achar seus TextBox é só vc fazer a atribuição normal de métodos a eventos.

    quinta-feira, 28 de julho de 2011 13:06
  • Olá,

    A resposta do E.Pacheco está correta , só para contextualizar :

     foreach (UIElement child in LayoutRoot.Children)
          {
            if (child is TextBox)
            {
              TextBox t = child as TextBox;
              t.TextChanged +=new TextChangedEventHandler(t_TextChanged);
            }         
          }
    

     Espero ter ajudado.


    Américo Arvani
    MCP Frw web 2.0 / MCPD Frw web/win/wcf 3.5
    Se ajudou , marque como resposta.
    http://americoarvani.blogspot.com
    View Americo Arvani's profile on LinkedIn
    quinta-feira, 28 de julho de 2011 13:58
  • Américo, seu código só tem uma falha: ao percorrer o LayoutRoot você pode se deparar com outro Panel (UIElement com Childrens),  que pode conter outro Panel e assim por diante, e no final de tudo, pode haver um TextBox (ou não).

    Ia deixar ele montar o código sozinho, mas vou postá-lo então:

     

    public void ApplyChangeToAll(Panel e)
    {
     foreach (var item in e.Children)
      if (item is TextBox) Size(item as ComboBox);
      else if (item is Panel) SizeAll(item as Panel);
    }
    public void ApplyChange(TextBox e)
    {
     //Faça aqui as mudanças no TextBox (e);
    }
    

     


    Meu código ainda possui uma falha: se você se deparar com um Border (por exemplo), ele não será considerado um Panel, pois só pode alocar um 
    UIElement , enquanto os Panel podem alocar vários. Porem, este border pode conter um Panel.

    Nway, talvez vc n precise de proucupar cm isso, talvez precise, é cm vc.


    • Editado E. Pacheco quinta-feira, 28 de julho de 2011 14:08 Errei o nome de uma classe.
    • Sugerido como Resposta E. Pacheco sexta-feira, 29 de julho de 2011 13:41
    quinta-feira, 28 de julho de 2011 14:06
  • Manoel,

    As opções dadas pelo Américo e pelo E. Pacheco são simples e válidas, mas há uma forma um pouco mais genérica de fazer esse tipo de busca nos objetos da tela, usando uma classe chamada VisualTreeHelper. Essa classe permite que você faça buscas na árvore visual da aplicação, tanto pra cima quanto para baixo.

    Eu criei a função abaixo para facilitar ainda mais o uso dessa classe.

    public static T[] SearchUIElements<T>(UIElement root, int maxlevel = int.MaxValue, int level = 0) where T : UIElement {
        var result = new List<T>();
     
        if (root != null) {
            if (root is T) {
                result.Add(root as T);
            }
     
            if (level < maxlevel) {
                var childrencount = VisualTreeHelper.GetChildrenCount(root);
                DependencyObject child;
                for (var i = 0; i < childrencount; i++) {
                    child = VisualTreeHelper.GetChild(root, i);
                    if (child is UIElement) {
                        result.AddRange(SearchUIElements<T>(child as UIElement, maxlevel, level + 1));
                    }
                }
            }
        }
     
        return result.ToArray();
    }
    

    Suponhamos que você tenha o seguinte XAML:

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBox />
        <TextBox />
        <Grid>
            <TextBox />
            <TextBox />
            <Grid>
                <TextBox />
            </Grid>
        </Grid>
    </Grid>

    Podemos usar a função das seguintes formas:

    TextBox[] textboxes = SearchUIElements<TextBox>(LayoutRoot); //acha TODOS os 5 campos TextBox 
    textboxes = SearchUIElements<TextBox>(LayoutRoot, 1);        //acha apenas os 2 campos TextBox de LayoutRoot
    textboxes = SearchUIElements<TextBox>(LayoutRoot, 2);        //acha 4. Os 2 acima e os 2 que estão no primeiro Grid filho
    TextBlock[] textblocks = SearchUIElements<TextBlock>(LayoutRoot); //não acha nada, mas procura por TODOS campos TextBlock
    

    Essa é uma função genérica, capaz de achar qualquer tipo de controle na tela. Essa função é executada de forma recursiva até que não existam mais filhos na arvore visual ou até atingir o nível hierárquico máximo passado no segundo parâmetro (que é opcional). O resultado dessa função será um array do tipo de controle solicitado. Sempre será retornado um array, mesmo que seja vazio.

    Mas eu fiquei com uma dúvida: Para que você precisa achar todos os campos TextBox dessa ChildWindow? Qual é exatamente a sua necessidade? Estou perguntando isso pois se você estiver fazendo essa varredura para ler os valores dos campos, a melhor forma seria usar Binding e não manipular a tela. Quanto menos o seu código souber sobre a estrutura da tela, mais fácil será de dar manutenção na aplicação no futuro. Sim, há várias situações onde realmente é necessário fazer algum tipo de varredura na tela ou manipular os controles diretamente, mas quanto menos fizermos isso, melhor.

    Se voce quiser elaborar mais sobre o assunto, estou a disposição para ajudar a encontrar a melhor solução para o seu problema.


    Atenciosamente,

    Kelps Leite de Sousa | MVP Silverlight
    blog: http://kelps.net
    twitter : http://twitter.com/kelps

    Não se esqueça de "marcar como resposta" o ítem que lhe ajudou.


    sexta-feira, 29 de julho de 2011 13:35
    Moderador
  • Excelente, excelente.
    sexta-feira, 29 de julho de 2011 13:40