ABP Framework version: v7.2.3
UI Type: Blazor Server
Database System: EF Core
Tiered (for MVC) or Auth Server Separated (for Angular): yes
Exception message and full stack trace:
Steps to reproduce the issue: seems to be related to resource release.
Hello I am using LeptonXTheme UI. I want to be able to see which pages have been opened like the picture above. Display all open tabs at the top and click on the tab above to achieve the effect of switching pages. This is what I have here. A usage habit, does LeptonXTheme UI support this function? In addition, every time I open the page and return to the previous page, the page status will not be retained. Is it possible to maintain the page status like vue keep-alive or do A short-lived storage; now I cannot use LeptonXTheme UI to achieve the above functions. Can you give me some methods or suggestions to achieve these functions?
42 Answer(s)
-
0
Hi,
Here is the code, But there is a serious problem when deleting the tab, which may be related to
blazor.zone. There is nothing I can do. so, I don't recommend you to useblazor.zone<BootstrapBlazor.Components.Tab @ref="_tabComponent" class="mt-3" ShowClose="true" OnClickTabItemAsync="OnSelectedTabChanged" OnCloseTabItemAsync="ClosePage"> @foreach (var tab in RouteDataList) { <BootstrapBlazor.Components.TabItem Text="@tab.Title"> <ContentTabToolbar RouteData="tab"></ContentTabToolbar> @tab.Body </BootstrapBlazor.Components.TabItem> } </BootstrapBlazor.Components.Tab> @code { private BootstrapBlazor.Components.Tab _tabComponent; [Inject] NavigationManager NavigationManager { get; set; } [Inject] PageHeaderService PageHeaderService { get; set; } [Inject] IMenuManager MenuManager { get; set; } [CascadingParameter(Name = "RouteData")] RouteData? RouteData { get; set; } List<ContentTabRouteData> RouteDataList { get; set; } = new(); [Parameter] public RenderFragment Body { get; set; } string? CurrentUrl { get; set; } ApplicationMenu? ApplicationMenu { get; set; } protected override async Task OnInitializedAsync() { ApplicationMenu = await MenuManager.GetMainMenuAsync(); PageHeaderService.PageHeaderDataChanged += OnPageHeaderDataChanged; NavigationManager.LocationChanged += OnLocationChanged; } protected override void OnAfterRender(bool firstRender) { if (firstRender) { OnLocationChanged(this, new LocationChangedEventArgs(NavigationManager.Uri, false)); } base.OnAfterRender(firstRender); } private async void OnPageHeaderDataChanged(object? sender, PageHeaderData? e) { if (e == null) { return; } var route = RouteDataList.FirstOrDefault(x => x.PageType == e.Type); route?.SetPageLayout(e.Title, e.BreadcrumbItems, e.PageToolbarItems); await InvokeAsync(StateHasChanged); } private async Task OnSelectedTabChanged(BootstrapBlazor.Components.TabItem tabItem) { var route = RouteDataList.FirstOrDefault(x => x.Title == tabItem.Text); if (route != null) { CurrentUrl = route.Url; var data = PageHeaderService.GetPageHeaderData(route.PageType); if (data != null) { route.SetPageLayout(data.Title, data.BreadcrumbItems, data.PageToolbarItems); } _tabComponent.ActiveTab(tabItem); NavigationManager.NavigateTo(route.Url); } await InvokeAsync(StateHasChanged); } private RenderFragment GenerateBody(ContentTabRouteData routeData) { return builder => { builder.OpenComponent(0, routeData.PageType); foreach (var routeValue in routeData.RouteValues) { builder.AddAttribute(1, routeValue.Key, routeValue.Value); } builder.CloseComponent(); }; } private async Task<bool> ClosePage(TabItem tabItem) { var routeData = GetRouteData(tabItem); if (routeData == null) { return true; } RouteDataList.Remove(routeData); await _tabComponent.RemoveTab(tabItem); var activeTab = _tabComponent.GetActiveTab(); if (activeTab != null) { await OnSelectedTabChanged(activeTab); } return false; } private ContentTabRouteData? GetRouteData(TabItem? tabItem) { return tabItem == null ? null : RouteDataList.FirstOrDefault(x => x.Title == tabItem.Text); } private void OnLocationChanged(object? sender, LocationChangedEventArgs e) { if (RouteData == null || CurrentUrl == e.Location) { return; } var contentTabRouteData = new ContentTabRouteData { PageType = RouteData.PageType, RouteValues = new Dictionary<string, object>(RouteData.RouteValues), TabName = RouteData.PageType.Name.ToLower(), Url = e.Location, Title = TryGetTitle(ApplicationMenu.Items, e.Location) }; contentTabRouteData.Body = GenerateBody(contentTabRouteData); RouteDataList.AddIfNotContains(x => x.PageType == RouteData.PageType, () => contentTabRouteData); StateHasChanged(); OnSelectedTabChanged(_tabComponent.Items.First(x => x.Text == contentTabRouteData.Title)); } protected override void Dispose(bool disposing) { PageHeaderService.PageHeaderDataChanged -= OnPageHeaderDataChanged; NavigationManager.LocationChanged -= OnLocationChanged; base.Dispose(disposing); } private string? TryGetTitle(ApplicationMenuItemList items, string url) { foreach (var item in items) { if (item.Items.Any()) { var result = TryGetTitle(item.Items, url); if (result != null) { return result; } continue; } if (item.Url.IsNullOrWhiteSpace()) { continue; } if (url.EndsWith(item.Url!.Replace("~/", ""))) { return item.DisplayName; } } // you can custom here return null; } }Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
You can consider https://mudblazor.com/components/tabs#scrolling-tabs or wait for Blazorise implements this function
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Here is the code,
But there is a serious problem when deleting the tab, which may be related toblazor.zone. There is nothing I can do. so, I don't recommend you to useblazor.zone<BootstrapBlazor.Components.Tab @ref="_tabComponent" class="mt-3" ShowClose="true" OnClickTabItemAsync="OnSelectedTabChanged" OnCloseTabItemAsync="ClosePage"> @foreach (var tab in RouteDataList) { <BootstrapBlazor.Components.TabItem Text="@tab.Title"> <ContentTabToolbar RouteData="tab"></ContentTabToolbar> @tab.Body </BootstrapBlazor.Components.TabItem> } </BootstrapBlazor.Components.Tab> @code { private BootstrapBlazor.Components.Tab _tabComponent; [Inject] NavigationManager NavigationManager { get; set; } [Inject] PageHeaderService PageHeaderService { get; set; } [Inject] IMenuManager MenuManager { get; set; } [CascadingParameter(Name = "RouteData")] RouteData? RouteData { get; set; } List<ContentTabRouteData> RouteDataList { get; set; } = new(); [Parameter] public RenderFragment Body { get; set; } string? CurrentUrl { get; set; } ApplicationMenu? ApplicationMenu { get; set; } protected override async Task OnInitializedAsync() { ApplicationMenu = await MenuManager.GetMainMenuAsync(); PageHeaderService.PageHeaderDataChanged += OnPageHeaderDataChanged; NavigationManager.LocationChanged += OnLocationChanged; } protected override void OnAfterRender(bool firstRender) { if (firstRender) { OnLocationChanged(this, new LocationChangedEventArgs(NavigationManager.Uri, false)); } base.OnAfterRender(firstRender); } private async void OnPageHeaderDataChanged(object? sender, PageHeaderData? e) { if (e == null) { return; } var route = RouteDataList.FirstOrDefault(x => x.PageType == e.Type); route?.SetPageLayout(e.Title, e.BreadcrumbItems, e.PageToolbarItems); await InvokeAsync(StateHasChanged); } private async Task OnSelectedTabChanged(BootstrapBlazor.Components.TabItem tabItem) { var route = RouteDataList.FirstOrDefault(x => x.Title == tabItem.Text); if (route != null) { CurrentUrl = route.Url; var data = PageHeaderService.GetPageHeaderData(route.PageType); if (data != null) { route.SetPageLayout(data.Title, data.BreadcrumbItems, data.PageToolbarItems); } _tabComponent.ActiveTab(tabItem); NavigationManager.NavigateTo(route.Url); } await InvokeAsync(StateHasChanged); } private RenderFragment GenerateBody(ContentTabRouteData routeData) { return builder => { builder.OpenComponent(0, routeData.PageType); foreach (var routeValue in routeData.RouteValues) { builder.AddAttribute(1, routeValue.Key, routeValue.Value); } builder.CloseComponent(); }; } private async Task<bool> ClosePage(TabItem tabItem) { var routeData = GetRouteData(tabItem); if (routeData == null) { return true; } RouteDataList.Remove(routeData); await _tabComponent.RemoveTab(tabItem); var activeTab = _tabComponent.GetActiveTab(); if (activeTab != null) { await OnSelectedTabChanged(activeTab); } return false; } private ContentTabRouteData? GetRouteData(TabItem? tabItem) { return tabItem == null ? null : RouteDataList.FirstOrDefault(x => x.Title == tabItem.Text); } private void OnLocationChanged(object? sender, LocationChangedEventArgs e) { if (RouteData == null || CurrentUrl == e.Location) { return; } var contentTabRouteData = new ContentTabRouteData { PageType = RouteData.PageType, RouteValues = new Dictionary<string, object>(RouteData.RouteValues), TabName = RouteData.PageType.Name.ToLower(), Url = e.Location, Title = TryGetTitle(ApplicationMenu.Items, e.Location) }; contentTabRouteData.Body = GenerateBody(contentTabRouteData); RouteDataList.AddIfNotContains(x => x.PageType == RouteData.PageType, () => contentTabRouteData); StateHasChanged(); OnSelectedTabChanged(_tabComponent.Items.First(x => x.Text == contentTabRouteData.Title)); } protected override void Dispose(bool disposing) { PageHeaderService.PageHeaderDataChanged -= OnPageHeaderDataChanged; NavigationManager.LocationChanged -= OnLocationChanged; base.Dispose(disposing); } private string? TryGetTitle(ApplicationMenuItemList items, string url) { foreach (var item in items) { if (item.Items.Any()) { var result = TryGetTitle(item.Items, url); if (result != null) { return result; } continue; } if (item.Url.IsNullOrWhiteSpace()) { continue; } if (url.EndsWith(item.Url!.Replace("~/", ""))) { return item.DisplayName; } } // you can custom here return null; } }Hi.What's the problem with closing it?
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
You can give it a try
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
-
0
Clicking the close button will trigger the SelectedTabChanged method of Tabs
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
This may be the limitation of blazorise and blazor (I'm not sure)
Add custom
classandstopPropagation: The page will flash, but it works.<Tab Name="@tab.TabName" Class="keep-tab-active"> @tab.Title <CloseButton @onclick:stopPropagation="true" Clicked="() => ClosePage(tab)"/> </Tab> .... <TabPanel Name="@route.TabName" Class="keep-panel-active" > ....Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
This may be the limitation of blazorise and blazor (I'm not sure)
Add custom
classandstopPropagation: The page will flash, but it works.<Tab Name="@tab.TabName" Class="keep-tab-active"> @tab.Title <CloseButton @onclick:stopPropagation="true" Clicked="() => ClosePage(tab)"/> </Tab> .... <TabPanel Name="@route.TabName" Class="keep-panel-active" > ....Hi,This flash will clear all input boxes and other conditions,It's like refreshing
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Yes, but I have no idea about this now.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Yes, but I have no idea about this now.
Sometimes clicking the close button won't refresh, it's really weird
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Yes, it's weird
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
-
0
Hi,
Here is the code: https://github.com/abpframework/abp/blob/956706eb62dba926ecd8876a9ba4b490088b8259/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor#L16-L39
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Yes, but I have no idea about this now.
It is related to Blazor's comparison algorithm. @key specifies the key used by the diffing algorithm to retain the elements in the set. I have solved this problem, thank you.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Can you share your solution, it might help others, thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Can you share your solution, it might help others, thanks
Sure.Set key for TabPanel in foreach
<Tabs Class="custom-nav-tabs" SelectedTab="@selectedTab" SelectedTabChanged="@OnSelectedTabChanged"> <Items> @foreach (var tab in RouteDataList) { <Tab Class="tab keep-tab-active" Name="@tab.TabName"> <Span Class="tab-span">@tab.Title</Span> <Button @onclick:stopPropagation="true" Clicked="()=>ClosePage(tab)" Class="close-button">×</Button> </Tab> } </Items> <Content> @foreach (var route in RouteDataList) { <TabPanel @key="route.Url" Class="keep-panel-active" Name="@route.TabName"> <ContentTabToolbar RouteData="route"></ContentTabToolbar> @route.Body </TabPanel> } </Content> </Tabs>Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)


