Implement a Property Editor Based on a Custom Component (Blazor)
- 5 minutes to read
This topic describes how to implement a Property Editor for ASP.NET Core Blazor applications. For this, implement the following entities in the application project (MySolution.Blazor.Server):
- Component Model
- An object representation of the component that is required to change the component’s state.
- Property Editor
- A class that integrates the component into your XAF application.
Note
When you use Razor markup (*.razor) to create a custom component, ensure that the component’s logic is separated from property editors. Use Parameters and the @inject directive to supply necessary data to the component. Avoid mixing the component’s logic with the component model or property editor.
The process of component creation in XAF is similar to non-XAF applications. The Component Model contains information about component parameters and component type, and is responsible for linking the component with the property editor.
For more information about the XAF Component Model, refer to the following topic: Underlying Controls and Components Behind UI Elements (ASP.NET Core Blazor).
The example below demonstrates a custom String Property Editor that displays the InputText component.
Component Model
- Create a
ComponentModelBase
descendant and name it InputTextModel. In this class, declare properties that you will set in the underlying InputText component. The properties must have the same type and name as their counterparts in the component. In this example, useValue
,ValueChanged
, andValueExpression
properties. - Override the
ComponentType
method and return the type of the component. XAF automatically creates a RenderFragment to renderInputText
based on properties and component type specified in the Component Model.
File: MySolution.Blazor.Server\Editors\InputTextModel.cs
using System.Linq.Expressions;
using DevExpress.ExpressApp.Blazor.Components.Models;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
namespace YourSolutionName.Blazor.Server.Editors;
public class InputTextModel : ComponentModelBase {
public string Value {
get => GetPropertyValue<string>();
set => SetPropertyValue(value);
}
public EventCallback<string> ValueChanged {
get => GetPropertyValue<EventCallback<string>>();
set => SetPropertyValue(value);
}
public Expression<Func<string>> ValueExpression {
get => GetPropertyValue<Expression<Func<string>>>();
set => SetPropertyValue(value);
}
public override Type ComponentType => typeof(InputText);
}
Property Editor
- Create a
BlazorPropertyEditorBase
descendant and name it CustomStringPropertyEditor. Apply a PropertyEditorAttribute to it and set its parameters tostring
andfalse
. These values specify that you can choose this Property Editor in the Model Editor for any string property, and this editor is not marked as default. - Override the
CreateComponentModel
method, create theInputTextModel
instance, and set it up. - Override the
ReadValueCore
andGetControlValueCore
methods to set and retrieve the value of the underlying component. - Override the
ApplyReadOnly
method to manage the read-only state.
File: MySolution.Blazor.Server\Editors\CustomStringPropertyEditor.cs
using DevExpress.ExpressApp.Blazor.Components.Models;
using DevExpress.ExpressApp.Blazor.Editors;
using DevExpress.ExpressApp.Editors;
using DevExpress.ExpressApp.Model;
using Microsoft.AspNetCore.Components;
namespace YourSolutionName.Blazor.Server.Editors;
[PropertyEditor(typeof(string), false)]
public class CustomStringPropertyEditor : BlazorPropertyEditorBase {
public CustomStringPropertyEditor(Type objectType, IModelMemberViewItem model) : base(objectType, model) { }
public override InputTextModel ComponentModel => (InputTextModel)base.ComponentModel;
protected override IComponentModel CreateComponentModel() {
var model = new InputTextModel();
model.ValueExpression = () => model.Value;
model.ValueChanged = EventCallback.Factory.Create<string>(this, value => {
model.Value = value;
OnControlValueChanged();
WriteValue();
});
return model;
}
protected override void ReadValueCore() {
base.ReadValueCore();
ComponentModel.Value = (string)PropertyValue;
}
protected override object GetControlValueCore() => ComponentModel.Value;
protected override void ApplyReadOnly() {
base.ApplyReadOnly();
ComponentModel?.SetAttribute("readonly", !AllowEdit);
}
}
Rebuild your solution and invoke the Model Editor for the ASP.NET Core Blazor application project (MySolution.Blazor.Server). Navigate to the required BOModel | <Class> | OwnMembers | <Member> node and set the node’s PropertyEditorType property to CustomStringPropertyEditor
.
You can also set this Property Editor for a particular View only. To do this, specify the PropertyEditorType
property of the Views | <DetailView> | Items | <PropertyEditor> node.
Note
If your project uses .NET 6 or earlier, an error may occur. For more information, refer to the following pull request in the ASP.NET Core open-source repository: Blazor input component support when EditContext is not supplied.
Note
The built-in Component Model handles the Component’s ValueChanged
event (TextChanged
, DateChanged
, TimeChanged
, and so on) and automatically reads and writes the Component’s Value (Text, Date, Time, and so on). For example, an implementation of a property editor based on DxTextBoxModel
may look like this:
using DevExpress.ExpressApp.Blazor.Components.Models;
using DevExpress.ExpressApp.Blazor.Editors;
using DevExpress.ExpressApp.Editors;
using DevExpress.ExpressApp.Model;
[PropertyEditor(typeof(string), false)]
public class CustomStringPropertyEditor : BlazorPropertyEditorBase {
public CustomStringPropertyEditor(Type objectType, IModelMemberViewItem model) : base(objectType, model) { }
public override DxTextBoxModel ComponentModel => (DxTextBoxModel)base.ComponentModel;
protected override IComponentModel CreateComponentModel() => new DxTextBoxModel();
}
Access XafApplication and ObjectSpace to Query and Manipulate Data (Perform CRUD Operations)
A custom Property Editor may require access to the application or the View ObjectSpace object. If so, implement the IComplexViewItem
interface as shown in the following topic: IComplexViewItem.
Use the IComplexViewItem.Setup method to get the XafApplication and IObjectSpace objects. The IObjectSpace object contains methods to access the application database.
Display a Custom Component in a List View
The InputText component from the above example will be rendered in Detail Views and in List Views during inline editing. To specify a component that your custom Property Editor should render in regular List View cells, override the BlazorPropertyEditorBase.CreateViewComponentCore
method.
File: MySolution.Blazor.Server\CustomStringPropertyEditor.cs
using DevExpress.ExpressApp.Blazor.Components.Models;
using DevExpress.ExpressApp.Blazor.Editors;
using DevExpress.ExpressApp.Editors;
using Microsoft.AspNetCore.Components;
namespace YourSolutionName.Blazor.Server.Editors;
[PropertyEditor(typeof(string), false)]
public class CustomStringPropertyEditor : BlazorPropertyEditorBase {
// ...
protected override RenderFragment CreateViewComponentCore(object dataContext) {
InputTextModel componentModel = new InputTextModel();
componentModel.Value = (string)this.GetPropertyValue(dataContext);
componentModel.ValueExpression = () => componentModel.Value;
componentModel.SetAttribute("readonly", true);
return componentModel.GetComponentContent();
}
}
The image below demonstrates the result.