Skip to content

Commit 3a72883

Browse files
elenapeskovakhamlyukAbadzhevdirkpieterse
authored
Update example with new API (#20)
* update image * update image * update readme * update readme * update readme * Apply suggestions from code review Co-authored-by: Elena Khamlyuk <[email protected]> * Apply suggestions from code review * Apply suggestions from code review Co-authored-by: Abadzhev <[email protected]> * Apply suggestions from code review Co-authored-by: dirkpieterse <[email protected]> --------- Co-authored-by: Elena Khamlyuk <[email protected]> Co-authored-by: Abadzhev <[email protected]> Co-authored-by: dirkpieterse <[email protected]>
1 parent c4e2f48 commit 3a72883

File tree

2 files changed

+144
-120
lines changed

2 files changed

+144
-120
lines changed

Readme.md

Lines changed: 144 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,168 +1,192 @@
1-
<!-- default badges list -->
2-
![](https://img.shields.io/endpoint?url=https://codecentral.devexpress.com/api/v1/VersionRange/227836631/25.1.3%2B)
3-
[![](https://img.shields.io/badge/Open_in_DevExpress_Support_Center-FF7200?style=flat-square&logo=DevExpress&logoColor=white)](https://supportcenter.devexpress.com/ticket/details/T845557)
4-
[![](https://img.shields.io/badge/📖_How_to_use_DevExpress_Examples-e9f6fc?style=flat-square)](https://docs.devexpress.com/GeneralInformation/403183)
5-
[![](https://img.shields.io/badge/💬_Leave_Feedback-feecdd?style=flat-square)](#does-this-example-address-your-development-requirementsobjectives)
6-
<!-- default badges end -->
7-
# How to implement a Theme Switcher in Blazor applications
1+
# Implement a Theme Switcher in Blazor Applications
82

9-
This example demonstrates how to add a Theme Switcher to your application. The switcher in this example is the same as in [DevExpress Blazor Demos](https://demos.devexpress.com/blazor/). It allows users to switch between [DevExpress built-in themes](https://docs.devexpress.com/Blazor/401523/common-concepts/customize-appearance/themes) and external Bootstrap themes (the default theme and [free Bootswatch options](https://bootswatch.com/)).
3+
This example demonstrates how to add a Theme Switcher to your application. Users can switch between DevExpress Fluent and Classic themes and external Bootstrap themes. This example uses the [DxResourceManager.RegisterTheme(ITheme)](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxResourceManager.RegisterTheme(DevExpress.Blazor.ITheme)) method to apply a theme at application startup and the [IThemeChangeService.SetTheme()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.IThemeChangeService.SetTheme(DevExpress.Blazor.ITheme)) method to change the theme at runtime.
104

115

126
![Blazor - Theme Switcher](images/blazor-theme-switcher.png)
137

14-
The example's solution targets .NET 8, but you can also integrate this Theme Switcher in projects that target .NET 6 and .NET 7.
8+
## Configure Available Themes
159

16-
## Add a Theme Switcher to an Application
10+
The theme switcher includes the following themes:
11+
12+
* DevExpress Fluent (Light Blue and Dark Blue)
13+
* DevExpress Classic (Blazing Berry, Blazing Dark, Purple, and Office White)
14+
* [Bootstrap External](https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css)
15+
16+
17+
Create a `Themes.cs` file and configure themes:
1718

18-
Follow the steps below to add a Theme Switcher into your application:
1919

20-
1. Copy this example's [ThemeSwitcher](./CS/switcher/switcher/ThemeSwitcher) folder to your project.
21-
2. In the *_Imports.razor* file, import the `switcher.ThemeSwitcher` namespace and files located in the *ThemeSwitcher* folder:
20+
1. For Classic themes, choose a theme from the built-in DevExpress Blazor [Themes](https://docs.devexpress.com/Blazor/DevExpress.Blazor.Themes) collection:
2221

2322
```cs
24-
@using <YourProjectName>.ThemeSwitcher
25-
@using switcher.ThemeSwitcher
23+
public static readonly ITheme BlazingBerry = Themes.BlazingBerry;
24+
public static readonly ITheme BlazingDark = Themes.BlazingDark;
25+
public static readonly ITheme Purple = Themes.Purple;
26+
public static readonly ITheme OfficeWhite = Themes.OfficeWhite;
2627
```
28+
1. For Fluent themes, call the [Clone()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxThemeBase-1.Clone(System.Action--0-)) method to add theme stylesheets and change theme mode:
2729
28-
3. Copy this example's [switcher-resources](./CS/switcher/switcher/wwwroot/switcher-resources) folder to your application's *wwwroot* folder. The *switcher-resources* folder has the following structure:
30+
```cs
31+
public static readonly ITheme FluentLight = Themes.Fluent.Clone(props => {
32+
props.AddFilePaths("css/theme-fluent.css");
33+
});
34+
public static readonly ITheme FluentDark = Themes.Fluent.Clone(props => {
35+
props.Mode = ThemeMode.Dark;
36+
props.AddFilePaths("css/theme-fluent.css");
37+
});
38+
```
39+
1. For Bootstrap themes, call the [Clone()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxThemeBase-1.Clone(System.Action--0-)) method to add a Bootstrap theme stylesheet. Use the same approach if you want to apply your own stylesheets.
2940
30-
* **css/themes**
31-
Includes nested folders whose names correspond to external Bootstrap themes. Each nested folder stores an external theme's stylesheet (*bootstrap.min.css*). Note that built-in DevExpress themes are added to the application with DevExpress Blazor components and stored separately in the **DevExpress.Blazor.Themes** NuGet package.
41+
```cs
42+
public static readonly ITheme BootstrapDefault = Themes.BootstrapExternal.Clone(props => {
43+
props.Name = "Bootstrap";
44+
props.AddFilePaths("https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css");
45+
props.AddFilePaths("css/theme-bs.css");
46+
});
47+
```
48+
1. Create a list of themes:
3249

33-
* **css/themes.css**
34-
Contains CSS rules used to draw colored squares for each theme in the Theme Switcher.
35-
* **css/theme-switcher.css**
36-
Contains CSS rules that define the Theme Switcher's appearance and behavior.
37-
* **theme-controller.js**
38-
Contains functions that add and remove links to theme stylesheets.
39-
* **theme.svg**
40-
An icon displayed in the Theme Switcher.
41-
42-
4. In the layout file, use the [HttpContextAccessor](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.httpcontextaccessor?view=aspnetcore-8.0) class to obtain the current theme from cookies:
43-
```html
44-
@using Microsoft.AspNetCore.Mvc.ViewFeatures
45-
@inject IFileVersionProvider FileVersionProvider
46-
@inject ThemeService Themes
47-
@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
48-
@{
49-
string? InitialThemeName = HttpContextAccessor.HttpContext?.Request.Cookies["ActiveTheme"];
50-
Themes.SetActiveThemeByName(InitialThemeName);
51-
var bsTheme = Themes.GetBootstrapThemeCssUrl(Themes.ActiveTheme);
52-
var dxTheme = Themes.GetThemeCssUrl(Themes.ActiveTheme);
53-
var hlTheme = Themes.GetHighlightJSThemeCssUrl(Themes.ActiveTheme);
54-
55-
string AppendVersion(string path) => FileVersionProvider.AddFileVersionToPath("/", path);
50+
51+
```cs
52+
public enum MyTheme {
53+
Fluent_Light,
54+
Fluent_Dark,
55+
56+
Blazing_Berry,
57+
Blazing_Dark,
58+
Purple,
59+
Office_White,
60+
61+
Bootstrap
5662
}
5763
```
58-
5. In the `head` section of the layout file, replace a link to a theme stylesheet with the following code:
59-
```html
60-
<head>
61-
@if (!string.IsNullOrEmpty(bsTheme)) {
62-
<link rel="stylesheet" href="@AppendVersion(bsTheme)" bs-theme-link />
63-
}
64-
@if (!string.IsNullOrEmpty(dxTheme)) {
65-
<link rel="stylesheet" href="@AppendVersion(dxTheme)" dx-theme-link />
66-
}
67-
@if (!string.IsNullOrEmpty(hlTheme)) {
68-
<link rel="stylesheet" href="@hlTheme" hl-theme-link />
69-
}
70-
</head>
71-
```
72-
6. Register the Theme Switcher's styles in the `head` section of the layout file:
73-
```html
74-
<head>
75-
<link href="switcher-resources/css/theme-switcher.css" rel="stylesheet" />
76-
<link href="switcher-resources/css/themes.css" rel="stylesheet" />
77-
@* ... *@
78-
</head>
79-
```
80-
7. Add the following `div` element to the `body` section of the layout file:
81-
```html
82-
<body>
83-
<div id="switcher-container" data-permanent></div>
84-
@* ... *@
85-
</body>
64+
65+
## Add a Theme Switcher to an Application
66+
67+
Follow the steps below to add a Theme Switcher to your application:
68+
69+
1. Copy this example's [ThemeSwitcher](./CS/switcher/switcher/Components/ThemeSwitcher) folder to your project.
70+
71+
2. Copy the example's [switcher-resources](./CS/switcher/switcher/wwwroot/switcher-resources) folder to your application's *wwwroot* folder. The *switcher-resources* folder has the following structure:
72+
73+
* **js/cookies-manager.js**
74+
Contains a function that stores the theme in a cookie variable.
75+
* **theme-switcher.css**
76+
Contains CSS rules that define the Theme Switcher's appearance and behavior.
77+
78+
3. Add the following services to your application (copy the corresponding files):
79+
80+
* [ThemeService.cs](./CS/switcher/switcher/Services/ThemesService.cs)
81+
Implements [IThemeChangeService](https://docs.devexpress.com/Blazor/DevExpress.Blazor.IThemeChangeService) to switch themes at runtime and uses the [SetTheme()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.IThemeChangeService.SetTheme(DevExpress.Blazor.ITheme)) method to apply the selected theme.
82+
* [Themes.cs](./CS/switcher/switcher/Services/Themes.cs)
83+
Creates a list of themes for the theme switcher using the built-in DevExpres Blazor [Themes](https://docs.devexpress.com/Blazor/DevExpress.Blazor.Themes) collection (for Classic themes) and the [Clone()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxThemeBase-1.Clone(System.Action--0-)) method for Fluent and Bootstrap themes.
84+
* [CookiesService.cs](./CS/switcher/switcher/Services/CookiesService.cs)
85+
Manages cookies.
86+
87+
2. In the [_Imports.razor](./CS/switcher/switcher/Components/_Imports.razor) file, import `{ProjectName}.Components.ThemeSwitcher` and `{ProjectName}.Services` namespaces:
88+
89+
```cs
90+
@using {ProjectName}.Components.ThemeSwitcher
91+
@using {ProjectName}.Services
8692
```
87-
8. Register `Mvc` and `ThemeService` in the `Program.cs` file:
93+
94+
5. Register `ThemesService` and `CookiesService` in the [Program.cs](./CS/switcher/switcher/Program.cs#L13-L16) file. Ensure that this file also contains `Mvc` and `HttpContextAccessor` services:
95+
8896
```cs
8997
builder.Services.AddMvc();
90-
builder.Services.AddScoped<ThemeService>();
98+
builder.Services.AddHttpContextAccessor();
99+
builder.Services.AddScoped<ThemesService>();
100+
builder.Services.AddTransient<CookiesService>();
91101
```
92-
9. Declare the Theme Switcher component in the *MainLayout.razor* file:
93-
```razor
94-
<ThemeSwitcher />
95-
```
96-
10. *For .NET 6 and .NET 7 applications.* Remove the `@rendermode InteractiveServer` directive from [ThemeSwitcher.razor](./CS/switcher/switcher/ThemeSwitcher/ThemeSwitcher.razor#L2), [ThemeSwitcherContainer.razor](./CS/switcher/switcher/ThemeSwitcher/ThemeSwitcherContainer.razor#L4), and [ThemeSwitcherItem.razor](./CS/switcher/switcher/ThemeSwitcher/ThemeSwitcherItem.razor#L2) files.
97102

98-
## Add Themes to the Theme Switcher
103+
6. Add the following code to the [App.razor](./CS/switcher/switcher/Components/App.razor) file:
99104

100-
Follow the steps below to add an external Bootstrap theme to the Theme Switcher:
105+
* Inject services with the [&#91;Inject&#93; attribute](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.injectattribute):
101106
102-
1. In the **wwwroot/css/themes** folder, create a new folder for this theme. The folder and theme names should match.
107+
```html
108+
@inject IHttpContextAccessor HttpContextAccessor
109+
@inject ThemesService ThemesService
110+
```
111+
112+
* Add script and stylesheet links to the file's `<head>` section and call the [DxResourceManager.RegisterTheme(ITheme)](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxResourceManager.RegisterTheme(DevExpress.Blazor.ITheme)) method to apply a theme on application startup:
103113

104-
2. Add the theme's stylesheet (*bootstrap.min.css*) to the newly created folder.
114+
```html
115+
<head>
116+
@* ... *@
117+
<script src=@AppendVersion("switcher-resources/js/cookies-manager.js")></script>
118+
<link href=@AppendVersion("switcher-resources/theme-switcher.css") rel="stylesheet" />
105119

106-
3. Add the following CSS rule to the *wwwroot/css/themes.css* file:
120+
@DxResourceManager.RegisterTheme(InitialTheme)
121+
@* ... *@
122+
</head>
123+
```
107124

108-
```css
109-
.blazor-themes a.<your-theme-name>:before {
110-
background: <theme-main-color>;
111-
}
112-
```
125+
* Obtain the theme from cookies during component initialization:
113126

114-
4. In *ThemeService.cs*, add the theme name to the **Bootstrap Themes** theme set:
127+
```razor
128+
@code {
129+
private ITheme InitialTheme;
130+
protected override void OnInitialized() {
131+
InitialTheme = ThemesService.GetThemeFromCookies(HttpContextAccessor);
132+
}
133+
}
134+
```
115135

136+
7. Declare the Theme Switcher component in the [MainLayout.razor](./CS/switcher/switcher/Components/Layout/MainLayout.razor#L22) file:
116137

117-
```cs
118-
private static List<ThemeSet> CreateSets(ThemeService config) {
119-
return new List<ThemeSet>() {
120-
new ThemeSet("DevExpress Themes", NEW_BLAZOR_THEMES),
121-
new ThemeSet("Bootstrap Themes", "<your-theme-name>", "default", "default-dark", "cerulean")
122-
};
123-
}
124-
```
138+
```razor
139+
<Drawer>
140+
@* ... *@
141+
<ThemeSwitcher />
142+
@* ... *@
143+
</Drawer>
144+
```
125145

126-
## Remove Themes from the Theme Switcher
146+
## Add Stylesheets to a Theme (Apply Styles to Non-DevExpress UI Elements)
127147

128-
Follow the steps below to remove a built-in DevExpress or external Bootstrap theme from the Theme Switcher:
129148

130-
1. Open *ThemeService.cs* and remove the theme name from the **DevExpress Themes** or **Bootstrap Themes** theme set:
149+
Our DevExpress Blazor themes affect DevExpress components only. To apply theme-specific styles to non-DevExpress elements or the entire application, add external stylesheets to the theme using its `AddFilePaths()` method:
131150

132-
```cs
133-
private static List<ThemeSet> CreateSets(ThemeService config) {
134-
return new List<ThemeSet>() {
135-
new ThemeSet("DevExpress Themes", NEW_BLAZOR_THEMES),
136-
new ThemeSet("Bootstrap Themes", /*"<your-theme-name>"*/, "default", "default-dark", "cerulean")
137-
};
138-
}
139-
```
140151

141-
2. Remove the CSS rule that corresponds to this theme from the *wwwroot/css/themes.css* file.
152+
> Bootstrap themes require external theme-specific stylesheets. Once you register a Bootstrap theme, call the `Clone()` method and add the stylesheet using theme properties.
142153

143-
```css
144-
/* .blazor-themes a.<your-theme-name>:before {
145-
background: <theme-main-color>;
146-
}*/
147-
```
148154

149-
3. *For an external Bootstrap theme.* Delete the *wwwroot/css/themes/\<your-theme-name\>* folder.
155+
```cs
156+
public static readonly ITheme BootstrapDefault = Themes.BootstrapExternal.Clone(props => {
157+
props.Name = "Bootstrap";
158+
// Links a Bootstrap theme stylesheet
159+
props.AddFilePaths("https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css");
160+
// Links a custom stylesheet
161+
props.AddFilePaths("css/theme-bs.css");
162+
});
163+
```
164+
165+
## Change Bootstrap Theme Color Modes
166+
167+
If you want to use dark Bootstrap themes, implement custom logic that applies a `data-bs-theme` attribute to the root <html> element:
168+
169+
* `data-bs-theme="light"` for light themes
170+
* `data-bs-theme="dark"` for dark themes
171+
172+
Refer to the following article for more information: [Color Modes](https://getbootstrap.com/docs/5.3/customize/color-modes/).
150173
151174
## Files to Review
152175

153-
* [ThemeSwitcher](./CS/switcher/switcher/ThemeSwitcher) (folder)
176+
* [ThemeSwitcher](./CS/switcher/switcher/Components/ThemeSwitcher) (folder)
154177
* [switcher-resources](./CS/switcher/switcher/wwwroot/switcher-resources) (folder)
155-
* [App.razor](./CS/switcher/switcher/App.razor)
156-
* [MainLayout.razor](./CS/switcher/switcher/Layout/MainLayout.razor)
178+
* [Services](./CS/switcher/switcher/Services) (folder)
179+
* [App.razor](./CS/switcher/switcher/Components/App.razor)
180+
* [MainLayout.razor](./CS/switcher/switcher/Components/Layout/MainLayout.razor)
157181
* [Program.cs](./CS/switcher/switcher/Program.cs)
158182

159183
## Documentation
160184

161185
* [Themes](https://docs.devexpress.com/Blazor/401523/common-concepts/themes)
162186
<!-- feedback -->
163-
## Does this example address your development requirements/objectives?
164-
165-
[<img src="https://www.devexpress.com/support/examples/i/yes-button.svg"/>](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=blazor-theme-switcher&~~~was_helpful=yes) [<img src="https://www.devexpress.com/support/examples/i/no-button.svg"/>](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=blazor-theme-switcher&~~~was_helpful=no)
166-
187+
## Does this example address your development requirements/objectives?
188+
189+
[<img src="https://www.devexpress.com/support/examples/i/yes-button.svg"/>](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=blazor-theme-switcher&~~~was_helpful=yes) [<img src="https://www.devexpress.com/support/examples/i/no-button.svg"/>](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=blazor-theme-switcher&~~~was_helpful=no)
190+
167191
(you will be redirected to DevExpress.com to submit your response)
168192
<!-- feedback end -->

images/blazor-theme-switcher.png

-13.4 KB
Loading

0 commit comments

Comments
 (0)