Files
radzen-blazor/Radzen.Blazor/DataBoundFormComponent.cs

413 lines
12 KiB
C#

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Web;
using Radzen.Blazor;
using Radzen.Blazor.Rendering;
using System;
using System.Collections;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace Radzen
{
/// <summary>
/// Class DataBoundFormComponent.
/// Implements the <see cref="Radzen.RadzenComponent" />
/// Implements the <see cref="Radzen.IRadzenFormComponent" />
/// </summary>
/// <typeparam name="T"></typeparam>
/// <seealso cref="Radzen.RadzenComponent" />
/// <seealso cref="Radzen.IRadzenFormComponent" />
public class DataBoundFormComponent<T> : RadzenComponent, IRadzenFormComponent
{
/// <summary>
/// Gets or sets the index of the tab.
/// </summary>
/// <value>The index of the tab.</value>
[Parameter]
public int TabIndex { get; set; } = 0;
/// <summary>
/// Gets or sets the filter case sensitivity.
/// </summary>
/// <value>The filter case sensitivity.</value>
[Parameter]
public FilterCaseSensitivity FilterCaseSensitivity { get; set; } = FilterCaseSensitivity.Default;
/// <summary>
/// Gets or sets the filter operator.
/// </summary>
/// <value>The filter operator.</value>
[Parameter]
public StringFilterOperator FilterOperator { get; set; } = StringFilterOperator.Contains;
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
[Parameter]
public string? Name { get; set; }
/// <summary>
/// Gets or sets the placeholder.
/// </summary>
/// <value>The placeholder.</value>
[Parameter]
public string? Placeholder { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="DataBoundFormComponent{T}"/> is disabled.
/// </summary>
/// <value><c>true</c> if disabled; otherwise, <c>false</c>.</value>
[Parameter]
public bool Disabled { get; set; }
/// <summary>
/// Gets or sets the change.
/// </summary>
/// <value>The change.</value>
[Parameter]
public EventCallback<object> Change { get; set; }
/// <summary>
/// Gets or sets the load data.
/// </summary>
/// <value>The load data.</value>
[Parameter]
public EventCallback<Radzen.LoadDataArgs> LoadData { get; set; }
/// <summary>
/// The form
/// </summary>
IRadzenForm? form;
/// <summary>
/// Gets or sets the form.
/// </summary>
/// <value>The form.</value>
[CascadingParameter]
public IRadzenForm? Form
{
get
{
return form;
}
set
{
form = value;
form?.AddComponent(this);
}
}
/// <summary>
/// The value
/// </summary>
private T? _value;
/// <summary>
/// Gets or sets the value.
/// </summary>
/// <value>The value.</value>
[Parameter]
public T? Value
{
get
{
return _value;
}
set
{
if (value == null || value.Equals("null"))
{
_value = default;
return;
}
if (!value.Equals(_value))
_value = value;
}
}
/// <summary>
/// Gets or sets the value changed.
/// </summary>
/// <value>The value changed.</value>
[Parameter]
public EventCallback<T> ValueChanged { get; set; }
/// <summary>
/// Gets a value indicating whether this instance is bound.
/// </summary>
/// <value><c>true</c> if this instance is bound; otherwise, <c>false</c>.</value>
public bool IsBound
{
get
{
return ValueChanged.HasDelegate;
}
}
/// <summary>
/// Gets a value indicating whether this instance has value.
/// </summary>
/// <value><c>true</c> if this instance has value; otherwise, <c>false</c>.</value>
public virtual bool HasValue
{
get
{
if (typeof(T) == typeof(string))
{
return !string.IsNullOrEmpty($"{Value}");
}
return Value != null;
}
}
/// <summary>
/// Gets or sets the text property.
/// </summary>
/// <value>The text property.</value>
[Parameter]
public string? TextProperty { get; set; }
/// <summary>
/// The data
/// </summary>
IEnumerable? _data;
/// <summary>
/// Gets or sets the data.
/// </summary>
/// <value>The data.</value>
[Parameter]
public virtual IEnumerable? Data
{
get
{
return _data;
}
set
{
if (_data != value)
{
_view = null;
_value = default;
_data = value;
StateHasChanged();
}
}
}
/// <summary>
/// Called when [data changed].
/// </summary>
protected virtual async Task OnDataChanged()
{
await Task.CompletedTask;
}
/// <summary>
/// Gets the query.
/// </summary>
/// <value>The query.</value>
protected virtual IQueryable? Query
{
get
{
return Data != null ? Data.AsQueryable() : null;
}
}
/// <summary>
/// Gets or sets the search text
/// </summary>
[Parameter]
public string? SearchText
{
get
{
return searchText;
}
set
{
if (searchText != value)
{
searchText = value;
}
}
}
/// <summary>
/// Gets or sets the search text changed.
/// </summary>
/// <value>The search text changed.</value>
[Parameter]
public EventCallback<string> SearchTextChanged { get; set; }
/// <summary>
/// The search text
/// </summary>
internal string? searchText;
/// <summary>
/// The view
/// </summary>
protected IQueryable? _view;
/// <summary>
/// Gets the view.
/// </summary>
/// <value>The view.</value>
protected virtual IEnumerable? View
{
get
{
var query = Query;
if (_view == null && query != null)
{
if (!string.IsNullOrEmpty(searchText) && !string.IsNullOrEmpty(TextProperty))
{
_view = query.Where(TextProperty, searchText, FilterOperator, FilterCaseSensitivity);
}
else
{
_view = Data is IQueryable ? query.Cast<object>().ToList().AsQueryable() : query;
}
}
return _view;
}
}
internal IEnumerable? GetView() => View;
/// <summary>
/// Gets or sets the edit context.
/// </summary>
/// <value>The edit context.</value>
[CascadingParameter]
public EditContext? EditContext { get; set; }
/// <summary>
/// Gets the field identifier.
/// </summary>
/// <value>The field identifier.</value>
[Parameter]
public FieldIdentifier FieldIdentifier { get; set; }
/// <summary>
/// Gets or sets the value expression.
/// </summary>
/// <value>The value expression.</value>
[Parameter]
public Expression<Func<T>>? ValueExpression { get; set; }
/// <summary>
/// Set parameters as an asynchronous operation.
/// </summary>
/// <param name="parameters">The parameters.</param>
/// <returns>A Task representing the asynchronous operation.</returns>
public override async Task SetParametersAsync(ParameterView parameters)
{
// check for changes before setting the properties through the base call
var dataChanged = parameters.DidParameterChange(nameof(Data), Data);
var disabledChanged = parameters.DidParameterChange(nameof(Disabled), Disabled);
// allow the base class to process parameters and set the properties
// after this call the parameters object should be considered stale
await base.SetParametersAsync(parameters);
// handle changes
if (dataChanged)
{
await OnDataChanged();
}
if (EditContext != null && (ValueExpression != null || ValueChanged.HasDelegate) && FieldIdentifier.Model != EditContext.Model)
{
FieldIdentifier = ValueExpression != null
? FieldIdentifier.Create(ValueExpression)
: FieldIdentifier.Create(() => Value);
EditContext.OnValidationStateChanged -= ValidationStateChanged;
EditContext.OnValidationStateChanged += ValidationStateChanged;
}
if (disabledChanged)
{
FormFieldContext?.DisabledChanged(Disabled);
}
}
/// <summary>
/// Validations the state changed.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="ValidationStateChangedEventArgs"/> instance containing the event data.</param>
private void ValidationStateChanged(object? sender, ValidationStateChangedEventArgs e)
{
StateHasChanged();
}
/// <summary>
/// Disposes this instance.
/// </summary>
public override void Dispose()
{
base.Dispose();
if (EditContext != null)
{
EditContext.OnValidationStateChanged -= ValidationStateChanged;
}
Form?.RemoveComponent(this);
GC.SuppressFinalize(this);
}
/// <summary>
/// Gets the value.
/// </summary>
/// <returns>System.Object.</returns>
public virtual object? GetValue()
{
return Value;
}
/// <summary>
/// Gets the class list.
/// </summary>
/// <param name="className">Name of the class.</param>
/// <returns>ClassList.</returns>
protected ClassList GetClassList(string className) => ClassList.Create(className)
.AddDisabled(Disabled)
.Add(FieldIdentifier, EditContext)
.Add("rz-state-empty", !HasValue);
/// <inheritdoc/>
public virtual async ValueTask FocusAsync()
{
await Element.FocusAsync();
}
/// <summary> Provides support for RadzenFormField integration. </summary>
[CascadingParameter]
public IFormFieldContext? FormFieldContext { get; set; }
/// <summary> Gets the current placeholder. Returns empty string if this component is inside a RadzenFormField.</summary>
protected string? CurrentPlaceholder => FormFieldContext?.AllowFloatingLabel == true ? " " : Placeholder;
/// <summary>
/// Handles the ContextMenu event.
/// </summary>
/// <param name="args">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
/// <returns>Task.</returns>
public override Task OnContextMenu(MouseEventArgs args)
{
if (!Disabled)
{
return base.OnContextMenu(args);
}
return Task.CompletedTask;
}
}
}