This example creates an interactive, multi-tab web interface using DevExpress Blazor Tabs and Context Menu components. It illustrates how end users can create personalized workspaces and multitask effectively.
The MdiTabs custom component is based on the DxTabs control.
Tabs are rendered by iterating over a persisted state collection (see details below). The content within each tab is loaded dynamically using a DynamicComponent. This approach allows for the flexible rendering of different components within the tabs without the need to hardcode them.
<DxTabs ActiveTabIndex=activeTabIndex
ActiveTabIndexChanged="OnActiveTabIndexChanged"
AllowTabReorder="true"
TabReordering="OnTabReordering"
TabClosing="OnTabClosing"
RenderMode="TabsRenderMode.OnDemand">
@for (int i = 0; i < tabsCollection.Count; i++)
{
var tabModel = tabsCollection[i];
<DxTabPage AllowClose="true"
CssClass="@TabCssClass"
VisibleIndex="@tabModel.VisibleIndex"
Visible="@tabModel.Visible"
Text="@tabModel.Text">
<ChildContent>
@if (stateService.TryGetType(tabModel.TabTypeName, out var type))
{
<DynamicComponent @key="@tabModel.Id" Type="type" Parameters="tabModel.Parameters" />
}
else
{
<DynamicComponent @key="@tabModel.Id" Type="@typeof(Unknown)" />
}
</ChildContent>
</DxTabPage>
}
</DxTabs>
The state of the multi-tab interface is managed by the following classes:
MdiTabModel
(MdiTabModel.cs) encapsulates properties associated with each individual tab: unique identifier, visibility, title, and so on.MdiStateModel
(MdiStateModel.cs) contains the list of all tabs (MdiTabModel
) and the index of the active tab.MdiStateService
(MdiStateService.cs) exposes methods for tab state management and maintains tab layout across sessions even after the user closes and reopens the browser. It serializesMdiStateModel
to JSON and saves it to the browser's local storage every time the UI layout changes. The tab state is restored in theMdiTabs
component'sOnInitializedAsync
method.
To ensure that the state model (MdiStateModel
) accurately reflects the live interface, implement event handlers for TabReorder
, TabClosing
, and ActiveTabIndexChanged
. These handlers will listen for user actions and dynamically update the state to match the current tab layout.
Implement a context menu that allows users to manage tabs as needed:
- Close the current tab.
- Close all tabs.
- Close all tabs except for the current one.
- Hide the current tab.
- Hide all tabs.
- Hide all tabs except for the current one.
- Restore hidden tabs.
Create a custom TabsContextMenu
component that contains DxContextMenu and all related actions. Place it inside the MdiTabs
component.
<TabsContextMenu @ref="contextMenu" TabSelector=@($".{TabCssClass}") />
Use the TabSelector
parameter to associate the specific tab with the context menu.
Implement a client-side script TabsContextMenu.razor.js
that handles right-clicks on tabs and performs the following actions:
- Finds the matching elements by their
CssClass
property. - Suppresses the default browser context menu.
- Captures the mouse position and invokes a .NET
[JSInvokable]
method that opens the context menu at the pointer's coordinates.
When a menu item is clicked, the handler calls the corresponding method of MdiStateService
to update the tab state (close, hide, or restore).
MdiTabs.razor
MdiTabModel.cs
MdiStateModel.cs
MdiStateService.cs
TabsContextMenu.razor
TabsContextMenu.razor.js
(you will be redirected to DevExpress.com to submit your response)