Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion CS/DxBlazorApplication1/Components/Layout/MainLayout.razor
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
private RenderFragment drawerHeader => @<div class="navigation-drawer-header">
<img class="logo" src="images/logo.svg" alt="DevExpress logo" />
<NavLink href="@UrlGenerator.GetUrl(new Uri(NavigationManager.Uri).LocalPath, !ToggledSidebar)">
<DxButton RenderStyle="@ButtonRenderStyle.Light" RenderStyleMode="@ButtonRenderStyleMode.Text" CssClass="menu-button-nav" IconCssClass="@(ToggledSidebar ? "icon icon-close" : "icon icon-menu")"></DxButton>
</NavLink>
</div>;

Expand Down
2 changes: 1 addition & 1 deletion CS/DxBlazorApplication1/Components/Layout/NavMenu.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<Items>
<DxMenuItem Name="Counter" Text="Counter" CssClass="menu-item" IconCssClass="icon counter-icon"></DxMenuItem>
<DxMenuItem Name="Weather" Text="Weather" CssClass="menu-item" IconCssClass="icon weather-icon"></DxMenuItem>
<DxMenuItem Name="Forms" Text="Forms" CssClass="menu-item" IconCssClass="icon weather-icon"></DxMenuItem>
<DxMenuItem Name="Form" Text="Form" CssClass="menu-item" IconCssClass="icon form-icon"></DxMenuItem>
</Items>
</DxMenu>
</div>
Expand Down
4 changes: 4 additions & 0 deletions CS/DxBlazorApplication1/Components/Layout/NavMenu.razor.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
background-image: url("images/weather.svg");
}

::deep .form-icon {
background-image: url("images/form.svg");
}

::deep .counter-icon {
background-image: url("images/counter.svg");
}
Expand Down
1 change: 0 additions & 1 deletion CS/DxBlazorApplication1/Components/Pages/Counter.razor
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
@page "/counter"
@rendermode InteractiveServer
<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@page "/forms"
@page "/form"

<style>
.my-form{
Expand All @@ -11,16 +11,17 @@
<DxTextBox></DxTextBox>
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Age">
<DxSpinEdit T="int"></DxSpinEdit>
</DxFormLayoutItem>
<DxFormLayoutItem Caption="DOB">
<DxDateEdit T="DateTime"></DxDateEdit>
<DxSpinEdit T="int" MinValue="0"></DxSpinEdit>
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Hobbies">
<DxTagBox TData="string" TValue="string"
Data="@(new List<string>(){"Swimming", "Hiking", "Chess"})"></DxTagBox>
</DxFormLayoutItem>
<DxFormLayoutItem ColSpanMd="12" Caption="Photo">
<DxFileInput></DxFileInput>
<DxFormLayoutItem BeginRow="true">
<DxFileInput SelectButtonText="Add a Photo"></DxFileInput>
</DxFormLayoutItem>
</DxFormLayout>

@code {
DateTime Today = DateTime.Today;
}
16 changes: 12 additions & 4 deletions CS/DxBlazorApplication1/Components/Pages/Index.razor
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
@inject IJSRuntime JS
@inject MDIStateHelper StateHelper

<PageTitle>Multi-Tab Interface</PageTitle>

<div @ref=divContainer>
<DxTabs @ref=tabs
@bind-ActiveTabIndex=activeTabIndex
Expand All @@ -12,13 +14,19 @@
TabClosing="OnTabClosing"
RenderMode="TabsRenderMode.AllTabs">
<DxTabPage CssClass="counter-tab" AllowClose="true" VisibleIndex="@collection.GetVisibleIndexByTabText("Counter")" Visible="@collection.GetVisibleByTabText("Counter")" Text="Counter">
<Counter></Counter>
<div class="tab-body">
<Counter />
</div>
</DxTabPage>
<DxTabPage CssClass="weather-tab" AllowClose="true" VisibleIndex="@collection.GetVisibleIndexByTabText("Weather")" Visible="@collection.GetVisibleByTabText("Weather")" Text="Weather">
<Weather></Weather>
<div class="tab-body">
<Weather />
</div>
</DxTabPage>
<DxTabPage CssClass="forms-tab" AllowClose="true" VisibleIndex="@collection.GetVisibleIndexByTabText("Forms")" Visible="@collection.GetVisibleByTabText("Forms")" Text="Forms">
<Forms></Forms>
<DxTabPage CssClass="form-tab" AllowClose="true" VisibleIndex="@collection.GetVisibleIndexByTabText("Form")" Visible="@collection.GetVisibleByTabText("Form")" Text="Form">
<div class="tab-body">
<Form />
</div>
</DxTabPage>
</DxTabs>
</div>
Expand Down
6 changes: 5 additions & 1 deletion CS/DxBlazorApplication1/Components/Pages/Index.razor.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
::deep .welcome-gridlayout {
.tab-body {
padding: 20px 16px;
}

::deep .welcome-gridlayout {
margin: auto;
width: auto;
height: auto;
Expand Down
1 change: 0 additions & 1 deletion CS/DxBlazorApplication1/Components/Pages/Weather.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
@rendermode InteractiveServer
@inject WeatherForecastService ForecastService

<PageTitle>Weather</PageTitle>
<h1>Weather</h1>

@if (forecasts == null)
Expand Down
3 changes: 3 additions & 0 deletions CS/DxBlazorApplication1/wwwroot/images/form.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
89 changes: 75 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,95 @@
<!-- default badges list -->
![](https://img.shields.io/endpoint?url=https://codecentral.devexpress.com/api/v1/VersionRange/955986368/24.2.1%2B)
[![](https://img.shields.io/badge/Open_in_DevExpress_Support_Center-FF7200?style=flat-square&logo=DevExpress&logoColor=white)](https://supportcenter.devexpress.com/ticket/details/T1288385)
[![](https://img.shields.io/badge/📖_How_to_use_DevExpress_Examples-e9f6fc?style=flat-square)](https://docs.devexpress.com/GeneralInformation/403183)
[![](https://img.shields.io/badge/💬_Leave_Feedback-feecdd?style=flat-square)](#does-this-example-address-your-development-requirementsobjectives)
<!-- default badges end -->
# Product/Platform - Task
# Blazor Tabs - Create a Dynamic Tabbed Interface

This is the repository template for creating new examples. Describe the solved task here.
The example demonstrates how to create an interactive multi-tab web interface with DevExpress Blazor [Tabs](https://docs.devexpress.com/Blazor/405074/components/layout/tabs) and [Context Menu](https://docs.devexpress.com/Blazor/405060/components/navigation-controls/context-menu) components.

Put a screenshot that illustrates the result here.
![Multi-Tab UI](images/blazor-tabbed-ui.png)

Then, add implementation details (steps, code snippets, and other technical information in a free form), or add a link to an existing document with implementation details.
It showcases core features that help end users build their personalized workspaces and multitask effectively.

### Organize Content Into Tabs

Place [DxTabs](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxTabs) container on the page (_Components/Pages/Index.razor_) and add a [DxTabPage](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxTabPage) for each tab.

Insert your custom Blazor components or content directly into each DxTabPage.

```razor
<DxTabs @ref=tabs
@bind-ActiveTabIndex=activeTabIndex
AllowTabReorder="true"
TabReordering="OnTabReordering"
TabClosing="OnTabClosing"
RenderMode="TabsRenderMode.AllTabs">
<DxTabPage CssClass="counter-tab"
AllowClose="true"
VisibleIndex="@collection.GetVisibleIndexByTabText("Counter")"
Visible="@collection.GetVisibleByTabText("Counter")"
Text="Counter">
<div class="tab-body">
<Counter />
</div>
</DxTabPage>
```

The CssClass property of a tab page serves as a unique identifier, allowing client-side scripts to interact with specific tabs.

### Persist Tab State

Implement a custom **MDITab** class to encapsulate specific properties of each individual tab. **MDITabCollection** will control visibility, display order, and titles of all tabs. The title links an underlying object to the visual tab representation in the UI.

Bind these properties to the visual tab elements in the UI. To ensure the MDITabCollection accurately reflects the live interface, implement event handlers for TabReorder and TabClosing. These handlers will listen for user actions and dynamically update the collection to match the current tab state.

To maintain the tab layout across sessions, serialize the collection to JSON and save it to the browser's local storage with **MDIStateHelper** class every time the UI layout changes. It maintains the tab visibility and order even after the user closes and reopens the browser. Tab state is restored in the OnAfterRenderAsync event handler.

### Add Context Menu to Tabs

Create a context menu that allows users to manage tabs:

- Close the current tab.
- Close all tabs.
- Close all tabs except for the current one.
- Restore closed tabs.

Place [DxContextMenu](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxContextMenu) on the page (_Components/Pages/Index.razor_) and add a [DxContextMenuItem](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxContextMenuItem) for each menu action.

```razor
<DxContextMenu @ref=menu>
<Items>
<DxContextMenuItem Click="CloseTab" Text="Close"></DxContextMenuItem>
<DxContextMenuItem Click="CloseAllTabs" Text="Close All Tabs"></DxContextMenuItem>
<DxContextMenuItem Click="CloseOtherTabs" Text="Close Other Tabs"></DxContextMenuItem>
<DxContextMenuItem Click="RestoreAllTabs" Text="Restore Closed Tabs"></DxContextMenuItem>
</Items>
</DxContextMenu>
```

Implement a client-side script (_wwwroot/js/mdi.js_) to handle right-clicks on specific tabs, identified by their CssClass property. This script should prevent the default browser context menu. Capture the mouse position, and invoke a .NET [JSInvokable] method.

## Files to Review

- link.cs (VB: link.vb)
- link.js
- ...
- Index.razor
- NavMenu.razor
- MainLayout.razor
- MDITab.cs
- MDITabCollection.cs
- MDIStateHelper.cs
- mdi.js

## Documentation

- link
- link
- ...
- [DxTabs Class](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxTabs)
- [DxTabPage Class](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxTabPage)
- [DxContextMenu Class](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxContextMenu)
- [DxContextMenuItem Class](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxContextMenuItem)

## More Examples

- link
- link
- ...
- [Form Layout for Blazor - Tabbed Wizard](https://github.com/DevExpress-Examples/Form-Layout-for-Blazor-Tabbed-Wizard)

<!-- feedback -->
## Does this example address your development requirements/objectives?

Expand Down
Binary file added images/blazor-tabbed-ui.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading