Skip to main content
All docs
V23.2

How to: Show a Custom Data-Bound Control in an XAF View (Blazor) - Current Object Data

  • 5 minutes to read

This article explains how to create a reusable View Item that can work with data supplied by the View’s current object. Before you continue, make sure you are familiar with the tutorial that describes the commonly required steps - How to: Show a Custom Data-Bound Control in an XAF View (Blazor) - External Data.

DevExpress XAF - A Custom Data-Bound Control

Create a Razor Component

In this example, you create a Razor component based on DxAccordion. The new component displays employees assigned to a particular department.

To add this component to your project, follow the steps below:

  1. In the Solution Explorer, right-click your project’s name and select Add -> New Item from the ensuing context menu.
  2. Specify a component name (DepartmentViewer.razor).
  3. Add the following code to the created file.

    @using MainDemo.Module.BusinessObjects;
    @using DevExpress.Blazor;
    
    <b>Department name:</b> <DxTextBox Text="@Department?.Title" TextChanged="@OnTitleChanged" /><br />
    <b>Department head:</b> @Department?.DepartmentHead?.FullName<br />
    <b>Department description:</b> @Department?.Description<br /><br />
    
    <DxAccordion ExpandMode="AccordionExpandMode.SingleOrNone"
                style="max-width: 600px"
                AnimationType="LayoutAnimationType.Slide">
        <Items>
            @if (Department?.Employees != null) {
                @foreach (var employee in Department.Employees) {
                    <DxAccordionItem Text="@employee.FullName" @key="employee">
                        <ContentTemplate>
                            <div style="display: flex;">
                                <div style="flex: 1 0 0;">
                                    <div><b>Full name:</b> @employee.FullName</div>
                                    <div><b>Email address:</b> @employee.Email</div>
                                    <div><b>Position:</b> @employee.Position</div>
                                    <div><b>Office:</b> @employee.Department.Office</div>
                                    @if (employee.Manager is not null) {
                                        <div><b>Manager:</b> @employee.Manager.FullName</div>
                                    }
                                </div>
                                <div style="flex: 1 0 0; display: flex; justify-content: end;">
                                    @if (employee.Photo != null) {
                                        <div style="flex: 1 0 0; display: flex; justify-content: end;">
                                            <img src="@($"data:image/png;base64,{Convert.ToBase64String(employee.Photo)}")"
                                                style="max-width: 300px; max-height: 300px;">
                                        </div>
                                    }
                                </div>
                            </div>
                        </ContentTemplate>
                    </DxAccordionItem>
                }
            }
        </Items>
    </DxAccordion>
    
    @code {
        [Parameter] public DepartmentViewerModel ComponentModel { get; set; }
        public static RenderFragment Create(DepartmentViewerModel componentModel) => @<DepartmentViewer ComponentModel="@componentModel" />;
        private Department Department => ComponentModel.Department;
        private void OnTitleChanged(string title) => ComponentModel.SetTitleFromUI(title);
    }
    

    The DepartmentViewerModel.SetTitleFromUI method notifies subscribers when a user changes the department’s title.

  4. In the Properties window, set this file’s Build Action to Content.

An important difference between this component and the one used in a similar tutorial is the OnTitleChanged method. This method allows you to notify the application that a user changed the value in the department name text box.

Implement a Custom View Item and Its Control

Implement a custom View Item that returns an IComponentContentHolder as its control, as well as a Component Model for the custom DepartmentViewer Razor component. To do this, follow the steps below:

  1. Add a new file (DepartmentViewerViewItem.cs) to your Blazor project.
  2. Add the following code to the created file.

    using DevExpress.ExpressApp.Blazor;
    using DevExpress.ExpressApp.Blazor.Components;
    using DevExpress.ExpressApp.Blazor.Components.Models;
    using DevExpress.ExpressApp.Editors;
    using DevExpress.ExpressApp.Model;
    using MainDemo.Module.BusinessObjects;
    using Microsoft.AspNetCore.Components;
    
    namespace MainDemo.Blazor.Server;
    
    public class DepartmentViewerModel : ComponentModelBase {
        public Department Department {
            get => GetPropertyValue<Department>();
            set => SetPropertyValue(value);
        }
        public void SetTitleFromUI(string title) {
            TitleChanged?.Invoke(this, title);
        }
        public event EventHandler<string> TitleChanged;
    }
    
    public class DepartmentViewerAdapter : IComponentContentHolder {
        private RenderFragment _componentContent;
        public DepartmentViewerModel ComponentModel { get; set; }
        public DepartmentViewerAdapter(DepartmentViewerModel componentModel) {
            ComponentModel = componentModel;
        }
        public RenderFragment ComponentContent {
            get {
                _componentContent ??= ComponentModelObserver.Create(ComponentModel, DepartmentViewer.Create(ComponentModel));
                return _componentContent;
            }
        }
    }
    
    public interface IModelDepartmentViewerViewItem : IModelViewItem { }
    
    [ViewItem(typeof(IModelDepartmentViewerViewItem))]
    public class DepartmentViewerViewItem : ViewItem {
        public DepartmentViewerAdapter ComponentAdapter { get; private set; }
        public DepartmentViewerViewItem(IModelDepartmentViewerViewItem model, Type objectType) : base(objectType, model.Id) { }
        protected override object CreateControlCore() {
            ComponentAdapter = new DepartmentViewerAdapter(new DepartmentViewerModel() { Department = View.CurrentObject as Department });
            return ComponentAdapter;
        }
    }
    
  3. Rebuild your solution.

For more information on how to implement View Items in XAF applications, refer to the following topic: Implement a View Item (WinForms).

Create a View Controller to Manage the Control’s Data

To make sure that the View Item refreshes to reflect the correct data when the current object changes, add the following controller to your application. This controller is also used to update the object after the user made changes to the View Item (e.g., changed the Department name).

  1. Add a new file (DepartmentViewerController.cs) to your Blazor project.
  2. Add the following code to the created file.

    using DevExpress.ExpressApp;
    using MainDemo.Module.BusinessObjects;
    
    namespace MainDemo.Blazor.Server.Controllers;
    
    public class DepartmentViewerController : ObjectViewController<DetailView, Department> {
        protected override void OnActivated() {
            base.OnActivated();
            View.CurrentObjectChanged += View_CurrentObjectChanged;
            View.CustomizeViewItemControl<DepartmentViewerViewItem>(this, viewItem => {
                viewItem.ComponentAdapter.ComponentModel.TitleChanged += (_, title) => {
                    if (View.CurrentObject is Department department) {
                        department.Title = title;
                    }
                };
            });
        }
    
        protected override void OnDeactivated() {
            base.OnDeactivated();
            View.CurrentObjectChanged -= View_CurrentObjectChanged;
        }
    
        // Alternatively, you can use the ViewItem.CurrentObjectChanged event to achieve similar functionality directly in the View Item.
        private void View_CurrentObjectChanged(object sender, EventArgs e) {
            foreach (var departmentViewItem in View.GetItems<DepartmentViewerViewItem>()) {
                if (departmentViewItem.ComponentAdapter is not null) {
                    departmentViewItem.ComponentAdapter.ComponentModel.Department = View.CurrentObject as Department;
                }
            }
        }
    }
    

Change the Default Detail View for the Department List View

  1. In the Blazor application project, double-click the Model.xafml file to start the Model Editor. Right-click the Views node and choose Add | DetailView.

    DevExpress XAF - Add a View

  2. Set the Id property to CustomDepartment_DetailView and the ModelClass property to MainDemo.Module.BusinessObjects.Department.

    DevExpress XAF - Specify a View ID

  3. Right-click the Views | MainDemo.Module.BusinessObjects | CustomDepartment_DetailView | Items node and choose Add… | DepartmentViewerItemView.

    DevExpress XAF - Add a Detail View Item

  4. Set the Id property to DepartmentViewItem.

  5. Navigate to the Views | MainDemo.Module.BusinessObjects | Department_ListView node. In the DetailView drop-down list, select CustomDepartment_DetailView.

    DevExpress XAF - Change a Default Detail View

  6. Run the your Blazor application, navigate to the Department List View and see the result.

    DevExpress XAF - A Custom Data-Bound Control