Este projeto adiciona suporte para temas nos aplicativos .NET WinForms. Este projeto suporta temas prontos para uso e personalizados e usa nosso projeto WinForms-Styable-Controls para controles de estilo que não têm suporte de estilo.
Primeiro, instale a ferramenta ReportGenerator:
dotnet tool install -g dotnet-reportgenerator-globaltool
Em seguida, construa uma versão de depuração do projeto:
dotnet build WinFormsThemes/WinFormsThemes.sln -c Debug
O relatório de cobertura do teste pode ser criado usando:
rmdir /s /q WinFormsThemesTestProjectTestResults
dotnet test WinFormsThemes/TestProject --no-build --verbosity normal --collect:"XPlat Code Coverage"
reportgenerator -reports:WinFormsThemesTestProjectTestResults*coverage.cobertura.xml -targetdir:WinFormsThemesTestProjectTestResultshtml -reporttypes:Html -sourcedirs:WinFormsThemesWinFormsThemes
start "" WinFormsThemesTestProjectTestResultshtmlindex.html
Usamos o stryker.net para testes de mutação. Para executar os testes de mutação, use:
dotnet tool restore
dotnet stryker
IMPORTANTE: Não comece a Stryker no diretório do projeto - você precisa iniciá -lo no diretor da solução, caso contrário, a configuração não será encontrada!
Para usar este projeto, você precisa adicionar uma referência ao nosso pacote NUGET ( dotnet add package AssortedDevelopment.WinFormsThemes ) primeiro.
Nota: Atualmente, este projeto requer .NET 6.0 ou superior.
Em seguida, você precisa configurar os temas:
var registry = ThemeRegistryHolder . GetBuilder ( ) . Build ( ) ;
var theme = registry . ThemeRegistry . GetTheme ( ) ; Isso pode, por exemplo, ser colocado no Program.cs do seu aplicativo e usa as configurações padrão para procurar os temas, retornar o registro e usar seu tema padrão.
Por fim, você precisa fornecer o tema a todos os formulários para ter o tema e adicionar uma única linha no evento Load :
theme . Apply ( this ) ;Isso aplicará esse tema no formulário dado e em todas as crianças.
Obviamente, você pode estender esta biblioteca e personalizar o manuseio para atender às suas necessidades. Aqui estão alguns exemplos:
Se você deseja depurar um problema com esta biblioteca, pode ativar o registro no IThemeRegistryBuilder :
ThemeRegistryHolder . GetBuilder ( ) . SetLoggerFactory ( LoggerFactory ) . Build ( ) ; Isso registrará todas as ações da biblioteca ao ILoggerFactory fornecido.
NOTA: Quaisquer chamadas antes de chamar SetLoggerFactory não serão afetadas, portanto, aconselhamos a chamar SetLoggerFactory o mais cedo possível.
Quando você não tem uma injeção de dependência disponível em seu projeto, fornecemos serviços públicos para tornar IThemeRegistry e ITheme disponível globalmente:
IThemeRegistry para o IThemeRegistry , fornecemos a classe ThemeRegistryHolder , que pode ser usada para armazenar o registro e recuperá -la mais tarde: ThemeRegistryHolder . ThemeRegistry = ThemeRegistryHolder . GetBuilder ( ) . Build ( ) ; Depois disso, você pode recuperar o registro de qualquer lugar do seu aplicativo usando: var registry = ThemeRegistryHolder.ThemeRegistry;
ITheme , o IThemeRegistry fornece uma propriedade Current que pode ITheme usada para recuperar o tema atual. Para que isso funcione, você precisa configurar um seletor que define o tema atual: private ITheme SelectCurrentTheme ( IThemeRegistry registry )
{
//logic to select theme here
}
.. .
ThemeRegistryHolder . ThemeRegistry = ThemeRegistryHolder . GetBuilder ( ) . WithCurrentThemeSelector ( SelectCurrentTheme ) . Build ( ) ; Isso permite que você use IThemeRegistry.Current para recuperar o tema atual e IThemeRegistry.OnThemeChanged para ser notificado de mudanças:
var mytheme = ThemeRegistryHolder . ThemeRegistry . Current ;
ThemeRegistryHolder . ThemeRegistry . OnThemeChanged += ( sender , args ) =>
{
//logic to handle theme change here
} ; Por padrão, nossa biblioteca homenageará as configurações do sistema operacional em relação ao modo escuro e alto contraste ao ligar GetTheme . Se você deseja adicionar critérios de seleção adicionais ou deseja dar ao usuário a opção de substituir esta seleção, você pode fazer isso com facilidade. Em vez de confiar nas configurações padrão no IThemeRegistry.GetTheme() você pode definir CurrentThemeSelector IThemeRegistry.Current .
IThemeRegistry registry = ThemeRegistryHolder . GetBuilder ( )
. WithCurrentThemeSelector ( registry => registry . GetTheme ( ) )
. Build ( ) ;
var selectedTheme = registry . CurrentTheme ;Fora da caixa, existem 2 maneiras pelas quais você pode adicionar temas personalizados:
.theme.json armazenado em um diretório themes do diretor que trabalha.CONFIG_THEMING_THEME_Ambas as maneiras usam o mesmo formato JSON para a definição do tema (a versão define o formato do arquivo). Um exemplo simples disso pode ser:
{
"name" : " theme-name " ,
"capabilities" : [ " DarkMode " , " HighContrast " ],
"version" : 3 ,
"variables" : {
"backColor" : " #082a56 " ,
"foreColor" : " #082a57 "
},
"colors" : {
"backColor" : " backColor " ,
"foreColor" : " foreColor " ,
"controls" : {
"backColor" : " backColor " ,
"foreColor" : " foreColor "
}
}
}Para obter a lista completa das configurações disponíveis, verifique nosso esquema JSON aqui.
Se essas duas maneiras não forem flexíveis o suficiente, você poderá implementar um tema sozinho e registrá -lo usando uma fonte de tema personalizada (veja abaixo): a maneira preferida é subclasse AbstractTheme , pois você só precisa implementar as cores base e opcionalmente as cores estendidas - modelar os controles é feita pela classe base.
A maneira mais avançada é implementar a interface ITheme . Isso suporta apenas a infraestrutura básica, como os recursos temáticos, mas o estilo está completamente em suas mãos.
As visualizações podem ser adicionadas implementando um IThemeLookup (veja abaixo) ou adicionando -o diretamente ao construtor:
ThemeRegistryHolder . GetBuilder ( )
. WithThemes ( )
. AddDefaultThemes ( )
. AddTheme ( new MySuperDarkTheme ( ) )
. FinishThemeList ( )
. Build ( ) ; Se você deseja adicionar outra fonte de tema, além de arquivos e recursos (por exemplo, ao implementar implementações ITheme ou AbstractTheme ) ou que você deseja alterar o caminho da pasta, pode adicionar uma implementação IThemeLookup que lida com a pesquisa de temas disponíveis:
internal class MyThemeLookup : IThemeLookup
{
public int Order => 999 ; //highest order wins when 2 lookups return the same theme name
public List < ITheme > Lookup ( )
{
List < ITheme > results = new List < ITheme > ( ) ;
//implement search for themes here
return results ;
}
}
}Depois disso, você precisa registrar esta aula no construtor:
ThemeRegistryHolder . GetBuilder ( )
. WithThemes ( )
. AddDefaultThemes ( )
. WithLookup ( )
. FinishThemeList ( )
. Build ( ) ;Como não queremos forçá-lo a usar uma biblioteca de controle WinForms específica, atualmente suportamos apenas o estilo de controles e controles padrão do nosso projeto WinForms-Stylable-Controls. Como entendemos, você também pode querer estilizar outros controles, apoiamos a adição de plugins especializados para lidar com o estilo de um tipo específico de controle. Para fazer isso, você precisa implementar ``:
internal class MyCustomControlThemePlugin : AbstractThemePlugin < MyCustomControl >
{
protected override void ApplyPlugin ( MyCustomControl mcc , AbstractTheme theme )
{
//style control based on the colors available in the Theme
}
}Por fim, você só precisa registrá -lo para o tipo correto:
ThemeRegistryHolder . GetBuilder ( )
. AddThemePlugin ( new MyCustomControlThemePlugin ( ) )
. Build ( ) ;Nota: Atualmente, suportamos apenas tipos registrados diretamente. As subclasses não serão estilizadas automaticamente!
Veja o guia contribuinte para obter mais informações.