Example E2690
Visible to All Users

XAF - How to: Create information panels

In certain scenarios, you may need to create additional functional areas in a UI to display data. You can do this using additional controls in XAF templates and by implementing the code that supplies data to the controls.

image

Implementation Details

To accomplish this task, follow the steps below:

  1. Create a custom template as described in the following topic: Templates.
  2. Add to this custom template a UI element that should display the additional information (e.g., div).
  3. To pass data to this element, use a dedicated ViewController that accesses the template and passes required information to this template.

[!WARNING]
We created this example for demonstration purposes and it is not intended to address all possible usage scenarios with it.
If this example does not have certain functionality or you want to change its behavior, you can extend this example as needed. Please note that this can be a complex task that requires good knowledge of XAF: UI Customization Categories by Skill Level. You will likely need to research how our components work under the hood. Refer to the following help topic for more information: Debug DevExpress .NET Source Code with PDB Symbols.
We are unable to help with such tasks as custom programming is outside our Support Service scope: Technical Support Scope.

Files to Review

Documenation

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

EFCore/InfoPanelEF/InfoPanelEF.Module/Controllers/MyCustomController.cs
C#
using DevExpress.ExpressApp; using MySolution.Module.BusinessObjects; namespace dxTestSolution.Module.Controllers { public interface ICustomTemplate { void SetCustomString(string _customString); } public abstract class MyCustomController : ObjectViewController<ListView, Contact> { protected override void OnActivated() { base.OnActivated(); this.View.SelectionChanged += View_SelectionChanged; } public abstract ICustomTemplate GetTemplate(); private void View_SelectionChanged(object sender, EventArgs e) { var infoPanelTemplate = GetTemplate(); var selectedObjectNames = this.View.SelectedObjects.Cast<Contact>().Select(x => x.FirstName).ToList(); var finalString = string.Join("; ", selectedObjectNames); infoPanelTemplate.SetCustomString(finalString); } } }
EFCore/InfoPanelEF/InfoPanelEF.Blazor.Server/Controllers/MyCustomControllerBlazor.cs
C#
using dxTestSolution.Module.Controllers; namespace InfoPanel.Blazor.Server.Controllers { public class MyCustomControllerBlazor : MyCustomController { public override ICustomTemplate GetTemplate() { return this.Frame.Template as ICustomTemplate; } } }
EFCore/InfoPanelEF/InfoPanelEF.Blazor.Server/Templates/CustomApplicationWindowTemplate.cs
C#
using DevExpress.CodeParser.VB; using DevExpress.ExpressApp; using DevExpress.ExpressApp.Blazor.Components.Models; using DevExpress.ExpressApp.Blazor.Templates; using DevExpress.ExpressApp.Blazor.Templates.Navigation.ActionControls; using DevExpress.ExpressApp.Blazor.Templates.Security.ActionControls; using DevExpress.ExpressApp.Blazor.Templates.Toolbar.ActionControls; using DevExpress.ExpressApp.Templates; using DevExpress.ExpressApp.Templates.ActionControls; using DevExpress.Persistent.Base; using dxTestSolution.Module.Controllers; using Microsoft.AspNetCore.Components; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; namespace InfoPanelEF.Blazor.Server.Templates { public class CustomApplicationWindowTemplate : WindowTemplateBase, ISupportActionsToolbarVisibility, ISelectionDependencyToolbar, ICustomTemplate, INotifyPropertyChanged { private string customString; public CustomApplicationWindowTemplate() { NavigateBackActionControl = new NavigateBackActionControl(); AddActionControl(NavigateBackActionControl); AccountComponent = new AccountComponentAdapter(); AddActionControls(AccountComponent.ActionControls); ShowNavigationItemActionControl = new ShowNavigationItemActionControl(); AddActionControl(ShowNavigationItemActionControl); IsActionsToolbarVisible = true; Toolbar = new DxToolbarAdapter(new DxToolbarModel()); Toolbar.AddActionContainer(nameof(PredefinedCategory.ObjectsCreation)); Toolbar.AddActionContainer(nameof(PredefinedCategory.Save)); Toolbar.AddActionContainer("Close"); Toolbar.AddActionContainer(nameof(PredefinedCategory.Export)); Toolbar.AddActionContainer(nameof(PredefinedCategory.UndoRedo)); Toolbar.AddActionContainer(nameof(PredefinedCategory.Edit)); Toolbar.AddActionContainer(nameof(PredefinedCategory.RecordEdit)); Toolbar.AddActionContainer(nameof(PredefinedCategory.RecordsNavigation)); Toolbar.AddActionContainer(nameof(PredefinedCategory.View)); Toolbar.AddActionContainer(nameof(PredefinedCategory.Reports)); Toolbar.AddActionContainer(nameof(PredefinedCategory.Search)); Toolbar.AddActionContainer(nameof(PredefinedCategory.Filters)); Toolbar.AddActionContainer(nameof(PredefinedCategory.FullTextSearch)); Toolbar.AddActionContainer(nameof(PredefinedCategory.Tools)); Toolbar.AddActionContainer("Diagnostic"); Toolbar.AddActionContainer(nameof(PredefinedCategory.Unspecified)); } protected override IEnumerable<IActionControlContainer> GetActionControlContainers() => Toolbar.ActionContainers; protected override RenderFragment CreateComponent() => CustomApplicationWindowTemplateComponent.Create(this); protected override void BeginUpdate() { base.BeginUpdate(); ((ISupportUpdate)Toolbar).BeginUpdate(); } protected override void EndUpdate() { ((ISupportUpdate)Toolbar).EndUpdate(); base.EndUpdate(); } public bool IsActionsToolbarVisible { get; private set; } public NavigateBackActionControl NavigateBackActionControl { get; } public AccountComponentAdapter AccountComponent { get; } public ShowNavigationItemActionControl ShowNavigationItemActionControl { get; } public DxToolbarAdapter Toolbar { get; } public string AboutInfoString { get; set; } public string CustomString { get => customString; set { customString = value; OnPropertyChanged(); } } void ISupportActionsToolbarVisibility.SetVisible(bool isVisible) => IsActionsToolbarVisible = isVisible; public event PropertyChangedEventHandler PropertyChanged; void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public void SetCustomString(string _customString) { CustomString = _customString; } } }
EFCore/InfoPanelEF/InfoPanelEF.Blazor.Server/Templates/CustomApplicationWindowTemplateComponent.razor
Razor
@using DevExpress.ExpressApp @using DevExpress.ExpressApp.Blazor @using DevExpress.ExpressApp.Blazor.Components @using DevExpress.ExpressApp.Blazor.Templates @using Microsoft.JSInterop @using System.ComponentModel @implements IDisposable @inherits FrameTemplateComponentBase<CustomApplicationWindowTemplate> <div id="main-window-template-component" class="app h-100 d-flex flex-column"> <ComponentModelObserver ComponentModel="@FrameTemplate.NavigateBackActionControl.ButtonModel"> <div class="header d-flex flex-row shadow-sm navbar-dark flex-nowrap @DetailViewHeaderClass @NavigateBackActionHeaderClass"> <div class="header-left-side d-flex align-items-center ps-2"> <button onclick="xaf.toggleSideBar()" class="btn-hamburger p-0 btn btn-secondary btn-header"> <XafImage ImageName="Hamburger" Size="24" Styles="margin: auto;" /> </button> <div class="header-logo mx-3"></div> </div> <div class="header-right-side w-100 overflow-hidden d-flex align-items-center ps-4"> @FrameTemplate.NavigateBackActionControl.GetComponentContent() <ViewCaptionComponent WindowCaption="@FrameTemplate" /> @FrameTemplate.AccountComponent.GetComponentContent() <SettingsComponent /> </div> </div> </ComponentModelObserver> <div class="xaf-flex-auto overflow-hidden d-flex"> <div class="xaf-sidebar sidebar d-none d-sm-flex flex-column"> @FrameTemplate.ShowNavigationItemActionControl.GetComponentContent() <div class="about-info mx-3 mb-4"> @((MarkupString)FrameTemplate.AboutInfoString) </div> </div> <div class="sidebar-sm-shadow" onclick="xaf.toggleSideBar()"></div> <div class="content-info-container"> <div class="main xaf-flex-auto overflow-hidden d-flex flex-column"> <SizeModeContainer> @if(FrameTemplate.IsActionsToolbarVisible && @FrameTemplate.Toolbar.ContainsVisibleActionControl()) { <div class="main-toolbar py-3 px-2 px-sm-3">@FrameTemplate.Toolbar.GetComponentContent()</div> } <div class="main-content xaf-flex-auto overflow-auto pb-3 px-2 px-sm-3"> <ViewSiteComponent View="@FrameTemplate.View" /> </div> </SizeModeContainer> </div> <div class="info-panel">@FrameTemplate.CustomString</div> </div> </div> </div> @code { public static RenderFragment Create(CustomApplicationWindowTemplate applicationWindowTemplate) => @<CustomApplicationWindowTemplateComponent FrameTemplate="@applicationWindowTemplate" />; private string DetailViewHeaderClass => FrameTemplate.View is DetailView ? "xaf-detail-view-header" : default; private string NavigateBackActionHeaderClass => FrameTemplate.NavigateBackActionControl.Visible ? "xaf-show-navigate-back-action" : default; protected override async Task InvokeAfterViewChangedJS() { await JSRuntime.InvokeVoidAsync("xaf.closeSideBarIfMobile"); await base.InvokeAfterViewChangedJS(); } protected override void OnInitialized() { FrameTemplate.PropertyChanged += OnFrameTemplatePropertyChanged; } private void OnFrameTemplatePropertyChanged(object sender, PropertyChangedEventArgs args) { StateHasChanged(); } public void Dispose() { FrameTemplate.PropertyChanged -= OnFrameTemplatePropertyChanged; } }

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.