Implementando Templates Hierárquicos de Três Níveis em TreeView com Binding WPF

Para criar uma árvore de navegação rica e escalável em aplicações WPF, é essencial dominar a construção de HierarchicalDataTemplate com múltiplos níveis. Ao contrário de templates planos, modelos hierárquicos permitem representar relações pai-filho naturalmente — como pastas contendo subpastas, que por sua vez contêm arquivos — tudo com suporte nativo a notificação de alterações e binding bidirecional.

O segredo está na cadeia de ItemsSource vinculada a propriedades de coleção observável em cada nível. Cada template deve declarar explicitamente:

  • DataType: tipo CLR da classe que o template representa (ex: Department, Team, Employee);
  • ItemsSource: caminho de propriedade que retorna a coleção de itens do nível imediatamente inferior;
  • Conteúdo visual: elementos de UI que exibem dados da instância atual (ex: TextBlock ligado à propriedade Name).

Abaixo segue um exemplo reescrito com estrutura clara, nomes descritivos e lógica robusta — sem dependência de classes genéricas ou convenções obscuras:

<!-- Nível 2: Equipes -->
<HierarchicalDataTemplate DataType="{x:Type local:Team}" ItemsSource="{Binding Members}">
  <StackPanel Orientation="Horizontal" Margin="2">
    <Image Source="/Assets/team.png" Width="16" Height="16" Margin="0,0,4,0"/>
    <TextBlock Text="{Binding TeamTitle}" FontStyle="Italic" Foreground="#3498DB"/>
  </StackPanel>
</HierarchicalDataTemplate>

<!-- Nível 3: Membros individuais -->
<DataTemplate DataType="{x:Type local:StaffMember}">
  <StackPanel Orientation="Horizontal" Margin="2">
    <Image Source="/Assets/person.png" Width="16" Height="16" Margin="0,0,4,0"/>
    <TextBlock Text="{Binding FullName}" Foreground="#27AE60"/>
  </StackPanel>
</DataTemplate>

</TreeView.Resources> </TreeView>


</div>As classes subjacentes devem implementar `INotifyPropertyChanged` e usar `ObservableCollection<T>` para garatnir atualizações automáticas da interface. Veja as versões simplificadas e modernizadas:

<div class="code-block">```
public class Department : INotifyPropertyChanged
{
    private string _displayName;
    private ObservableCollection<Team> _subDepartments = new();

    public string DisplayName
    {
        get => _displayName;
        set { _displayName = value; OnPropertyChanged(); }
    }

    public ObservableCollection<Team> SubDepartments => _subDepartments;

    public event PropertyChangedEventHandler? PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string TeamTitle
{
    get => _teamTitle;
    set { _teamTitle = value; OnPropertyChanged(); }
}

public ObservableCollection<StaffMember> Members => _members;

public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) =>
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

}


</div><div class="code-block">```
public class StaffMember : INotifyPropertyChanged
{
    private string _fullName;

    public string FullName
    {
        get => _fullName;
        set { _fullName = value; OnPropertyChanged(); }
    }

    public event PropertyChangedEventHandler? PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

OrganizationalTree.ItemsSource = root;


</div>Para estilização avançada, é possível substituir o `ControlTemplate` padrão do `TreeViewItem`, personalizendo ícones de expansão, linhas de conexão e estados visuais (selecionado, desabilitado, expandido). O uso de `ToggleButton` customizado com `ControlTemplate` permite total controle sobre a aparência do botão de expansão — inclusive com gradientes, animações e comportamento condicional baseado em `IsChecked`.

Tags: WPF hierarchicaldatatemplate observablecollection innotifypropertychanged treeview

Publicado em 10-11 17:12