Guia Completo de XAML: Crie Interfaces de Qualidade em .NET
Domine o Data Binding: Sincronize Código e Interface
Imagine que você tem uma interface de usuário que deve exibir e atualizar dados📝 SQL Básico: SELECT, INSERT, UPDATE e DELETE para Sobreviver!Aprenda os comandos cruciais de SQL para manipular dados em bancos relacionais com exemplos práticos, dicas e boas práticas para livrarias. de forma automática, como um maestro regendo uma orquestra de informações. Data Binding é exatamente isso: a arte de conectar as informações do seu código (back-end) com os elementos da interface
📜 Interfaces: Contratos que Garantem a Ordem no Universo OOP!Descubra como as interfaces em C# funcionam como contratos que garantem implementações flexíveis e robustas, facilitando o design e testes de sistemas. (front-end), garantindo que qualquer mudança seja refletida instantaneamente em ambas as pontas. Neste artigo, vamos mergulhar de forma aprofundada no conceito de Data Binding, entendendo como ele funciona, para que serve e como aplicá-lo em cenários reais, tudo de maneira simples e sem formalidades excessivas.
Tabela de Conteúdo🔗
2. Como funciona o Data Binding?
3. Tipos de Binding mais Comuns
4. DataContext🔍 LINQ to SQL: Esqueça Queries Escritas à Mão!Aprenda a simplificar consultas SQL com LINQ to SQL usando C#. Descubra benefícios, mapeamento de dados, e práticas essenciais para performance! e Fontes de Dados
5. Exemplo Prático📝 Logging com Serilog: Registre Tudo como um Detetive de Bugs!Aprenda a usar Serilog em .NET para registrar logs estruturados, identificar erros e enriquecer informações, transformando seu código num enigma solucionável.: Conectando Propriedade a um Elemento de UI
7. Erros Comuns e Boas Práticas🔢 Operadores Aritméticos: Faça Cálculos como uma Calculadora Humana!Aprenda a dominar operadores aritméticos em C# com exemplos práticos, técnicas de cálculo e dicas para evitar erros e maximizar resultados.
8. Implementação no WPF: XAML🖌️ XAML Básico: Crie Interfaces sem Código C# (Quase)!Descubra como usar XAML para criar interfaces atrativas em aplicações .NET. Aprenda conceitos e dicas práticas para iniciar seu projeto. e C#
9. INotifyPropertyChanged: A Magia por Trás da Atualização
10. Validação e📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. Conversão de Dados
11. Exemplo Prático📝 Logging com Serilog: Registre Tudo como um Detetive de Bugs!Aprenda a usar Serilog em .NET para registrar logs estruturados, identificar erros e enriquecer informações, transformando seu código num enigma solucionável.: Formulário de Cadastro com Validação
12. Conclusão
O que é Data Binding?🔗
- Data Binding é o mecanismo que permite vincular (ou “amarrar”) os dados do seu código à interface do usuário. Por exemplo, se você tem uma classe com uma propriedade
⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção. chamada
NomeUsuario
, e deseja que essa informação apareça em um rótulo (label) na tela, o Data Binding é quem fará a ponte. Quando o valor da propriedade⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção. mudar, o rótulo na tela também muda, e vice-versa (dependendo do tipo de binding configurado).
De forma simples:
- O Código (objeto, propriedade
⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção.) é a origem dos dados.
- A Interface
📜 Interfaces: Contratos que Garantem a Ordem no Universo OOP!Descubra como as interfaces em C# funcionam como contratos que garantem implementações flexíveis e robustas, facilitando o design e testes de sistemas. (controle visual, como um label
🖌️ XAML Básico: Crie Interfaces sem Código C# (Quase)!Descubra como usar XAML para criar interfaces atrativas em aplicações .NET. Aprenda conceitos e dicas práticas para iniciar seu projeto.) é o destino dos dados.
Como funciona o Data Binding?🔗
O Data Binding depende de duas coisas principais:
1. Origem (Source): quem fornece os dados. Pode ser um objeto simples, uma coleção, ou até um serviço remoto.
2. Destino (Target): geralmente, um elemento de interface📜 Interfaces: Contratos que Garantem a Ordem no Universo OOP!Descubra como as interfaces em C# funcionam como contratos que garantem implementações flexíveis e robustas, facilitando o design e testes de sistemas. que exibe as informações, como um rótulo, caixa de texto ou lista.
Quando configuramos o Data Binding, criamos uma “ligação” entre esses dois pontos. Sob o capô, há um sistema de notificação de mudanças. Se você quiser que a interface seja atualizada automaticamente quando o valor mudar, seu objeto deve sinalizar esta alteração (normalmente implementando interfaces de notificação de alteração de propriedade⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção.).
Tipos de Binding mais Comuns🔗
Em muitos cenários📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades., existem vários modos de binding, mas vamos destacar os mais usados:
1. OneWay (Somente Leitura)
O destino exibe o valor da origem, mas se você mudar esse valor no destino (por exemplo, digitando em uma caixa de texto📝 Strings em C#: Manipule Textos como um Mestre dos Caracteres!Aprenda a dominar os segredos das strings em C# com técnicas de manipulação, concatenação, interpolação e boas práticas, impulsionando sua performance.), a origem não é atualizada.
2. TwoWay (Leitura e📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. Escrita)
Tanto a origem quanto o destino podem atualizar📡 RESTful 101: Princípios que Todo Dev API Precisa Saber!Descubra os fundamentos do REST e boas práticas para criar APIs simples, escaláveis e eficientes. Domine métodos HTTP e status codes com exemplos práticos. um ao outro. É o clássico “quando o usuário digita no campo, o objeto é atualizado e vice-versa”.
3. OneTime (Carga Única)
O destino lê da origem apenas uma vez, normalmente quando📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. a tela é carregada. Se a origem mudar, o destino não atualiza automaticamente.
4. OneWayToSource
A atualização ocorre apenas da UI para a origem. Útil em cenários onde a interface📜 Interfaces: Contratos que Garantem a Ordem no Universo OOP!Descubra como as interfaces em C# funcionam como contratos que garantem implementações flexíveis e robustas, facilitando o design e testes de sistemas. é a fonte primária de dados.
Esses modos ajudam a definir como a sincronização vai ocorrer.
DataContext e Fontes de Dados🔗
Em muitas tecnologias de interface📜 Interfaces: Contratos que Garantem a Ordem no Universo OOP!Descubra como as interfaces em C# funcionam como contratos que garantem implementações flexíveis e robustas, facilitando o design e testes de sistemas. baseadas em .NET, o conceito de DataContext
🔍 LINQ to SQL: Esqueça Queries Escritas à Mão!Aprenda a simplificar consultas SQL com LINQ to SQL usando C#. Descubra benefícios, mapeamento de dados, e práticas essenciais para performance! aparece bastante. Ele indica qual objeto ou fonte de dados a interface
📜 Interfaces: Contratos que Garantem a Ordem no Universo OOP!Descubra como as interfaces em C# funcionam como contratos que garantem implementações flexíveis e robustas, facilitando o design e testes de sistemas. deve “enxergar”. Por exemplo, se você configurar o
DataContext
de uma janela ou página inteira para🔍 LINQ to SQL: Esqueça Queries Escritas à Mão!Aprenda a simplificar consultas SQL com LINQ to SQL usando C#. Descubra benefícios, mapeamento de dados, e práticas essenciais para performance!
🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)Descubra como automatizar repetições em C# utilizando loops for e while com exemplos práticos que evitam erros e otimizam seu código. Aprenda mais! um objeto
ViewModel
, todos os controles dentro dela podem fazer binding às propriedades🎭 MVVM: Separe Regras de Negócio da Interface Graficamente!Descubra como o padrão MVVM separa a interface e a lógica de negócio, facilitando testes e manutenção, com exemplos e dicas práticas para seu projeto.
⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção. desse objeto, sem que você precise repetir a configuração em cada controle.
Num cenário simples, você poderia fazer algo como:
public class Usuario
{
public string NomeUsuario { get; set; }
public int Idade { get; set; }
}
// Em algum ponto do código (por exemplo, no construtor da janela)
var usuario = new Usuario
{
NomeUsuario = "Alice",
Idade = 30
};
this.DataContext = usuario; // 'this' representaria a sua janela ou página
Agora, na interface, os controles podem se vincular às propriedades⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção.
NomeUsuario
e📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades.
Idade
de forma simplificada (dependendo, é claro, da forma de binding que a tecnologia oferece).
Exemplo Prático: Conectando Propriedade a um Elemento de UI🔗
Vamos supor que temos um label🖌️ XAML Básico: Crie Interfaces sem Código C# (Quase)!Descubra como usar XAML para criar interfaces atrativas em aplicações .NET. Aprenda conceitos e dicas práticas para iniciar seu projeto. chamado
lblNome
. Queremos que ele exiba o valor da propriedade⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção.
NomeUsuario
de um objeto do tipo🧠 Variáveis em C#: Onde os Dados Ganham Vida (e Nome!)Descubra como as variáveis em C# funcionam, com exemplos do mundo real, boas práticas de nomeação e dicas para otimizar seu código.
Usuario
. Com C#, você pode fazer:
// Exemplo em código imperativo (sem XAML)
Binding meuBinding = new Binding("NomeUsuario");
lblNome.SetBinding(ContentProperty, meuBinding);
"NomeUsuario"
é a string que indica o nome da propriedade⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção. no objeto de origem.
lblNome.SetBinding(...)
diz ao label para se manter sincronizado com essa propriedade⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção..
- Se
this.DataContext
estiver definido como o objetoUsuario
, então📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades.
lblNome
“sabe” de onde tirar o valor🗂️ Dicionários: Acesse Dados por Chaves como um Mestre dos HashMaps!Aprenda a usar dicionários em C# de modo prático e eficiente. Nosso tutorial mostra criação, acesso e otimização para manipular dados com segurança..
Assim que a propriedade⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção.
NomeUsuario
no objeto Usuario
for modificada (e se esse objeto notificar corretamente a mudança), o texto📝 Strings em C#: Manipule Textos como um Mestre dos Caracteres!Aprenda a dominar os segredos das strings em C# com técnicas de manipulação, concatenação, interpolação e boas práticas, impulsionando sua performance. do label mudará automaticamente.
Binding em Coleções🔗
Além de ligar propriedades⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção. simples, o Data Binding também funciona muito bem com coleções. Se você tiver, por exemplo, uma lista de produtos, pode exibi-la em um elemento de interface
📜 Interfaces: Contratos que Garantem a Ordem no Universo OOP!Descubra como as interfaces em C# funcionam como contratos que garantem implementações flexíveis e robustas, facilitando o design e testes de sistemas. (como um
ListBox
) e cada alteração na coleção (adição🔢 Operadores Aritméticos: Faça Cálculos como uma Calculadora Humana!Aprenda a dominar operadores aritméticos em C# com exemplos práticos, técnicas de cálculo e dicas para evitar erros e maximizar resultados., remoção, etc.) refletirá na tela. Para isso, geralmente se usa uma coleção que emite notificação de alterações, como
ObservableCollection<T>
:
public ObservableCollection<Produto> Produtos { get; set; }
public MainViewModel()
{
Produtos = new ObservableCollection<Produto>()
{
new Produto { Nome = "Lápis", Preco = 1.99 },
new Produto { Nome = "Caderno", Preco = 10.50 }
};
}
Em seguida, basta ligar essa coleção a um controle que aceite exibição de listas📦 List<T>: Dinamismo além dos Arrays!Descubra como utilizar List<T> em C# de forma eficiente. Aprenda a criar, manipular e otimizar listas para diferentes cenários com exemplos práticos.. Quando você chamar algo como
Produtos
, o controle que está fazendo o binding será automaticamente atualizado.🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio..Add(new Produto { ... })
Implementação no WPF: XAML e C#🔗
No WPF, o Data Binding é declarado diretamente no XAML, vinculando propriedades de controles a propriedades⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção. de objetos (ViewModel):
<!-- Window ou UserControl -->
<Window.DataContext>
<local:UsuarioViewModel/>
</Window.DataContext>
<StackPanel>
<TextBox Text="{Binding Usuario.Nome, Mode=TwoWay}"/>
<TextBlock Text="{Binding Usuario.Idade}"/>
</StackPanel>
public class UsuarioViewModel
{
public Usuario Usuario { get; set; } = new Usuario { Nome = "João", Idade = 30 };
}
INotifyPropertyChanged: A Magia por Trás da Atualização🔗
Para🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)Descubra como automatizar repetições em C# utilizando loops for e while com exemplos práticos que evitam erros e otimizam seu código. Aprenda mais! que o binding TwoWay funcione, o objeto de dados precisa notificar a UI sobre mudanças. Isso é feito implementando
INotifyPropertyChanged
:
public class Usuario : INotifyPropertyChanged
{
private string _nome;
public string Nome
{
get => _nome;
set
{
_nome = value;
OnPropertyChanged(nameof(Nome)); // Notifica a UI
}
}
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Validação e Conversão de Dados🔗
Validação com IDataErrorInfo
:
public class Usuario : IDataErrorInfo
{
public string this[string columnName]
{
get => columnName == nameof(Email) && !Email.Contains("@") ? "E-mail inválido" : null;
}
public string Error => null;
}
// No XAML:
<TextBox Text="{Binding Email, ValidatesOnDataErrors=True}" />
Conversor de Dados (ex.: booleano para🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)Descubra como automatizar repetições em C# utilizando loops for e while com exemplos práticos que evitam erros e otimizam seu código. Aprenda mais! visibilidade):
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(...) => throw new NotImplementedException();
}
// Uso:
<CheckBox x:Name="chkMostrar"/>
<TextBlock Visibility="{Binding IsChecked, ElementName=chkMostrar, Converter={StaticResource BoolToVisibility}}"/>
Exemplo Prático: Formulário de Cadastro com Validação🔗
Passo a Passo:
public class CadastroViewModel : INotifyPropertyChanged
{
private Usuario _usuario = new Usuario();
public Usuario Usuario
{
get => _usuario;
set { _usuario = value; OnPropertyChanged(); }
}
// Implementação de INotifyPropertyChanged...
}
<Window ...>
<Window.Resources>
<local:BoolToVisibilityConverter x:Key="BoolToVisibility"/>
</Window.Resources>
<StackPanel>
<TextBox Text="{Binding Usuario.Nome, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="5"/>
<TextBox Text="{Binding Usuario.Email, ValidatesOnDataErrors=True}"
Margin="5"/>
<TextBlock Text="{Binding Usuario.Error}" Foreground="Red"
Visibility="{Binding Usuario.HasErrors, Converter={StaticResource BoolToVisibility}}"/>
<Button Content="Salvar" Command="{Binding SalvarCommand}" Margin="5"/>
</StackPanel>
</Window>
Resultado: Um formulário onde🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio.:
- O botão "Salvar" só é habilitado se todos os campos forem válidos.
- Mensagens de erro
🎲 Desafio: Crie um Sistema de Login com Tratamento de Erros Robusto!Aprenda a criar um sistema de login robusto em C#, com tratamento de erros adequado, validação e segurança para evitar vulnerabilidades. aparecem automaticamente.
- Dados são atualizados em tempo real no objeto
Usuario
.
Erros Comuns e Boas Práticas🔗
Embora o Data Binding seja poderoso, alguns erros🎲 Desafio: Crie um Sistema de Login com Tratamento de Erros Robusto!Aprenda a criar um sistema de login robusto em C#, com tratamento de erros adequado, validação e segurança para evitar vulnerabilidades. são recorrentes:
1. Falta de Notificação de Mudanças
- Se você esquece de implementar interfaces
📜 Interfaces: Contratos que Garantem a Ordem no Universo OOP!Descubra como as interfaces em C# funcionam como contratos que garantem implementações flexíveis e robustas, facilitando o design e testes de sistemas. como
INotifyPropertyChanged
(quando necessário), a interface📜 Interfaces: Contratos que Garantem a Ordem no Universo OOP!Descubra como as interfaces em C# funcionam como contratos que garantem implementações flexíveis e robustas, facilitando o design e testes de sistemas. não atualiza.
- Para propriedades
⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção. simples em alguns ambientes, pode ser preciso disparar eventos de mudança.
- Usar
Binding("NomeDePropriedadeErrado")
vai resultar em bindings silenciosamente quebrados. Sempre confira o nome das propriedades⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção..
3. Binding ao Objeto Errado
- Se o
DataContext
não está configurado ou está configurado para o objeto incorreto, nada vai aparecer na interface🔍 LINQ to SQL: Esqueça Queries Escritas à Mão!Aprenda a simplificar consultas SQL com LINQ to SQL usando C#. Descubra benefícios, mapeamento de dados, e práticas essenciais para performance!
📜 Interfaces: Contratos que Garantem a Ordem no Universo OOP!Descubra como as interfaces em C# funcionam como contratos que garantem implementações flexíveis e robustas, facilitando o design e testes de sistemas..
4. Multi-Threading
- Em aplicações mais complexas, atualizar
📡 RESTful 101: Princípios que Todo Dev API Precisa Saber!Descubra os fundamentos do REST e boas práticas para criar APIs simples, escaláveis e eficientes. Domine métodos HTTP e status codes com exemplos práticos. o objeto de origem em threads diferentes pode exigir mecanismos de sincronização.
- Mantenha o conteúdo de dados (classes
🏗️ Classes vs. Structs: Quando Usar Cada Uma (e Não Quebrar a Cabeça)!Descubra como escolher entre classes e structs em C#. Aprenda sobre alocação de memória, passagem por valor e referência, e performance nesta explicação clara., coleções) o mais coeso possível.
- Sempre que precisar atualizar a UI em tempo real, certifique-se de que suas propriedades
⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção. estão prontas para isso (com notificações de mudança).
- Evite acoplamentos exagerados: cada controle deve saber apenas o mínimo
🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. sobre o objeto que está exibindo.
Conclusão🔗
O Data Binding transforma o desenvolvimento de UI de uma tarefa🤝 GitHub Básico: Versionamento para Iniciantes!Descubra como o GitHub facilita colaboração, versionamento e organização de código com este tutorial prático e essencial para desenvolvedores iniciantes. manual em uma coreografia automática. Dominar essa técnica permite criar aplicações mais limpas, testáveis e fáceis de manter. Com esses fundamentos bem assimilados, você já consegue criar aplicativos cuja interface
📜 Interfaces: Contratos que Garantem a Ordem no Universo OOP!Descubra como as interfaces em C# funcionam como contratos que garantem implementações flexíveis e robustas, facilitando o design e testes de sistemas. se atualiza sozinha conforme as mudanças de dados. É um passo fundamental para desenvolver ferramentas profissionais, aumentar a produtividade e, de quebra, escrever um código mais limpo e organizado. Boa prática de binding e... mãos à obra! 🚀
💡 Sabia? No MAUI, o Data Binding funciona de forma similar ao WPF, mas com algumas otimizações para multiplataforma. Ideal para apps mobile! (Confira nosso artigo dedicado a MAUI!)
Autor: Marcelo V. Souza - Engenheiro de Sistemas e Entusiasta em IoT e Desenvolvimento de Software, com foco em inovação tecnológica.
Referências🔗
- .NET Documentation: learn.microsoft.com/pt-br/dotnet/
- Awesome .NET: github.com/quozd/awesome-dotnet
- C# Language Specification: learn.microsoft.com/pt-br/dotnet/csharp/language-reference/language-specification/
- GitHub: Microsoft/.NET: github.com/dotnet
- Microsoft Learn: C# e .NET: learn.microsoft.com/pt-br/dotnet/csharp/