Este proyecto agrega soporte para temas en .NET WinForms Aplications. Este proyecto es compatible con temas de uso listos y personalizados y utiliza nuestro proyecto WinForms-Stylable-Controls a controles de estilo que carecen de soporte de estilo.
Primero, instale la herramienta ReportGenerator:
dotnet tool install -g dotnet-reportgenerator-globaltool
A continuación, cree una versión de depuración del proyecto:
dotnet build WinFormsThemes/WinFormsThemes.sln -c Debug
El informe de cobertura de prueba se puede crear 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 stryker.net para pruebas de mutación. Para ejecutar las pruebas de mutación, use:
dotnet tool restore
dotnet stryker
IMPORTANTE: No comience a Stryker en el directorio del proyecto: debe iniciarlo en el Dir de la solución, ¡de lo contrario no se encontrará la configuración!
Para usar este proyecto, debe agregar una referencia a nuestro paquete NUGET ( dotnet add package AssortedDevelopment.WinFormsThemes ) primero.
Nota: Actualmente, este proyecto requiere .NET 6.0 o superior.
A continuación, debe configurar los temas:
var registry = ThemeRegistryHolder . GetBuilder ( ) . Build ( ) ;
var theme = registry . ThemeRegistry . GetTheme ( ) ; Esto se puede colocar en el Program.cs de su aplicación y utiliza la configuración predeterminada para buscar los temas, devolver el registro y usar su tema estándar.
Por fin, debe proporcionar el tema a todos los formularios para ser temáticos y agregar una sola línea en el evento Load :
theme . Apply ( this ) ;Esto aplicará este tema en el formulario dado y todos los niños.
Por supuesto, puede extender esta biblioteca y personalizar el manejo para satisfacer sus necesidades. Aquí hay algunos ejemplos:
Si desea depurar un problema con esta biblioteca, puede habilitar el inicio de sesión en IThemeRegistryBuilder :
ThemeRegistryHolder . GetBuilder ( ) . SetLoggerFactory ( LoggerFactory ) . Build ( ) ; Esto registrará todas las acciones de la biblioteca a la ILoggerFactory dada.
Nota: Cualquier llamada antes de llamar SetLoggerFactory no se verá afectada, por lo que recomendamos llamar SetLoggerFactory lo antes posible.
Cuando no tiene una inyección de dependencia disponible en su proyecto, proporcionamos servicios públicos para que tanto IThemeRegistry como ITheme a nivel mundial estén a nivel mundial:
IThemeRegistry Para el IThemeRegistry , proporcionamos la clase ThemeRegistryHolder que puede usarse para almacenar el registro y recuperarlo más tarde: ThemeRegistryHolder . ThemeRegistry = ThemeRegistryHolder . GetBuilder ( ) . Build ( ) ; Después de esto, puede recuperar el registro desde cualquier lugar de su aplicación utilizando: var registry = ThemeRegistryHolder.ThemeRegistry;
ITheme para el ITheme , el IThemeRegistry proporciona una propiedad Current que se puede utilizar para recuperar el tema actual. Sin embargo, para que esto funcione, debe configurar un selector que define el tema actual: private ITheme SelectCurrentTheme ( IThemeRegistry registry )
{
//logic to select theme here
}
.. .
ThemeRegistryHolder . ThemeRegistry = ThemeRegistryHolder . GetBuilder ( ) . WithCurrentThemeSelector ( SelectCurrentTheme ) . Build ( ) ; Esto le permite usar IThemeRegistry.Current Current para recuperar el tema actual y IThemeRegistry.OnThemeChanged
var mytheme = ThemeRegistryHolder . ThemeRegistry . Current ;
ThemeRegistryHolder . ThemeRegistry . OnThemeChanged += ( sender , args ) =>
{
//logic to handle theme change here
} ; Por defecto, nuestra biblioteca honrará la configuración del sistema operativo con respecto al modo oscuro y un alto contraste al llamar GetTheme . Si desea agregar criterios de selección adicionales o desea darle al usuario una opción para anular esta selección, puede hacerlo fácilmente. En lugar de confiar en la configuración predeterminada en IThemeRegistry.GetTheme() puede establecer IThemeRegistry.Current a cualquier tema que desee al proporcionar un CurrentThemeSelector :
IThemeRegistry registry = ThemeRegistryHolder . GetBuilder ( )
. WithCurrentThemeSelector ( registry => registry . GetTheme ( ) )
. Build ( ) ;
var selectedTheme = registry . CurrentTheme ;Fuera de la caja, hay 2 formas en que puede agregar temas personalizados:
.theme.json almacenado en un directorio themes del Dir de trabajo.CONFIG_THEMING_THEME_Ambas formas usan el mismo formato JSON para la definición del tema (la versión define el formato del archivo). Un ejemplo simple de esto podría 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 obtener la lista completa de la configuración disponible, consulte nuestro esquema JSON aquí.
Si esas 2 maneras no son lo suficientemente flexibles, puede implementar un tema por usted mismo y registrarlo utilizando una fuente de tema personalizada (ver más abajo): la forma preferida es subclase AbstractTheme , ya que solo necesita implementar los colores base y anular opcionalmente los colores extendidos: el diseño de los controles se realiza por la clase base.
La forma más avanzada está implementando la interfaz ITheme . Esto solo admite la infraestructura básica, como las capacidades del tema, pero el estilo está completamente en sus manos.
Las vistas se pueden agregar implementando un IThemeLookup (ver más abajo) o agregándolo directamente al constructor:
ThemeRegistryHolder . GetBuilder ( )
. WithThemes ( )
. AddDefaultThemes ( )
. AddTheme ( new MySuperDarkTheme ( ) )
. FinishThemeList ( )
. Build ( ) ; Si desea agregar otra fuente de tema además de archivos y recursos (por ejemplo, al implementar las implementaciones personalizadas ITheme o AbstractTheme ) o solo desea cambiar la ruta de la carpeta, puede agregar una implementación personalizada IThemeLookup que maneja la búsqueda de los temas disponibles:
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 ;
}
}
}Después de esto, debe registrar esta clase en el constructor:
ThemeRegistryHolder . GetBuilder ( )
. WithThemes ( )
. AddDefaultThemes ( )
. WithLookup ( )
. FinishThemeList ( )
. Build ( ) ;Como no queremos obligarlo a usar una biblioteca de control de WinForms específica, actualmente solo admitimos el estilo de controles y controles estándar de nuestro proyecto WinForms-Stylable-Controls. Como entendemos, es posible que también desee diseñar otros controles, admitimos agregar complementos especializados para manejar el estilo de un tipo específico de control. Para hacer esto, debe 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 fin, solo necesita registrarlo para el tipo correcto:
ThemeRegistryHolder . GetBuilder ( )
. AddThemePlugin ( new MyCustomControlThemePlugin ( ) )
. Build ( ) ;Nota: Actualmente, solo admitemos tipos registrados directamente. ¡Las subclases no se diseñarán automáticamente!
Vea la guía de contribución para obtener más información.