Ticket T1279903
Visible to All Users

XAF Blazor : CreateListView in TabbedMDI from external Razor Component

created 3 days ago (modified 2 days ago)

Hello,

I'm intercepting the click on a button in an external Razor component that I'm displaying using a DashboardView and I'd like to load a listview when I click on that button and display it in a new tab of the TabbedMDI.

I've managed to display the listview in a popupWindow, but I need to display it in a tab in the main window.
I'd also like to be able to select the navigation item corresponding to this listview.

Here's the Handle method:

C#
private void HandleItemClick(Type objectType) { ListView dlView = BlazorApplication.CreateListView(objectType, true); //BlazorApplication.ShowViewStrategy.ShowViewInPopupWindow(dlView); --> OK works fine but not what I need // BlazorApplication.ShowViewStrategy.ShowViewFromCommonView(dlView); --> NOT WORKING ShowViewParameters svp = new ShowViewParameters(dlView); svp.Context = TemplateContext.ApplicationWindow; svp.CreateAllControllers = true; BlazorApplication.ShowViewStrategy.ShowView(svp, new ShowViewSource(null, null)); --> NOT WORKING }

Here is the entire code of my component, thank you for your help.

RazorComponent.cs

Razor
@page "/dashboard" @using DevExpress.Blazor @using DevExpress.ExpressApp; @using DevExpress.ExpressApp.Xpo @using DevExpress.ExpressApp.Blazor @using DevExpress.ExpressApp.Blazor.Services @using DevExpress.ExpressApp.Model; @using DevExpress.Persistent.BaseImpl; @using DevExpress.Xpo @using Microsoft.JSInterop @using Proakt.Module.BO; @using System.Collections.ObjectModel; @using System.Net; @using Microsoft.AspNetCore.Components.Web @inject IJSRuntime JSRuntime @inject NavigationManager NavigationManager @inject DevExpress.ExpressApp.Blazor.Services.IXafApplicationProvider ApplicationProvider <DevExpress.ExpressApp.Blazor.Templates.LoadingIndicatorComponent /> <DevExpress.ExpressApp.Blazor.Templates.PopupComponent /> <style> /* Style pour le tableau de bord */ .dashboard { display: flex; flex-wrap: wrap; gap: 20px; padding: 20px; background-color: #ffffff; justify-content: space-between; flex-direction: row; } .dashboard-item { background-color: #f8f9fa; border: 1px solid #dee2e6; border-radius: 8px; padding: 20px; flex: 1 1 calc(33.333% - 40px); /* Occupe un tiers de l'espace */ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); transition: transform 0.3s ease; cursor: pointer; text-align: center; box-sizing: border-box; } .dashboard-item:hover { transform: translateY(-5px); } .dashboard-item:hover h4 { color: #000000; } .dashboard-item img { width: 40px; height: 40px; margin-right: 15px; } .dashboard-item h4 { color: #ff5722; margin-bottom: 10px; } .dashboard-item p { color: #333333; margin: 5px 0; } .status-completed { color: green; } .status-in-progress { color: orange; } .status-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-left: 5px; } /* Style pour les titres et texte */ h3 { color: #ff5722; text-align: center; margin-bottom: 30px; } /* Style pour les liens et boutons */ a, button { color: #ff5722; text-decoration: none; border: 1px solid #ff5722; padding: 10px 20px; border-radius: 5px; transition: background-color 0.3s ease, color 0.3s ease; } a:hover, button:hover { background-color: #ff5722; color: #ffffff; } </style> @* <h3>Tableau de Bord</h3> *@ <div class="dashboard"> @foreach (var item in ObjectTypes) { switch (item.Name) { case "Sites": @* <a href="@GetViewUrl(item.Type)" class="dashboard-item"> *@ <div class="dashboard-item" @onclick="() => HandleItemClick(item.Type)"> @* <img src="@GetImageUrl(item.Type)" alt="@item.Name Icon"> *@ <div> <h4>@item.Count @item.Name</h4> @* <p class="status-in-progress">@item.Count sites<span class="status-dot" style="background-color: orange;"></span></p> *@ <p class="status-completed">@item.CountState1 sites neufs<span class="status-dot" style="background-color: #0011ff;"></span></p> </div> </div> @* </a> *@ break; default: @* <a href="@GetViewUrl(item.Type)" class="dashboard-item"> *@ <div class="dashboard-item" @onclick="() => HandleItemClick(item.Type)"> <div> <h4>@item.Count @item.Name</h4> @* <p>Nombre total : @item.Count</p> *@ <p class="status-in-progress">@item.CountState1 @item.State1<span class="status-dot" style="background-color: orange;"></span></p> <p class="status-completed">@item.CountState2 @item.State2<span class="status-dot" style="background-color: green;"></span></p> </div> </div> @* </a> *@ break; } } </div> @code { List<ObjectTypeInfo> ObjectTypes; BlazorApplication BlazorApplication = null; protected override void OnInitialized() { this.BlazorApplication = ApplicationProvider.GetApplication(); this.ObjectTypes = GetObjectCollection(); } private void HandleItemClick(Type objectType) { ListView dlView = BlazorApplication.CreateListView(objectType, true); //BlazorApplication.ShowViewStrategy.ShowViewInPopupWindow(dlView); --> OK but not what i need // BlazorApplication.ShowViewStrategy.ShowViewFromCommonView(dlView); -- NOK ShowViewParameters svp = new ShowViewParameters(dlView); svp.Context = TemplateContext.ApplicationWindow; svp.CreateAllControllers = true; BlazorApplication.ShowViewStrategy.ShowView(svp, new ShowViewSource(null, null)); --> NOK } private List<ObjectTypeInfo> GetObjectCollection() { var ObjectSpace = BlazorApplication.CreateObjectSpace(); List<ObjectTypeInfo> objectTypeInfos = new List<ObjectTypeInfo>(); var sites = ObjectSpace.GetObjectsQuery<Sites>(); objectTypeInfos.Add(new ObjectTypeInfo { Name = "Sites", Type = typeof(Sites), Count = sites.Count(), State1 = "New", CountState1 = sites.Count(obj => obj.New), State2 = "", CountState2 = sites.Count() }); var commandes = ObjectSpace.GetObjectsQuery<Commandes>(); objectTypeInfos.Add(new ObjectTypeInfo { Name = "Commandes", Type = typeof(Commandes), Count = commandes.Count(), State1 = "In Progress", CountState1 = commandes.Count(obj => obj.Statut == Status.Progress), State2 = "Finished", CountState2 = commandes.Count(obj => obj.Statut == Status.Finished), }); var tasks = ObjectSpace.GetObjectsQuery<Tasks>(); objectTypeInfos.Add(new ObjectTypeInfo { Name = "Tasks", Type = typeof(Tasks), Count = tasks.Count(), State1 = "In Progress", CountState1 = taches.Count(obj => obj.Statut == Status.Progress), State2 = "Finished", CountState2 = taches.Count(obj => obj.Statut == Status.Finished), }); var delivers = ObjectSpace.GetObjectsQuery<Delivers>(); objectTypeInfos.Add(new ObjectTypeInfo { Name = "Delivers", Type = typeof(Delivers), Count = delivers.Count(), State1 = "In Progress", CountState1 = depots.Count(obj => obj.Statut == Status.Progress), State2 = "Finished", CountState2 = depots.Count(obj => obj.Statut == Status.Finished), }); return (objectTypeInfos); } private string GetViewUrl(Type objectType) { try { return $"/{objectType.Name}_ListView"; } catch (Exception ex) { Console.WriteLine(ex); return null; } } private class ObjectTypeInfo { public string Name { get; set; } public Type Type { get; set; } public int Count { get; set; } public string State1 { get; set; } public int CountState1 { get; set; } public string State2 { get; set; } public int CountState2 { get; set; } } }

ViewItem.cs

C#
public interface IModelMDashBoardViewItem : IModelViewItem { } [ViewItem(typeof(IModelMDashBoardViewItem))] public class IMDashBoardView : ViewItem { class ComponentContentHolder : IComponentContentHolder { private readonly RenderFragment componentContent; public ComponentContentHolder(RenderFragment componentContent) { this.componentContent = componentContent; } RenderFragment IComponentContentHolder.ComponentContent => componentContent; } public IMDashBoardView(IModelMDashBoardViewItem model, Type classType) : base(classType, model.Id) { } protected override object CreateControlCore() { RenderFragment iframeFragment; iframeFragment = b => { b.OpenElement(1, "div"); b.OpenElement(2, "iframe"); b.AddAttribute(2, "id", "frame_id"); b.AddAttribute(2, "src", "./dashboard"); b.AddAttribute(2, "width", "100%"); b.AddAttribute(2, "height", "750px"); b.AddAttribute(2, "frameborder", "0"); b.AddAttribute(2, "border-radius", "20px"); b.CloseElement(); b.CloseElement(); }; return new ComponentContentHolder(iframeFragment); } }

Answers approved by DevExpress Support

created 2 days ago

Hello,

I tried replicating your use-case with a WindowController and a SimpleAction. The ShowViewStrategyBase.ShowViewFromCommonView method looks suitable for opening a View in a new tab. I see that you attempted this method but without success. Please create a small sample project that reproduces the issue. This will put us in a better position to look for a suitable solution.

Additionally, I recommend that you check the following help topic: Ways to Show a View.

The following code example also demonstrates how to access the DxAccordion instance to manage its selection:

C#
using DevExpress.ExpressApp; using DevExpress.ExpressApp.Actions; using DevExpress.ExpressApp.Blazor.Templates; using DevExpress.ExpressApp.Blazor.Templates.Navigation; using MainDemo.Module.BusinessObjects; namespace MainDemo.Blazor.Server.Controllers { public class TestController : WindowController { public TestController() { SimpleAction action = new SimpleAction(this, "OpenEmployeeView", "Edit"); action.Execute += Action_Execute; } private void Action_Execute(object sender, SimpleActionExecuteEventArgs e) { IObjectSpace objectSpace = Application.CreateObjectSpace(typeof(Employee)); ListView dlView = Application.CreateListView(typeof(Employee), true); //Open the Employee View in a separate tab Application.ShowViewStrategy.ShowViewFromCommonView(dlView); //Select the navigation item if(Application.MainWindow.Template is IMainFormTemplate mainFormTemplate && mainFormTemplate.ShowNavigationItemActionControl.NavigationComponentAdapter is DxAccordionAdapter accordionAdapter) { accordionAdapter.Component?.SelectItem(i => i.Text == dlView.Caption); } } } }

Thanks,
Arkady

    Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

    Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.