O controle TreeView é um elemento funadmental em aplicações de desktop Windows Forms (WinForms) quando se precisa exibir dados hierárquicos de forma intuitiva. Ele permite apresentar informações em uma estrutura de árvore expansível e recolhível, onde os usuários podem navegar facilmente entre os nós pai e filho. Este artigo explora as funcionalidades básicas do TreeView em C#, incluindo a construção programática da árvore a partir de dados, manipulação de eventos de seleção e configurações de expansão.
- Construção da Estrutura da Árvore
Para popular um TreeView, geralmente começamos com uma fonte de dados que define a relação pai-filho entre os itens. Uma abordagem comum é usar uma lista de objetos que contêm identificadores para o próprio item e para seu pai.
1.1. Definição do Modelo de Dados
Vamos definir uma classe simples para representar os itens que serão exibidos na árvore. Cada item terá um identificador único, um identificador do pai (onde 0 pode indicar um nó raiz), um texto para exibição e um valor associado.
namespace WinFormsApp1
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
/// <summary>
/// Modelo para itens da árvore hierárquica.
/// </summary>
public class ItemDeArvore
{
/// <summary>
/// Texto a ser exibido no nó da árvore.
/// </summary>
public string TextoExibicao { get; set; }
/// <summary>
/// Valor associado ao nó (pode ser usado para dados adicionais).
/// </summary>
public string ValorAssociado { get; set; }
/// <summary>
/// Identificador único do item.
/// </summary>
public int IdUnico { get; set; }
/// <summary>
/// Identificador do item pai (0 para nós raiz).
/// </summary>
public int IdPai { get; set; }
}
// ... (restante do código da classe Form)
}
}
1.2. Preenchendo o TreeView com Dados Recursivamente
A seguir, criaremos um método que simula a obtenção de dados e outro método auxiliar recursivo para construir os nós da árvore. O método principal será acionado por um botão, limpando o TreeView existente e cnostruindo a nova estrutura.
/// <summary>
/// Manipulador do clique do botão para construir a árvore.
/// </summary>
private void btnCarregarArvore_Click(object sender, EventArgs e)
{
// Simulação de uma fonte de dados
List<ItemDeArvore> listaItens = new List<ItemDeArvore>
{
new ItemDeArvore { IdUnico = 1, TextoExibicao = "Avô", IdPai = 0, ValorAssociado = "Valor do Avô" },
new ItemDeArvore { IdUnico = 2, TextoExibicao = "Pai", IdPai = 1, ValorAssociado = "Valor do Pai" },
new ItemDeArvore { IdUnico = 3, TextoExibicao = "Filho", IdPai = 2, ValorAssociado = "Valor do Filho" },
new ItemDeArvore { IdUnico = 4, TextoExibicao = "Filha", IdPai = 2, ValorAssociado = "Valor da Filha" },
new ItemDeArvore { IdUnico = 5, TextoExibicao = "Tia", IdPai = 1, ValorAssociado = "Valor da Tia" },
new ItemDeArvore { IdUnico = 6, TextoExibicao = "Primo", IdPai = 5, ValorAssociado = "Valor do Primo" }
};
// Chama o método para popular o TreeView
PopularTreeView(myTreeView, listaItens);
}
/// <summary>
/// Popula um controle TreeView a partir de uma lista de ItemDeArvore.
/// </summary>
/// <param name="treeView"></param>O controle TreeView a ser populado.
/// <param name="dados"></param>A lista de ItemDeArvore que contém os dados.
private void PopularTreeView(TreeView treeView, List<ItemDeArvore> dados)
{
treeView.Nodes.Clear(); // Limpa quaisquer nós existentes
// Encontra e adiciona os nós raiz (aqueles com IdPai = 0)
var nosRaiz = dados.Where(item => item.IdPai == 0);
foreach (var itemRaiz in nosRaiz)
{
TreeNode novoNo = CriarNoRecursivo(itemRaiz, dados);
treeView.Nodes.Add(novoNo);
}
}
/// <summary>
/// Método recursivo para criar um TreeNode e seus filhos.
/// </summary>
/// <param name="itemAtual"></param>O ItemDeArvore atual a ser convertido em TreeNode.
/// <param name="todosOsDados"></param>A lista completa de todos os ItemDeArvore para encontrar os filhos.
/// <returns>O TreeNode criado com seus filhos.</returns>
private TreeNode CriarNoRecursivo(ItemDeArvore itemAtual, List<ItemDeArvore> todosOsDados)
{
TreeNode no = new TreeNode(itemAtual.TextoExibicao);
no.Tag = itemAtual; // Armazena o objeto de dados original no Tag do nó
// Encontra todos os filhos do itemAtual
var filhos = todosOsDados.Where(item => item.IdPai == itemAtual.IdUnico);
foreach (var filho in filhos)
{
// Chama recursivamente para criar os nós filhos
no.Nodes.Add(CriarNoRecursivo(filho, todosOsDados));
}
return no;
}
- Manipulação de Eventos de Seleção
Quando um usuário seleciona um nó na árvore, é comum querer exibir informações detalhadas sobre esse nó ou realizar alguma ação. O evento AfterSelect do TreeView é o local ideal para capturar essa interação.
/// <summary>
/// Manipulador do evento AfterSelect do TreeView, acionado quando um nó é selecionado.
/// </summary>
private void myTreeView_AfterSelect(object sender, TreeViewEventArgs e)
{
// Garante que um nó foi realmente selecionado
if (e.Node == null) return;
// Recupera o objeto ItemDeArvore associado ao nó selecionado
ItemDeArvore itemSelecionado = e.Node.Tag as ItemDeArvore;
if (itemSelecionado != null)
{
lblInfoNoSelecionado.Text = $"Nó: {itemSelecionado.TextoExibicao}, Valor: {itemSelecionado.ValorAssociado}";
// Exibe o caminho dos ancestrais do nó selecionado
string caminhoAncestrais = ObterCaminhoAncestral(e.Node);
lblCaminhoAncestral.Text = $"Caminho: {caminhoAncestrais}";
}
}
/// <summary>
/// Constrói uma string com o caminho completo de um nó até a raiz.
/// </summary>
/// <param name="no"></param>O TreeNode do qual o caminho ancestral será obtido.
/// <returns>Uma string representando o caminho ancestral, e.g., "Avô > Pai > Filho".</returns>
private string ObterCaminhoAncestral(TreeNode no)
{
Stack<string> caminho = new Stack<string>();
TreeNode noAtual = no;
while (noAtual != null)
{
caminho.Push(noAtual.Text);
noAtual = noAtual.Parent;
}
// Remove o primeiro elemento (o próprio nó selecionado) se não quiser incluí-lo no "caminho ancestral"
// Se você quer o caminho completo incluindo o nó atual:
// return string.Join(" > ", caminho.ToList());
// Se você quer apenas os ancestrais, sem o nó atual:
if (caminho.Count > 0) caminho.Pop(); // Remove o próprio nó
return string.Join(" > ", caminho.ToList());
}
- Recursos de Expansão e Colapso
O TreeView oferece controle sobre como os nós são exibidos inicialmente e como eles respondem às interações do usuário.
3.1. Expansão Padrão
É possível configurar o TreeView para expandir todos os nós ou apenas os nós de nível superior automaticamente.
/// <summary>
/// Expande todos os nós na árvore.
/// </summary>
private void ExpandirTudo()
{
myTreeView.ExpandAll();
}
/// <summary>
/// Expande apenas os nós de primeiro nível.
/// </summary>
private void ExpandirPrimeiroNivel()
{
foreach (TreeNode no in myTreeView.Nodes)
{
no.Expand();
}
}
3.2. Expansão/Colapso ao Clicar
Por padrão, o TreeView expande e colapsa nós quando o usuário clica no ícone de seta ou no sinal de mais/menos. Para replicar essa funcionalidade com um clique em qualquer parte do texto do nó, você pode usar o evento NodeMouseClick.
/// <summary>
/// Manipulador do evento NodeMouseClick para expandir/colapsar o nó ao clicar.
/// </summary>
private void myTreeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (e.Node != null)
{
if (e.Node.IsExpanded)
{
e.Node.Collapse(); // Se já estiver expandido, colapsa
}
else
{
e.Node.Expand(); // Se estiver colapsado, expande
}
}
}