Skip to main content
All docs
V23.2

Underlying Controls and Components Behind UI Elements (ASP.NET Core Blazor)

  • 5 minutes to read

Overview

In XAF Blazor applications, UI is built using Razor components. Component classes are usually Razor markup pages with .razor file extension. The code snippet below demonstrates a custom Razor component:

<DxSpinEdit @bind-Value="@Value" ShowSpinButtons="false" CssClass="my-custom-class"></DxSpinEdit>

@code {
    int Value { get; set; } = 10;
}

In this code snippet, you add a DxSpinEdit<T> control to the markup, and specify the following parameters:

  • ShowSpinButtons - disables increment/decrement buttons.
  • CssClass - adds a custom class to HTML elements rendered by the DxSpinEdit component.

@bind-Value="@Value" is responsible for the following functionality:

  • When XAF renders a DxSpinEdit component, its value is set to the Value property.
  • When you change the DxSpinEdit value in UI, the Value property is updated.

See also:

You will rarely need to create custom components., but may need to customize built-in components. To do that, you don’t need to modify markup code. Use XAF component models - proxy objects that allow you to change the parameters of their respective components from anywhere in code.

For example, DxSpinEditModel is an object representation of the DxSpinEdit component. Each DxSpinEditModel property has a corresponding DxSpinEdit property:

public class DxSpinEditModel : ComponentModelBase {
    //
    public bool ShowSpinButtons {
        get => GetPropertyValue<bool>(true);
        set => SetPropertyValue(value);
    }
    public string CssClass {
        get => GetPropertyValue<string>();
        set => SetPropertyValue(value);
    }
}

To customize a property editor’s component in an auto-generated XAF View, you have to work with Component Model at runtime or in code:

using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Blazor.Editors;

public class AddCustomCssClassController : ViewController<DetailView> {
    protected override void OnActivated() {
        base.OnActivated();
        View.CustomizeViewItemControl<NumericPropertyEditor>(this, editor => {
            editor.ComponentModel.ShowSpinButtons = false;
            editor.ComponentModel.CssClass += " my-custom-class";
        });
    }
}

You can use Component Models to customize visual appearance and behavior of Property Editors (such as DxTextBox, DxDateEdit, DxSpinEdit), List Editors (such as DxGrid, DxScheduler), navigation (such as DxAccordion, DxTreeView), DxToolbar, and other components in XAF ASP.NET Core Blazor applications.

See also:

A Base Class for Underlying XAF Blazor Components

DevExpress.ExpressApp.Blazor.Components.Models.ComponentModelBase is an abstract base class for all Component Models. Built-in Component Models replicate all parameters of the corresponding component by default. However, when you create a custom Component Model, you can include only necessary parameters. You can compare XAF Blazor’s ComponentModelBase to BaseEdit in XAF WinForms or ASPxEditBase in XAF Web Forms apps.

In most cases, you can use the SetPropertyValue and GetPropertyValue methods to add the required component parameters to your Component Model class:

using DevExpress.ExpressApp.Blazor.Components.Models;
using Microsoft.AspNetCore.Components;

namespace MainDemo.Blazor.Server.Controllers;

public class InputModel : ComponentModelBase {
    public string Value {
        get => GetPropertyValue<string>();
        set => SetPropertyValue(value);
    }
    public EventCallback<string> ValueChanged {
        get => GetPropertyValue<EventCallback<string>>();
        set => SetPropertyValue(value);
    }
    public bool ReadOnly {
        get => GetPropertyValue<bool>();
        set => SetPropertyValue(value);
    }
}

The following methods and properties can also be useful:

ComponentModelBase.SetAttribute

This method sets additional attributes for the component (an equivalent of the ParameterAttribute.CaptureUnmatchedValues property). For more information, refer to the following topic: Arbitrary attributes.

public void SetAttribute(string name, object value)

Example of usage:

InputModel model = new InputModel();
model.SetAttribute("title", "A tooltip text");

XAF ASP.NET Core Blazor ComponentModel SetAttribute Method, DevExpress

ComponentModelBase.Attributes

This property contains a list of additional attributes specified by the ComponentModelBase.SetAttribute method.

public IReadOnlyDictionary<string, object> Attributes { get; }

Example of usage:

<InputText Value=@ComponentModel.Value
        @* --- *@
        @attributes=ComponentModel.Attributes />

@code {
    [Parameter] public InputModel ComponentModel { get; set; }
}

Note

For additional context, see the following topic: Component Renderer.

See also:

Component State Changes and Content Re-Render

ComponentModelBase implements the IComponentModel interface that has the Changed event.

namespace DevExpress.ExpressApp.Blazor.Components.Models

public interface IComponentModel {
    event EventHandler Changed;
}

This event is triggered every time a property of the Component Model changes, for example, when you call the SetPropertyValue method with a new value.

DevExpress.ExpressApp.Blazor.Components.ComponentModelObserver is a component that wraps the main component and subscribes to the ComponentModel.Changed event. When the event is triggered, ComponentModelObserver calls the StateHasChanged method and re-renders itself and the child component.

Razor markup
<ComponentModelObserver ComponentModel="@ComponentModel">
    <InputRenderer ComponentModel="@ComponentModel" />
</ComponentModelObserver>

@code {
    [Parameter] public InputModel ComponentModel { get; set; }
}
In XAF
public class InputAdapter : ComponentAdapterBase {
    //...
    public override InputModel ComponentModel { get; }
    protected override RenderFragment CreateComponent() {
        return ComponentModelObserver.Create(ComponentModel, InputRenderer.Create(ComponentModel));
    }
}

Tip

For the complete scenario, refer to the following topic: Implement a Property Editor Based on a Custom Component (Blazor).

For all component models shipped with XAF, we auto-generate the GetComponentContent extension method that returns RenderFragment of the related component. The following code snipped demonstrates how to use this method:

Razor markup
<ComponentModelObserver ComponentModel="TextBoxModel">
    @TextBoxModel.GetComponentContent()
</ComponentModelObserver>

@code {
    DxTextBoxModel TextBoxModel { get; set; } = new DxTextBoxModel();
}
In XAF
DxTextBoxModel TextBoxModel { get; set; } = new DxTextBoxModel();
//
public RenderFragment CreateComponent() {
    return ComponentModelObserver.Create(TextBoxModel, TextBoxModel.GetComponentContent());
}

Handle Component Events

Razor components usually have events implemented as properties of the EventCallback<T> type. Examples include DxTextBox.TextChanged or InputBase.ValueChanged.

XAF can handle some of these events. To safely add your own event handler without overriding the default XAF implementation, we recommend that you use the following pattern:

var defaultEventHandler = ComponentModel.SomeEvent;
ComponentModel.SomeEvent = EventCallback.Factory.Create<TArgument>(this, async eventArgument => {
    // Comment out the line below if you do not want XAF to handle this event.
    await defaultEventHandler.InvokeAsync(eventArgument);

    // Implement your custom logic here.
    // ...
});

See also: