[WIP] Refactor components to match converter refactor
This commit is contained in:
parent
f3ae953772
commit
6f91dacb0c
@ -5,14 +5,14 @@
|
|||||||
<CascadingValue Name="SubscribeToParentForm" Value="false" IsFixed="true">
|
<CascadingValue Name="SubscribeToParentForm" Value="false" IsFixed="true">
|
||||||
<div class="@AutocompleteClassList">
|
<div class="@AutocompleteClassList">
|
||||||
<InputControl Label="@Label" Variant="@Variant" HelperText="@HelperText" HelperTextOnFocus="@HelperTextOnFocus" FullWidth="@FullWidth" Margin="@Margin" Class="@ClassList()" Style="@Style"
|
<InputControl Label="@Label" Variant="@Variant" HelperText="@HelperText" HelperTextOnFocus="@HelperTextOnFocus" FullWidth="@FullWidth" Margin="@Margin" Class="@ClassList()" Style="@Style"
|
||||||
Error="@Error" ErrorText="@ErrorText" Disabled="@Disabled" @onclick="@ToggleMenu" Required="@Required" ForId="@FieldId">
|
Error="@HasError" ErrorText="@ErrorText" Disabled="@Disabled" @onclick="@ToggleMenu" Required="@Required" ForId="@FieldId">
|
||||||
<InputContent>
|
<InputContent>
|
||||||
<Input @ref="_elementReference" @key="_elementKey" InputType="InputType.Text"
|
<Input @ref="_elementReference" @key="_elementKey" InputType="InputType.Text"
|
||||||
Class="select-input" Margin="@Margin"
|
Class="select-input" Margin="@Margin"
|
||||||
Variant="@Variant"
|
Variant="@Variant"
|
||||||
TextUpdateSuppression="@TextUpdateSuppression"
|
TextUpdateSuppression="@TextUpdateSuppression"
|
||||||
Value="@Text" DisableUnderLine="@DisableUnderLine"
|
Value="@Text" DisableUnderLine="@DisableUnderLine"
|
||||||
Disabled="@Disabled" ReadOnly="@ReadOnly" Error="@Error"
|
Disabled="@Disabled" ReadOnly="@ReadOnly" Error="@HasError"
|
||||||
OnAdornmentClick="@OnAdornmentClick" AdornmentIcon="@CurrentIcon" Adornment="@Adornment" AdornmentColor="@AdornmentColor" IconSize="@IconSize" AdornmentText="@AdornmentText"
|
OnAdornmentClick="@OnAdornmentClick" AdornmentIcon="@CurrentIcon" Adornment="@Adornment" AdornmentColor="@AdornmentColor" IconSize="@IconSize" AdornmentText="@AdornmentText"
|
||||||
Clearable="@Clearable" OnClearButtonClick="@OnClearButtonClick"
|
Clearable="@Clearable" OnClearButtonClick="@OnClearButtonClick"
|
||||||
@attributes="UserAttributes"
|
@attributes="UserAttributes"
|
||||||
|
@ -83,10 +83,7 @@ public partial class Autocomplete<T> : InputBase<T>, IDisposable
|
|||||||
|
|
||||||
_toStringFunc = value;
|
_toStringFunc = value;
|
||||||
|
|
||||||
Converter = new Converter<T>
|
Converter = new LambdaConverter<T, string>(_toStringFunc ?? (x => x?.ToString()), null);
|
||||||
{
|
|
||||||
SetFunc = _toStringFunc ?? (x => x?.ToString()),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -461,7 +458,7 @@ public partial class Autocomplete<T> : InputBase<T>, IDisposable
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Converter.Set(item);
|
return Converter.Convert(item);
|
||||||
}
|
}
|
||||||
catch (NullReferenceException) { }
|
catch (NullReferenceException) { }
|
||||||
|
|
||||||
@ -628,7 +625,7 @@ public partial class Autocomplete<T> : InputBase<T>, IDisposable
|
|||||||
|
|
||||||
_timer?.Dispose();
|
_timer?.Dispose();
|
||||||
|
|
||||||
var value = Converter.Get(Text);
|
var value = Converter.ConvertBack(Text);
|
||||||
|
|
||||||
return SetValueAsync(value, updateText: false);
|
return SetValueAsync(value, updateText: false);
|
||||||
}
|
}
|
||||||
|
@ -44,17 +44,17 @@ public class BooleanInput<T> : FormComponent<T, bool?>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter] public EventCallback<T> CheckedChanged { get; set; }
|
[Parameter] public EventCallback<T> CheckedChanged { get; set; }
|
||||||
|
|
||||||
protected bool? BoolValue => Converter.Set(Checked);
|
protected bool? BoolValue => Converter.Convert(Checked);
|
||||||
|
|
||||||
protected virtual Task OnChange(ChangeEventArgs args)
|
protected virtual Task OnChange(ChangeEventArgs args)
|
||||||
{
|
{
|
||||||
Touched = true;
|
Modified = true;
|
||||||
return SetBoolValueAsync((bool?)args.Value);
|
return SetBoolValueAsync((bool?)args.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Task SetBoolValueAsync(bool? value)
|
protected Task SetBoolValueAsync(bool? value)
|
||||||
{
|
{
|
||||||
return SetCheckedAsync(Converter.Get(value));
|
return SetCheckedAsync(Converter.ConvertBack(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task SetCheckedAsync(T value)
|
protected async Task SetCheckedAsync(T value)
|
||||||
@ -74,7 +74,7 @@ public class BooleanInput<T> : FormComponent<T, bool?>
|
|||||||
{
|
{
|
||||||
var changed = base.SetConverter(value);
|
var changed = base.SetConverter(value);
|
||||||
if (changed)
|
if (changed)
|
||||||
SetBoolValueAsync(Converter.Set(Checked)).AndForget();
|
SetBoolValueAsync(Converter.Convert(Checked)).AndForget();
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ public partial class CheckBox<T> : BooleanInput<T>
|
|||||||
|
|
||||||
protected override Task OnChange(ChangeEventArgs args)
|
protected override Task OnChange(ChangeEventArgs args)
|
||||||
{
|
{
|
||||||
Touched = true;
|
Modified = true;
|
||||||
|
|
||||||
// Apply only when TriState parameter is set to true and T is bool?
|
// Apply only when TriState parameter is set to true and T is bool?
|
||||||
if (TriState && typeof(T) == typeof(bool?))
|
if (TriState && typeof(T) == typeof(bool?))
|
||||||
|
@ -116,11 +116,7 @@ public partial class DataGrid<T> : UIComponent
|
|||||||
internal bool isEditFormOpen;
|
internal bool isEditFormOpen;
|
||||||
|
|
||||||
// converters
|
// converters
|
||||||
private Converter<bool, bool?> _oppositeBoolConverter = new Converter<bool, bool?>
|
private Converter<bool, bool?> _oppositeBoolConverter = new LambdaConverter<bool, bool?>(value => value ? false : true, value => value.HasValue ? !value.Value : true);
|
||||||
{
|
|
||||||
SetFunc = value => value ? false : true,
|
|
||||||
GetFunc = value => value.HasValue ? !value.Value : true,
|
|
||||||
};
|
|
||||||
|
|
||||||
#region Notify Children Delegates
|
#region Notify Children Delegates
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ public class DatePicker : DatePickerBase
|
|||||||
{
|
{
|
||||||
if (_value != date)
|
if (_value != date)
|
||||||
{
|
{
|
||||||
Touched = true;
|
Modified = true;
|
||||||
|
|
||||||
if (date is not null && IsDateDisabledFunc(date.Value.Date))
|
if (date is not null && IsDateDisabledFunc(date.Value.Date))
|
||||||
{
|
{
|
||||||
@ -40,10 +40,8 @@ public class DatePicker : DatePickerBase
|
|||||||
|
|
||||||
_value = date;
|
_value = date;
|
||||||
if (updateValue)
|
if (updateValue)
|
||||||
{
|
await SetTextAsync(Converter.Convert(_value), false);
|
||||||
Converter.GetError = false;
|
|
||||||
await SetTextAsync(Converter.Set(_value), false);
|
|
||||||
}
|
|
||||||
await DateChanged.InvokeAsync(_value);
|
await DateChanged.InvokeAsync(_value);
|
||||||
BeginValidate();
|
BeginValidate();
|
||||||
FieldChanged(_value);
|
FieldChanged(_value);
|
||||||
@ -52,15 +50,15 @@ public class DatePicker : DatePickerBase
|
|||||||
|
|
||||||
protected override Task DateFormatChanged(string newFormat)
|
protected override Task DateFormatChanged(string newFormat)
|
||||||
{
|
{
|
||||||
Touched = true;
|
Modified = true;
|
||||||
return SetTextAsync(Converter.Set(_value), false);
|
return SetTextAsync(Converter.Convert(_value), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Task StringValueChanged(string value)
|
protected override Task StringValueChanged(string value)
|
||||||
{
|
{
|
||||||
Touched = true;
|
Modified = true;
|
||||||
// Update the date property (without updating back the Value property)
|
// Update the date property (without updating back the Value property)
|
||||||
return SetDateAsync(Converter.Get(value), false);
|
return SetDateAsync(Converter.ConvertBack(value), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string GetDayClasses(int month, DateTime day)
|
protected override string GetDayClasses(int month, DateTime day)
|
||||||
|
@ -230,7 +230,7 @@ public abstract partial class DatePickerBase : Picker<DateTime?>
|
|||||||
base.OnPickerOpened();
|
base.OnPickerOpened();
|
||||||
if (Editable == true && Text != null)
|
if (Editable == true && Text != null)
|
||||||
{
|
{
|
||||||
DateTime? a = Converter.Get(Text);
|
DateTime? a = Converter.ConvertBack(Text);
|
||||||
if (a.HasValue)
|
if (a.HasValue)
|
||||||
{
|
{
|
||||||
a = new DateTime(a.Value.Year, a.Value.Month, 1);
|
a = new DateTime(a.Value.Year, a.Value.Month, 1);
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
namespace Connected.Components;
|
using Connected.Extensions;
|
||||||
|
|
||||||
|
namespace Connected.Components;
|
||||||
|
|
||||||
public class DateRange : Range<DateTime?>, IEquatable<DateRange>
|
public class DateRange : Range<DateTime?>, IEquatable<DateRange>
|
||||||
{
|
{
|
||||||
@ -15,7 +17,7 @@ public class DateRange : Range<DateTime?>, IEquatable<DateRange>
|
|||||||
if (Start == null || End == null)
|
if (Start == null || End == null)
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
|
||||||
return RangeConverter<DateTime>.Join(converter.Set(Start.Value), converter.Set(End.Value));
|
return RangeConverter<DateTime>.Join(converter.Convert(Start.Value), converter.Convert(End.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ToIsoDateString()
|
public string ToIsoDateString()
|
||||||
@ -40,12 +42,14 @@ public class DateRange : Range<DateTime?>, IEquatable<DateRange>
|
|||||||
{
|
{
|
||||||
date = null;
|
date = null;
|
||||||
|
|
||||||
var endDate = converter.Get(end);
|
var endDate = converter.ConvertBack(end);
|
||||||
if (converter.GetError)
|
|
||||||
|
if (endDate is null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var startDate = converter.Get(start);
|
var startDate = converter.ConvertBack(start);
|
||||||
if (converter.GetError)
|
|
||||||
|
if (startDate is null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
date = new DateRange(startDate, endDate);
|
date = new DateRange(startDate, endDate);
|
||||||
|
@ -6,13 +6,13 @@
|
|||||||
@code{
|
@code{
|
||||||
|
|
||||||
protected override RenderFragment InputContent=>
|
protected override RenderFragment InputContent=>
|
||||||
@<InputControl Label="@Label" Variant="@Variant" HelperText="@HelperText" Error="@Error"
|
@<InputControl Label="@Label" Variant="@Variant" HelperText="@HelperText" Error="@HasError"
|
||||||
ErrorText="@ErrorText" Disabled="@Disabled" Margin="@Margin" Required="@Required"
|
ErrorText="@ErrorText" Disabled="@Disabled" Margin="@Margin" Required="@Required"
|
||||||
@onclick="() => { if (!Editable) ToggleState(); }" ForId="@FieldId">
|
@onclick="() => { if (!Editable) ToggleState(); }" ForId="@FieldId">
|
||||||
<InputContent>
|
<InputContent>
|
||||||
<RangeInput @ref="_rangeInput" @attributes="UserAttributes" InputType="@InputType.Text" Class="@PickerInputClass" Style="@Style" Variant="@Variant" ReadOnly="@(!Editable)"
|
<RangeInput @ref="_rangeInput" @attributes="UserAttributes" InputType="@InputType.Text" Class="@PickerInputClass" Style="@Style" Variant="@Variant" ReadOnly="@(!Editable)"
|
||||||
@bind-Value="@RangeText" Disabled="@Disabled" Adornment="@Adornment" AdornmentIcon="@AdornmentIcon" AdornmentColor="@AdornmentColor" IconSize="@IconSize" OnAdornmentClick="ToggleState"
|
@bind-Value="@RangeText" Disabled="@Disabled" Adornment="@Adornment" AdornmentIcon="@AdornmentIcon" AdornmentColor="@AdornmentColor" IconSize="@IconSize" OnAdornmentClick="ToggleState"
|
||||||
Required="@Required" RequiredError="@RequiredError" Error="@Error" ErrorText="@ErrorText" Margin="@Margin" AdornmentAriaLabel="@AdornmentAriaLabel"/>
|
Required="@Required" RequiredError="@RequiredError" Error="@HasError" ErrorText="@ErrorText" Margin="@Margin" AdornmentAriaLabel="@AdornmentAriaLabel"/>
|
||||||
</InputContent>
|
</InputContent>
|
||||||
</InputControl>;
|
</InputControl>;
|
||||||
|
|
||||||
|
@ -57,7 +57,6 @@ public partial class DateRangePicker : DatePickerBase
|
|||||||
|
|
||||||
if (updateValue)
|
if (updateValue)
|
||||||
{
|
{
|
||||||
Converter.GetError = false;
|
|
||||||
if (_dateRange == null)
|
if (_dateRange == null)
|
||||||
{
|
{
|
||||||
_rangeText = null;
|
_rangeText = null;
|
||||||
@ -66,8 +65,8 @@ public partial class DateRangePicker : DatePickerBase
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_rangeText = new Range<string>(
|
_rangeText = new Range<string>(
|
||||||
Converter.Set(_dateRange.Start),
|
Converter.Convert(_dateRange.Start),
|
||||||
Converter.Set(_dateRange.End));
|
Converter.Convert(_dateRange.End));
|
||||||
await SetTextAsync(_dateRange.ToString(Converter), false);
|
await SetTextAsync(_dateRange.ToString(Converter), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,7 +84,7 @@ public partial class DateRangePicker : DatePickerBase
|
|||||||
if (_rangeText?.Equals(value) ?? value == null)
|
if (_rangeText?.Equals(value) ?? value == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Touched = true;
|
Modified = true;
|
||||||
_rangeText = value;
|
_rangeText = value;
|
||||||
SetDateRangeAsync(ParseDateRangeValue(value?.Start, value?.End), false).AndForget();
|
SetDateRangeAsync(ParseDateRangeValue(value?.Start, value?.End), false).AndForget();
|
||||||
}
|
}
|
||||||
@ -135,13 +134,13 @@ public partial class DateRangePicker : DatePickerBase
|
|||||||
|
|
||||||
protected override Task DateFormatChanged(string newFormat)
|
protected override Task DateFormatChanged(string newFormat)
|
||||||
{
|
{
|
||||||
Touched = true;
|
Modified = true;
|
||||||
return SetTextAsync(_dateRange?.ToString(Converter), false);
|
return SetTextAsync(_dateRange?.ToString(Converter), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Task StringValueChanged(string value)
|
protected override Task StringValueChanged(string value)
|
||||||
{
|
{
|
||||||
Touched = true;
|
Modified = true;
|
||||||
// Update the daterange property (without updating back the Value property)
|
// Update the daterange property (without updating back the Value property)
|
||||||
return SetDateRangeAsync(ParseDateRangeValue(value), false);
|
return SetDateRangeAsync(ParseDateRangeValue(value), false);
|
||||||
}
|
}
|
||||||
|
@ -109,14 +109,14 @@ public partial class FileUpload<T> : FormComponent<T, string>
|
|||||||
await FilesChanged.InvokeAsync(_value);
|
await FilesChanged.InvokeAsync(_value);
|
||||||
BeginValidate();
|
BeginValidate();
|
||||||
FieldChanged(_value);
|
FieldChanged(_value);
|
||||||
if (!Error || !SuppressOnChangeWhenInvalid) //only trigger FilesChanged if validation passes or SuppressOnChangeWhenInvalid is false
|
if (!HasError || !SuppressOnChangeWhenInvalid) //only trigger FilesChanged if validation passes or SuppressOnChangeWhenInvalid is false
|
||||||
await OnFilesChanged.InvokeAsync(args);
|
await OnFilesChanged.InvokeAsync(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
if (!(typeof(T) == typeof(IReadOnlyList<IBrowserFile>) || typeof(T) == typeof(IBrowserFile)))
|
//if (!(typeof(T) == typeof(IReadOnlyList<IBrowserFile>) || typeof(T) == typeof(IBrowserFile)))
|
||||||
Logger.LogWarning("T must be of type {type1} or {type2}", typeof(IReadOnlyList<IBrowserFile>), typeof(IBrowserFile));
|
// Logger.LogWarning("T must be of type {type1} or {type2}", typeof(IReadOnlyList<IBrowserFile>), typeof(IBrowserFile));
|
||||||
|
|
||||||
base.OnInitialized();
|
base.OnInitialized();
|
||||||
}
|
}
|
||||||
|
@ -206,11 +206,11 @@ public partial class Form : UIComponent, IDisposable, IForm
|
|||||||
// - none have an error
|
// - none have an error
|
||||||
// - all required fields have been touched (and thus validated)
|
// - all required fields have been touched (and thus validated)
|
||||||
var no_errors = _formControls.All(x => x.HasErrors == false);
|
var no_errors = _formControls.All(x => x.HasErrors == false);
|
||||||
var required_all_touched = _formControls.Where(x => x.Required).All(x => x.Touched);
|
var required_all_touched = _formControls.Where(x => x.Required).All(x => x.Modified);
|
||||||
var valid = no_errors && required_all_touched;
|
var valid = no_errors && required_all_touched;
|
||||||
|
|
||||||
var old_touched = _touched;
|
var old_touched = _touched;
|
||||||
_touched = _formControls.Any(x => x.Touched);
|
_touched = _formControls.Any(x => x.Modified);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_shouldRender = false;
|
_shouldRender = false;
|
||||||
|
@ -14,13 +14,19 @@ public abstract class FormComponent<T, U> : UIComponent, IFormComponent, IDispos
|
|||||||
{
|
{
|
||||||
private Converter<T, U> _converter;
|
private Converter<T, U> _converter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked whenever the string value cannot be converted
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<string> ConversionErrorOccured;
|
||||||
|
|
||||||
protected FormComponent(Converter<T, U> converter)
|
protected FormComponent(Converter<T, U> converter)
|
||||||
{
|
{
|
||||||
_converter = converter ?? throw new ArgumentNullException(nameof(converter));
|
_converter = converter ?? throw new ArgumentNullException(nameof(converter));
|
||||||
_converter.OnError = OnConversionError;
|
_converter.ErrorOccured += (s, e) => OnConversionError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
[CascadingParameter] internal IForm Form { get; set; }
|
[CascadingParameter]
|
||||||
|
internal IForm? Form { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If true, this is a top-level form component. If false, this input is a sub-component of another input (i.e. TextField, Select, etc).
|
/// If true, this is a top-level form component. If false, this input is a sub-component of another input (i.e. TextField, Select, etc).
|
||||||
@ -33,77 +39,77 @@ public abstract class FormComponent<T, U> : UIComponent, IFormComponent, IDispos
|
|||||||
/// If true, this form input is required to be filled out.
|
/// If true, this form input is required to be filled out.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
[Category(CategoryTypes.FormComponent.Validation)]
|
|
||||||
public bool Required { get; set; }
|
public bool Required { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The error text that will be displayed if the input is not filled out but required.
|
/// The error text that will be displayed if the input is not filled out but required.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
[Category(CategoryTypes.FormComponent.Validation)]
|
|
||||||
public string RequiredError { get; set; } = "Required";
|
public string RequiredError { get; set; } = "Required";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The ErrorText that will be displayed if Error true.
|
/// The ErrorText that will be displayed if <see cref="HasError"/> is set to true.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
[Category(CategoryTypes.FormComponent.Validation)]
|
|
||||||
public string ErrorText { get; set; }
|
public string ErrorText { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If true, the label will be displayed in an error state.
|
/// If true, the label will be displayed in an error state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
[Category(CategoryTypes.FormComponent.Validation)]
|
public bool HasError { get; set; }
|
||||||
public bool Error { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The ErrorId that will be used by aria-describedby if Error true
|
/// The ErrorId that will be used by aria-describedby if <see cref="HasError"/> is true
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
[Category(CategoryTypes.FormComponent.Validation)]
|
|
||||||
public string ErrorId { get; set; }
|
public string ErrorId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The generic converter of the component.
|
/// The generic converter of the component.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
[Category(CategoryTypes.FormComponent.Behavior)]
|
|
||||||
public Converter<T, U> Converter
|
public Converter<T, U> Converter
|
||||||
{
|
{
|
||||||
get => _converter;
|
get => _converter;
|
||||||
set => SetConverter(value);
|
set => SetConverter(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual bool SetConverter(Converter<T, U> value)
|
|
||||||
{
|
|
||||||
var changed = (_converter != value);
|
|
||||||
if (changed)
|
|
||||||
{
|
|
||||||
_converter = value ?? throw new ArgumentNullException(nameof(value)); // converter is mandatory at all times
|
|
||||||
_converter.OnError = OnConversionError;
|
|
||||||
}
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The culture of the component.
|
/// The culture of the component. Also sets the culture of the <see cref="Converter"/> .
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
[Category(CategoryTypes.FormComponent.Behavior)]
|
|
||||||
public CultureInfo Culture
|
public CultureInfo Culture
|
||||||
{
|
{
|
||||||
get => _converter.Culture;
|
get => _converter.Culture;
|
||||||
set => SetCulture(value);
|
set => SetCulture(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual bool SetCulture(CultureInfo value)
|
private string _conversionError { get; set; }
|
||||||
|
|
||||||
|
protected virtual bool SetConverter(Converter<T, U> value)
|
||||||
{
|
{
|
||||||
var changed = (_converter.Culture != value);
|
var changed = _converter != value;
|
||||||
|
|
||||||
if (changed)
|
if (changed)
|
||||||
{
|
{
|
||||||
_converter.Culture = value;
|
/*
|
||||||
|
* Converter is mandatory at all times
|
||||||
|
*/
|
||||||
|
_converter = value ?? throw new ArgumentNullException(nameof(value));
|
||||||
|
_converter.ErrorOccured += (s, e) => OnConversionError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual bool SetCulture(CultureInfo value)
|
||||||
|
{
|
||||||
|
var changed = _converter.Culture != value;
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
_converter.Culture = value;
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,37 +117,38 @@ public abstract class FormComponent<T, U> : UIComponent, IFormComponent, IDispos
|
|||||||
{
|
{
|
||||||
// note: we need to update the form here because the conversion error might lead to not updating the value
|
// note: we need to update the form here because the conversion error might lead to not updating the value
|
||||||
// ... which leads to not updating the form
|
// ... which leads to not updating the form
|
||||||
Touched = true;
|
|
||||||
Form?.Update(this);
|
|
||||||
OnConversionErrorOccurred(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnConversionErrorOccurred(string error)
|
//TODO Why does the form need to be updated?
|
||||||
{
|
Modified = true;
|
||||||
/* Descendants can override this method to catch conversion errors */
|
|
||||||
|
_conversionError = error;
|
||||||
|
|
||||||
|
Form?.Update(this);
|
||||||
|
|
||||||
|
ConversionErrorOccured?.Invoke(this, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// True if the conversion from string to T failed
|
/// True if the conversion from string to T failed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ConversionError => _converter.GetError;
|
public bool ConversionError => !string.IsNullOrWhiteSpace(_conversionError);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The error message of the conversion error from string to T. Null otherwise
|
/// The error message of the conversion error from string to T. Null otherwise
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ConversionErrorMessage => _converter.GetErrorMessage;
|
public string ConversionErrorMessage => _conversionError;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// True if the input has any of the following errors: An error set from outside, a conversion error or
|
/// True if the input has any of the following errors: An error set from outside, a conversion error or
|
||||||
/// one or more validation errors
|
/// one or more validation errors
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HasErrors => Error || ConversionError || ValidationErrors.Count > 0;
|
public bool HasErrors => HasError || ConversionError || ValidationErrors.Count > 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Return the validation error text or the conversion error message.
|
/// Return the validation error text or the conversion error message.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Error text/message</returns>
|
/// <returns>Error text/message</returns>
|
||||||
public string GetErrorText()
|
public string? GetErrorText()
|
||||||
{
|
{
|
||||||
// ErrorText is either set from outside or the first validation error
|
// ErrorText is either set from outside or the first validation error
|
||||||
if (!IsNullOrWhiteSpace(ErrorText))
|
if (!IsNullOrWhiteSpace(ErrorText))
|
||||||
@ -154,13 +161,13 @@ public abstract class FormComponent<T, U> : UIComponent, IFormComponent, IDispos
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This manages the state of having been "touched" by the user. A form control always starts out untouched
|
/// This manages the state of having been modified by the user. A form control always starts out unmodified
|
||||||
/// but becomes touched when the user performed input or the blur event was raised.
|
/// but becomes modified when the user performed input or the blur event was raised.
|
||||||
///
|
///
|
||||||
/// The touched state is only relevant for inputs that have no value (i.e. empty text fields). Being untouched will
|
/// The modified state is only relevant for inputs that have no value (i.e. empty text fields). Being unmodified will
|
||||||
/// suppress RequiredError
|
/// suppress the display of the <see cref="RequiredError"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Touched { get; protected set; }
|
public bool Modified { get; protected set; }
|
||||||
|
|
||||||
#region MudForm Validation
|
#region MudForm Validation
|
||||||
|
|
||||||
@ -182,10 +189,20 @@ public abstract class FormComponent<T, U> : UIComponent, IFormComponent, IDispos
|
|||||||
[Category(CategoryTypes.FormComponent.Validation)]
|
[Category(CategoryTypes.FormComponent.Validation)]
|
||||||
public object Validation { get; set; }
|
public object Validation { get; set; }
|
||||||
|
|
||||||
|
private T __value;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is the form component's value.
|
/// This is the form component's value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected T _value;
|
protected T _value
|
||||||
|
{
|
||||||
|
get => __value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
__value = value;
|
||||||
|
_conversionError = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// These are the fire-and-forget methods to launch an async validation process.
|
// These are the fire-and-forget methods to launch an async validation process.
|
||||||
// After each async step, we make sure the current Value of the component has not changed while
|
// After each async step, we make sure the current Value of the component has not changed while
|
||||||
@ -232,7 +249,7 @@ public abstract class FormComponent<T, U> : UIComponent, IFormComponent, IDispos
|
|||||||
// when a validation is forced, we must set Touched to true, because for untouched fields with
|
// when a validation is forced, we must set Touched to true, because for untouched fields with
|
||||||
// no value, validation does nothing due to the way forms are expected to work (display errors
|
// no value, validation does nothing due to the way forms are expected to work (display errors
|
||||||
// only after fields have been touched).
|
// only after fields have been touched).
|
||||||
Touched = true;
|
Modified = true;
|
||||||
return ValidateValue();
|
return ValidateValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,7 +301,7 @@ public abstract class FormComponent<T, U> : UIComponent, IFormComponent, IDispos
|
|||||||
// required error (must be last, because it is least important!)
|
// required error (must be last, because it is least important!)
|
||||||
if (Required)
|
if (Required)
|
||||||
{
|
{
|
||||||
if (Touched && !HasValue(_value))
|
if (Modified && !HasValue(_value))
|
||||||
errors.Add(RequiredError);
|
errors.Add(RequiredError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -297,7 +314,7 @@ public abstract class FormComponent<T, U> : UIComponent, IFormComponent, IDispos
|
|||||||
// if Error and ErrorText are set by the user, setting them here will have no effect.
|
// if Error and ErrorText are set by the user, setting them here will have no effect.
|
||||||
// if Error, create an error id that can be used by aria-describedby on input control
|
// if Error, create an error id that can be used by aria-describedby on input control
|
||||||
ValidationErrors = errors;
|
ValidationErrors = errors;
|
||||||
Error = errors.Count > 0;
|
HasError = errors.Count > 0;
|
||||||
ErrorText = errors.FirstOrDefault();
|
ErrorText = errors.FirstOrDefault();
|
||||||
ErrorId = HasErrors ? Guid.NewGuid().ToString() : null;
|
ErrorId = HasErrors ? Guid.NewGuid().ToString() : null;
|
||||||
Form?.Update(this);
|
Form?.Update(this);
|
||||||
@ -487,7 +504,8 @@ public abstract class FormComponent<T, U> : UIComponent, IFormComponent, IDispos
|
|||||||
{
|
{
|
||||||
/* to be overridden */
|
/* to be overridden */
|
||||||
_value = default;
|
_value = default;
|
||||||
Touched = false;
|
_conversionError = null;
|
||||||
|
Modified = false;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,7 +514,7 @@ public abstract class FormComponent<T, U> : UIComponent, IFormComponent, IDispos
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void ResetValidation()
|
public void ResetValidation()
|
||||||
{
|
{
|
||||||
Error = false;
|
HasError = false;
|
||||||
ValidationErrors.Clear();
|
ValidationErrors.Clear();
|
||||||
ErrorText = null;
|
ErrorText = null;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
@ -527,28 +545,26 @@ public abstract class FormComponent<T, U> : UIComponent, IFormComponent, IDispos
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Specify an expression which returns the model's field for which validation messages should be displayed.
|
/// Specify an expression which returns the model's field for which validation messages should be displayed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#nullable enable
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
[Category(CategoryTypes.FormComponent.Validation)]
|
|
||||||
public Expression<Func<T>>? For { get; set; }
|
public Expression<Func<T>>? For { get; set; }
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
public bool IsForNull => For == null;
|
public bool IsForNull => For == null;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stores the list of validation attributes attached to the property targeted by <seealso cref="For"/>. If <seealso cref="For"/> is null, this property is null too.
|
/// Stores the list of validation attributes attached to the property targeted by <seealso cref="For"/>. If <seealso cref="For"/> is null, this property is null too.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#nullable enable
|
|
||||||
private IEnumerable<ValidationAttribute>? _validationAttrsFor;
|
private IEnumerable<ValidationAttribute>? _validationAttrsFor;
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
private void OnValidationStateChanged(object sender, ValidationStateChangedEventArgs e)
|
private void OnValidationStateChanged(object sender, ValidationStateChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (EditContext != null && !_fieldIdentifier.Equals(default(FieldIdentifier)))
|
if (EditContext != null && !_fieldIdentifier.Equals(default(FieldIdentifier)))
|
||||||
{
|
{
|
||||||
var error_msgs = EditContext.GetValidationMessages(_fieldIdentifier).ToArray();
|
var error_msgs = EditContext.GetValidationMessages(_fieldIdentifier).ToArray();
|
||||||
Error = error_msgs.Length > 0;
|
HasError = error_msgs.Length > 0;
|
||||||
ErrorText = (Error ? error_msgs[0] : null);
|
ErrorText = (HasError ? error_msgs[0] : null);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -561,16 +577,13 @@ public abstract class FormComponent<T, U> : UIComponent, IFormComponent, IDispos
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// To find out whether or not For parameter has changed we keep a separate reference
|
/// To find out whether or not For parameter has changed we keep a separate reference
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#nullable enable
|
|
||||||
private Expression<Func<T>>? _currentFor;
|
private Expression<Func<T>>? _currentFor;
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// To find out whether or not EditContext parameter has changed we keep a separate reference
|
/// To find out whether or not EditContext parameter has changed we keep a separate reference
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#nullable enable
|
|
||||||
private EditContext? _currentEditContext;
|
private EditContext? _currentEditContext;
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
public interface IFormComponent
|
public interface IFormComponent
|
||||||
{
|
{
|
||||||
public bool Required { get; set; }
|
public bool Required { get; set; }
|
||||||
public bool Error { get; set; }
|
public bool HasError { get; set; }
|
||||||
public bool HasErrors { get; }
|
public bool HasErrors { get; }
|
||||||
public bool Touched { get; }
|
public bool Modified { get; }
|
||||||
public object Validation { get; set; }
|
public object Validation { get; set; }
|
||||||
public bool IsForNull { get; }
|
public bool IsForNull { get; }
|
||||||
public List<string> ValidationErrors { get; set; }
|
public List<string> ValidationErrors { get; set; }
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
@onkeyup:preventDefault="@KeyUpPreventDefault"
|
@onkeyup:preventDefault="@KeyUpPreventDefault"
|
||||||
@onmousewheel="@OnMouseWheel"
|
@onmousewheel="@OnMouseWheel"
|
||||||
@onwheel="@OnMouseWheel"
|
@onwheel="@OnMouseWheel"
|
||||||
aria-invalid="@Error.ToString().ToLower()"
|
aria-invalid="@HasError.ToString().ToLower()"
|
||||||
aria-describedby="@ErrorId"
|
aria-describedby="@ErrorId"
|
||||||
>
|
>
|
||||||
@Text
|
@Text
|
||||||
@ -73,7 +73,7 @@
|
|||||||
@onkeyup:preventDefault="@KeyUpPreventDefault"
|
@onkeyup:preventDefault="@KeyUpPreventDefault"
|
||||||
@onmousewheel="@OnMouseWheel"
|
@onmousewheel="@OnMouseWheel"
|
||||||
@onwheel="@OnMouseWheel"
|
@onwheel="@OnMouseWheel"
|
||||||
aria-invalid="@Error.ToString().ToLower()"
|
aria-invalid="@HasError.ToString().ToLower()"
|
||||||
aria-describedby="@ErrorId"
|
aria-describedby="@ErrorId"
|
||||||
/>
|
/>
|
||||||
@*Note: double mouse wheel handlers needed for Firefox because it doesn't know onmousewheel*@
|
@*Note: double mouse wheel handlers needed for Firefox because it doesn't know onmousewheel*@
|
||||||
|
@ -215,7 +215,7 @@ public abstract class InputBase<T> : FormComponent<T, string>
|
|||||||
{
|
{
|
||||||
Text = text;
|
Text = text;
|
||||||
if (!string.IsNullOrWhiteSpace(Text))
|
if (!string.IsNullOrWhiteSpace(Text))
|
||||||
Touched = true;
|
Modified = true;
|
||||||
if (updateValue)
|
if (updateValue)
|
||||||
await UpdateValuePropertyAsync(false);
|
await UpdateValuePropertyAsync(false);
|
||||||
await TextChanged.InvokeAsync(Text);
|
await TextChanged.InvokeAsync(Text);
|
||||||
@ -227,7 +227,7 @@ public abstract class InputBase<T> : FormComponent<T, string>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual Task UpdateTextPropertyAsync(bool updateValue)
|
protected virtual Task UpdateTextPropertyAsync(bool updateValue)
|
||||||
{
|
{
|
||||||
return SetTextAsync(Converter.Set(Value), updateValue);
|
return SetTextAsync(Converter.Convert(Value), updateValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -266,7 +266,7 @@ public abstract class InputBase<T> : FormComponent<T, string>
|
|||||||
|
|
||||||
if (!OnlyValidateIfDirty || _isDirty)
|
if (!OnlyValidateIfDirty || _isDirty)
|
||||||
{
|
{
|
||||||
Touched = true;
|
Modified = true;
|
||||||
BeginValidateAfter(OnBlur.InvokeAsync(obj));
|
BeginValidateAfter(OnBlur.InvokeAsync(obj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -361,7 +361,7 @@ public abstract class InputBase<T> : FormComponent<T, string>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual Task UpdateValuePropertyAsync(bool updateText)
|
protected virtual Task UpdateValuePropertyAsync(bool updateText)
|
||||||
{
|
{
|
||||||
return SetValueAsync(Converter.Get(Text), updateText);
|
return SetValueAsync(Converter.ConvertBack(Text), updateText);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool SetConverter(Converter<T, string> value)
|
protected override bool SetConverter(Converter<T, string> value)
|
||||||
@ -389,7 +389,7 @@ public abstract class InputBase<T> : FormComponent<T, string>
|
|||||||
[Category(CategoryTypes.FormComponent.Behavior)]
|
[Category(CategoryTypes.FormComponent.Behavior)]
|
||||||
public string Format
|
public string Format
|
||||||
{
|
{
|
||||||
get => ((Converter<T>)Converter).Format;
|
get => ((ToStringConverter<T>)Converter).Format;
|
||||||
set => SetFormat(value);
|
set => SetFormat(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,7 +398,7 @@ public abstract class InputBase<T> : FormComponent<T, string>
|
|||||||
var changed = Format != value;
|
var changed = Format != value;
|
||||||
if (changed)
|
if (changed)
|
||||||
{
|
{
|
||||||
((Converter<T>)Converter).Format = value;
|
((ToStringConverter<T>)Converter).Format = value;
|
||||||
UpdateTextPropertyAsync(false).AndForget(); // refresh only Text property from current Value
|
UpdateTextPropertyAsync(false).AndForget(); // refresh only Text property from current Value
|
||||||
}
|
}
|
||||||
return changed;
|
return changed;
|
||||||
|
@ -238,7 +238,7 @@ public partial class Mask : InputBase<string>, IDisposable
|
|||||||
await base.SetTextAsync(text, updateValue: false);
|
await base.SetTextAsync(text, updateValue: false);
|
||||||
if (Clearable)
|
if (Clearable)
|
||||||
UpdateClearable(Text);
|
UpdateClearable(Text);
|
||||||
var v = Converter.Get(cleanText);
|
var v = Converter.ConvertBack(cleanText);
|
||||||
Value = v;
|
Value = v;
|
||||||
await ValueChanged.InvokeAsync(v);
|
await ValueChanged.InvokeAsync(v);
|
||||||
SetCaretPosition(caret, selection);
|
SetCaretPosition(caret, selection);
|
||||||
@ -262,7 +262,7 @@ public partial class Mask : InputBase<string>, IDisposable
|
|||||||
// allow this only via changes from the outside
|
// allow this only via changes from the outside
|
||||||
if (_updating)
|
if (_updating)
|
||||||
return;
|
return;
|
||||||
var text = Converter.Set(Value);
|
var text = Converter.Convert(Value);
|
||||||
var cleanText = MaskKind.GetCleanText();
|
var cleanText = MaskKind.GetCleanText();
|
||||||
if (cleanText == text || string.IsNullOrEmpty(cleanText) && string.IsNullOrEmpty(text))
|
if (cleanText == text || string.IsNullOrEmpty(cleanText) && string.IsNullOrEmpty(text))
|
||||||
return;
|
return;
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
AdornmentIcon="@AdornmentIcon"
|
AdornmentIcon="@AdornmentIcon"
|
||||||
AdornmentColor="@AdornmentColor"
|
AdornmentColor="@AdornmentColor"
|
||||||
IconSize="@IconSize"
|
IconSize="@IconSize"
|
||||||
Error="@Error"
|
Error="@HasError"
|
||||||
Immediate="@(Immediate)"
|
Immediate="@(Immediate)"
|
||||||
Margin="@Margin"
|
Margin="@Margin"
|
||||||
MaxLength="@MaxLength"
|
MaxLength="@MaxLength"
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
Margin="@Margin"
|
Margin="@Margin"
|
||||||
Required="@Required"
|
Required="@Required"
|
||||||
RequiredError="@RequiredError"
|
RequiredError="@RequiredError"
|
||||||
Error="@Error"
|
Error="@HasError"
|
||||||
ErrorText="@ErrorText"
|
ErrorText="@ErrorText"
|
||||||
Clearable="@(ReadOnly ? false : Clearable)"
|
Clearable="@(ReadOnly ? false : Clearable)"
|
||||||
OnClearButtonClick="@(() => Clear())"
|
OnClearButtonClick="@(() => Clear())"
|
||||||
|
@ -81,7 +81,7 @@ public partial class RadioGroup<T> : FormComponent<T, T>, IRadioGroup
|
|||||||
|
|
||||||
internal Task SetSelectedRadioAsync(Radio<T> radio)
|
internal Task SetSelectedRadioAsync(Radio<T> radio)
|
||||||
{
|
{
|
||||||
Touched = true;
|
Modified = true;
|
||||||
return SetSelectedRadioAsync(radio, true);
|
return SetSelectedRadioAsync(radio, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,14 +5,14 @@
|
|||||||
<CascadingValue Name="SubscribeToParentForm" Value="false" IsFixed="true">
|
<CascadingValue Name="SubscribeToParentForm" Value="false" IsFixed="true">
|
||||||
<div class="mud-select" id="@_elementId">
|
<div class="mud-select" id="@_elementId">
|
||||||
<InputControl Label="@Label" Variant="@Variant" HelperText="@HelperText" HelperTextOnFocus="@HelperTextOnFocus" FullWidth="@FullWidth" Margin="@Margin" Class="@Classname" Style="@Style"
|
<InputControl Label="@Label" Variant="@Variant" HelperText="@HelperText" HelperTextOnFocus="@HelperTextOnFocus" FullWidth="@FullWidth" Margin="@Margin" Class="@Classname" Style="@Style"
|
||||||
Error="@Error" ErrorText="@ErrorText" ErrorId="@ErrorId" Disabled="@Disabled" @onclick="@ToggleMenu" Required="@Required" ForId="@FieldId">
|
Error="@HasError" ErrorText="@ErrorText" ErrorId="@ErrorId" Disabled="@Disabled" @onclick="@ToggleMenu" Required="@Required" ForId="@FieldId">
|
||||||
<InputContent>
|
<InputContent>
|
||||||
<Input @ref="_elementReference" InputType="@(CanRenderValue || (Strict && !IsValueInList) ? InputType.Hidden : InputType.Text)"
|
<Input @ref="_elementReference" InputType="@(CanRenderValue || (Strict && !IsValueInList) ? InputType.Hidden : InputType.Text)"
|
||||||
Class="mud-select-input" Margin="@Margin" Placeholder="@Placeholder"
|
Class="mud-select-input" Margin="@Margin" Placeholder="@Placeholder"
|
||||||
Variant="@Variant"
|
Variant="@Variant"
|
||||||
TextUpdateSuppression="false"
|
TextUpdateSuppression="false"
|
||||||
Value="@(Strict && !IsValueInList ? null : Text)" DisableUnderLine="@DisableUnderLine"
|
Value="@(Strict && !IsValueInList ? null : Text)" DisableUnderLine="@DisableUnderLine"
|
||||||
Disabled="@Disabled" ReadOnly="true" Error="@Error" ErrorId="@ErrorId"
|
Disabled="@Disabled" ReadOnly="true" Error="@HasError" ErrorId="@ErrorId"
|
||||||
OnAdornmentClick="@OnAdornmentClick" AdornmentIcon="@_currentIcon" Adornment="@Adornment"
|
OnAdornmentClick="@OnAdornmentClick" AdornmentIcon="@_currentIcon" Adornment="@Adornment"
|
||||||
AdornmentColor="@AdornmentColor" IconSize="@IconSize" AdornmentText="@AdornmentText"
|
AdornmentColor="@AdornmentColor" IconSize="@IconSize" AdornmentText="@AdornmentText"
|
||||||
Clearable="@Clearable" OnClearButtonClick="(async (e) => await SelectClearButtonClickHandlerAsync(e))"
|
Clearable="@Clearable" OnClearButtonClick="(async (e) => await SelectClearButtonClickHandlerAsync(e))"
|
||||||
|
@ -86,12 +86,12 @@ public partial class Select<T> : InputBase<T>, ISelect, IShadowSelect
|
|||||||
// find first item that starts with the letter
|
// find first item that starts with the letter
|
||||||
var currentItem = items.FirstOrDefault(x => x.ItemId == (string)_activeItemId);
|
var currentItem = items.FirstOrDefault(x => x.ItemId == (string)_activeItemId);
|
||||||
if (currentItem != null &&
|
if (currentItem != null &&
|
||||||
Converter.Set(currentItem.Value)?.ToLowerInvariant().StartsWith(startChar) == true)
|
Converter.Convert(currentItem.Value)?.ToLowerInvariant().StartsWith(startChar) == true)
|
||||||
{
|
{
|
||||||
// this will step through all items that start with the same letter if pressed multiple times
|
// this will step through all items that start with the same letter if pressed multiple times
|
||||||
items = items.SkipWhile(x => x != currentItem).Skip(1);
|
items = items.SkipWhile(x => x != currentItem).Skip(1);
|
||||||
}
|
}
|
||||||
items = items.Where(x => Converter.Set(x.Value)?.ToLowerInvariant().StartsWith(startChar) == true);
|
items = items.Where(x => Converter.Convert(x.Value)?.ToLowerInvariant().StartsWith(startChar) == true);
|
||||||
}
|
}
|
||||||
var item = items.FirstOrDefault();
|
var item = items.FirstOrDefault();
|
||||||
if (item == null)
|
if (item == null)
|
||||||
@ -244,13 +244,13 @@ public partial class Select<T> : InputBase<T>, ISelect, IShadowSelect
|
|||||||
//Warning. Here the Converter was not set yet
|
//Warning. Here the Converter was not set yet
|
||||||
if (MultiSelectionTextFunc != null)
|
if (MultiSelectionTextFunc != null)
|
||||||
{
|
{
|
||||||
SetCustomizedTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Set(x))),
|
SetCustomizedTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Convert(x))),
|
||||||
selectedConvertedValues: SelectedValues.Select(x => Converter.Set(x)).ToList(),
|
selectedConvertedValues: SelectedValues.Select(x => Converter.Convert(x)).ToList(),
|
||||||
multiSelectionTextFunc: MultiSelectionTextFunc).AndForget();
|
multiSelectionTextFunc: MultiSelectionTextFunc).AndForget();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SetTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Set(x))), updateValue: false).AndForget();
|
SetTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Convert(x))), updateValue: false).AndForget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SelectedValuesChanged.InvokeAsync(new HashSet<T>(SelectedValues, _comparer));
|
SelectedValuesChanged.InvokeAsync(new HashSet<T>(SelectedValues, _comparer));
|
||||||
@ -293,11 +293,7 @@ public partial class Select<T> : InputBase<T>, ISelect, IShadowSelect
|
|||||||
if (_toStringFunc == value)
|
if (_toStringFunc == value)
|
||||||
return;
|
return;
|
||||||
_toStringFunc = value;
|
_toStringFunc = value;
|
||||||
Converter = new Converter<T>
|
Converter = new LambdaConverter<T, string>(_toStringFunc ?? (x => x?.ToString()), null);
|
||||||
{
|
|
||||||
SetFunc = _toStringFunc ?? (x => x?.ToString()),
|
|
||||||
//GetFunc = LookupValue,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,15 +389,15 @@ public partial class Select<T> : InputBase<T>, ISelect, IShadowSelect
|
|||||||
if (MultiSelectionTextFunc != null)
|
if (MultiSelectionTextFunc != null)
|
||||||
{
|
{
|
||||||
return MultiSelection
|
return MultiSelection
|
||||||
? SetCustomizedTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Set(x))),
|
? SetCustomizedTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Convert(x))),
|
||||||
selectedConvertedValues: SelectedValues.Select(x => Converter.Set(x)).ToList(),
|
selectedConvertedValues: SelectedValues.Select(x => Converter.Convert(x)).ToList(),
|
||||||
multiSelectionTextFunc: MultiSelectionTextFunc)
|
multiSelectionTextFunc: MultiSelectionTextFunc)
|
||||||
: base.UpdateTextPropertyAsync(updateValue);
|
: base.UpdateTextPropertyAsync(updateValue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return MultiSelection
|
return MultiSelection
|
||||||
? SetTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Set(x))))
|
? SetTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Convert(x))))
|
||||||
: base.UpdateTextPropertyAsync(updateValue);
|
: base.UpdateTextPropertyAsync(updateValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -568,13 +564,13 @@ public partial class Select<T> : InputBase<T>, ISelect, IShadowSelect
|
|||||||
|
|
||||||
if (MultiSelectionTextFunc != null)
|
if (MultiSelectionTextFunc != null)
|
||||||
{
|
{
|
||||||
await SetCustomizedTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Set(x))),
|
await SetCustomizedTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Convert(x))),
|
||||||
selectedConvertedValues: SelectedValues.Select(x => Converter.Set(x)).ToList(),
|
selectedConvertedValues: SelectedValues.Select(x => Converter.Convert(x)).ToList(),
|
||||||
multiSelectionTextFunc: MultiSelectionTextFunc);
|
multiSelectionTextFunc: MultiSelectionTextFunc);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await SetTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Set(x))), updateValue: false);
|
await SetTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Convert(x))), updateValue: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateSelectAllChecked();
|
UpdateSelectAllChecked();
|
||||||
@ -811,7 +807,7 @@ public partial class Select<T> : InputBase<T>, ISelect, IShadowSelect
|
|||||||
{
|
{
|
||||||
multiSelectionText = text;
|
multiSelectionText = text;
|
||||||
if (!string.IsNullOrWhiteSpace(multiSelectionText))
|
if (!string.IsNullOrWhiteSpace(multiSelectionText))
|
||||||
Touched = true;
|
Modified = true;
|
||||||
if (updateValue)
|
if (updateValue)
|
||||||
await UpdateValuePropertyAsync(false);
|
await UpdateValuePropertyAsync(false);
|
||||||
await TextChanged.InvokeAsync(multiSelectionText);
|
await TextChanged.InvokeAsync(multiSelectionText);
|
||||||
@ -1004,13 +1000,13 @@ public partial class Select<T> : InputBase<T>, ISelect, IShadowSelect
|
|||||||
_selectedValues = new HashSet<T>(selectedValues, _comparer);
|
_selectedValues = new HashSet<T>(selectedValues, _comparer);
|
||||||
if (MultiSelectionTextFunc != null)
|
if (MultiSelectionTextFunc != null)
|
||||||
{
|
{
|
||||||
await SetCustomizedTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Set(x))),
|
await SetCustomizedTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Convert(x))),
|
||||||
selectedConvertedValues: SelectedValues.Select(x => Converter.Set(x)).ToList(),
|
selectedConvertedValues: SelectedValues.Select(x => Converter.Convert(x)).ToList(),
|
||||||
multiSelectionTextFunc: MultiSelectionTextFunc);
|
multiSelectionTextFunc: MultiSelectionTextFunc);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await SetTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Set(x))), updateValue: false);
|
await SetTextAsync(string.Join(Delimiter, SelectedValues.Select(x => Converter.Convert(x))), updateValue: false);
|
||||||
}
|
}
|
||||||
UpdateSelectAllChecked();
|
UpdateSelectAllChecked();
|
||||||
_selectedValues = selectedValues; // need to force selected values because Blazor overwrites it under certain circumstances due to changes of Text or Value
|
_selectedValues = selectedValues; // need to force selected values because Blazor overwrites it under certain circumstances due to changes of Text or Value
|
||||||
|
@ -129,7 +129,7 @@ public partial class SelectItem<T> : SelectItemBase, IDisposable
|
|||||||
var converter = Select?.Converter;
|
var converter = Select?.Converter;
|
||||||
if (converter == null)
|
if (converter == null)
|
||||||
return $"{Value}";
|
return $"{Value}";
|
||||||
return converter.Set(Value);
|
return converter.Convert(Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,8 +28,8 @@ public partial class Slider<T> : UIComponent
|
|||||||
[Category(CategoryTypes.Slider.Validation)]
|
[Category(CategoryTypes.Slider.Validation)]
|
||||||
public T Min
|
public T Min
|
||||||
{
|
{
|
||||||
get => Converter.Get(_min);
|
get => Converter.ConvertBack(_min);
|
||||||
set => _min = Converter.Set(value);
|
set => _min = Converter.Convert(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -40,8 +40,8 @@ public partial class Slider<T> : UIComponent
|
|||||||
[Category(CategoryTypes.Slider.Validation)]
|
[Category(CategoryTypes.Slider.Validation)]
|
||||||
public T Max
|
public T Max
|
||||||
{
|
{
|
||||||
get => Converter.Get(_max);
|
get => Converter.ConvertBack(_max);
|
||||||
set => _max = Converter.Set(value);
|
set => _max = Converter.Convert(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -52,8 +52,8 @@ public partial class Slider<T> : UIComponent
|
|||||||
[Category(CategoryTypes.Slider.Validation)]
|
[Category(CategoryTypes.Slider.Validation)]
|
||||||
public T Step
|
public T Step
|
||||||
{
|
{
|
||||||
get => Converter.Get(_step);
|
get => Converter.ConvertBack(_step);
|
||||||
set => _step = Converter.Set(value);
|
set => _step = Converter.Convert(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -73,7 +73,7 @@ public partial class Slider<T> : UIComponent
|
|||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
[Category(CategoryTypes.Slider.Behavior)]
|
[Category(CategoryTypes.Slider.Behavior)]
|
||||||
public Converter<T> Converter { get; set; } = new DefaultConverter<T>() { Culture = CultureInfo.InvariantCulture };
|
public ToStringConverter<T> Converter { get; set; } = new DefaultConverter<T>() { Culture = CultureInfo.InvariantCulture };
|
||||||
|
|
||||||
[Parameter] public EventCallback<T> ValueChanged { get; set; }
|
[Parameter] public EventCallback<T> ValueChanged { get; set; }
|
||||||
|
|
||||||
@ -81,10 +81,10 @@ public partial class Slider<T> : UIComponent
|
|||||||
[Category(CategoryTypes.Slider.Data)]
|
[Category(CategoryTypes.Slider.Data)]
|
||||||
public T Value
|
public T Value
|
||||||
{
|
{
|
||||||
get => Converter.Get(_value);
|
get => Converter.ConvertBack(_value);
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
var d = Converter.Set(value);
|
var d = Converter.Convert(value);
|
||||||
if (_value == d)
|
if (_value == d)
|
||||||
return;
|
return;
|
||||||
_value = d;
|
_value = d;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
HelperTextOnFocus="@HelperTextOnFocus"
|
HelperTextOnFocus="@HelperTextOnFocus"
|
||||||
CounterText="@GetCounterText()"
|
CounterText="@GetCounterText()"
|
||||||
FullWidth="@FullWidth"
|
FullWidth="@FullWidth"
|
||||||
Class="@Classname"
|
Class="@ClassList"
|
||||||
Error="@HasErrors"
|
Error="@HasErrors"
|
||||||
ErrorText="@GetErrorText()"
|
ErrorText="@GetErrorText()"
|
||||||
ErrorId="@ErrorId"
|
ErrorId="@ErrorId"
|
||||||
@ -43,7 +43,7 @@
|
|||||||
AdornmentAriaLabel="@AdornmentAriaLabel"
|
AdornmentAriaLabel="@AdornmentAriaLabel"
|
||||||
IconSize="@IconSize"
|
IconSize="@IconSize"
|
||||||
OnAdornmentClick="@OnAdornmentClick"
|
OnAdornmentClick="@OnAdornmentClick"
|
||||||
Error="@Error"
|
Error="@HasError"
|
||||||
ErrorId="@ErrorId"
|
ErrorId="@ErrorId"
|
||||||
Immediate="@Immediate"
|
Immediate="@Immediate"
|
||||||
Margin="@Margin"
|
Margin="@Margin"
|
||||||
@ -83,7 +83,7 @@
|
|||||||
AdornmentColor="@AdornmentColor"
|
AdornmentColor="@AdornmentColor"
|
||||||
IconSize="@IconSize"
|
IconSize="@IconSize"
|
||||||
OnAdornmentClick="@OnAdornmentClick"
|
OnAdornmentClick="@OnAdornmentClick"
|
||||||
Error="@Error"
|
Error="@HasError"
|
||||||
Immediate="@Immediate"
|
Immediate="@Immediate"
|
||||||
Margin="@Margin" OnBlur="@OnBlurred"
|
Margin="@Margin" OnBlur="@OnBlurred"
|
||||||
Clearable="@Clearable"
|
Clearable="@Clearable"
|
||||||
|
@ -7,13 +7,9 @@ namespace Connected.Components;
|
|||||||
|
|
||||||
public partial class TextField<T> : DebouncedInput<T>
|
public partial class TextField<T> : DebouncedInput<T>
|
||||||
{
|
{
|
||||||
protected string Classname =>
|
private Mask? _maskReference;
|
||||||
new CssBuilder("mud-input-input-control")
|
|
||||||
.AddClass(Class)
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
public Input<string> InputReference { get; private set; }
|
public Input<string> InputReference { get; private set; }
|
||||||
private Mask _maskReference;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Type of the input element. It should be a valid HTML5 input type.
|
/// Type of the input element. It should be a valid HTML5 input type.
|
||||||
@ -38,6 +34,11 @@ public partial class TextField<T> : DebouncedInput<T>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter] public EventCallback<MouseEventArgs> OnClearButtonClick { get; set; }
|
[Parameter] public EventCallback<MouseEventArgs> OnClearButtonClick { get; set; }
|
||||||
|
|
||||||
|
protected string ClassList =>
|
||||||
|
new CssBuilder("mud-input-input-control")
|
||||||
|
.AddClass(Class)
|
||||||
|
.Build();
|
||||||
|
|
||||||
public override ValueTask FocusAsync()
|
public override ValueTask FocusAsync()
|
||||||
{
|
{
|
||||||
if (_mask == null)
|
if (_mask == null)
|
||||||
@ -130,10 +131,10 @@ public partial class TextField<T> : DebouncedInput<T>
|
|||||||
{
|
{
|
||||||
if (_mask != null)
|
if (_mask != null)
|
||||||
{
|
{
|
||||||
var textValue = Converter.Set(value);
|
var textValue = Converter.Convert(value);
|
||||||
_mask.SetText(textValue);
|
_mask.SetText(textValue);
|
||||||
textValue = Mask.GetCleanText();
|
textValue = Mask.GetCleanText();
|
||||||
value = Converter.Get(textValue);
|
value = Converter.ConvertBack(textValue);
|
||||||
}
|
}
|
||||||
return base.SetValueAsync(value, updateText);
|
return base.SetValueAsync(value, updateText);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Dynamic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Connected.Annotations;
|
using Connected.Annotations;
|
||||||
@ -14,11 +15,13 @@ public partial class TimePicker : Picker<TimeSpan?>
|
|||||||
private const string format24Hours = "HH:mm";
|
private const string format24Hours = "HH:mm";
|
||||||
private const string format12Hours = "hh:mm tt";
|
private const string format12Hours = "hh:mm tt";
|
||||||
|
|
||||||
public TimePicker() : base(new DefaultConverter<TimeSpan?>())
|
|
||||||
|
public TimePicker() : base()
|
||||||
{
|
{
|
||||||
Converter.GetFunc = OnGet;
|
_timeFormat = format24Hours;
|
||||||
Converter.SetFunc = OnSet;
|
|
||||||
((DefaultConverter<TimeSpan?>)Converter).Format = format24Hours;
|
Converter = new LambdaConverter<TimeSpan?, string>((e) => OnSet(e), (e) => OnGet(e));
|
||||||
|
|
||||||
AdornmentIcon = Icons.Material.Filled.AccessTime;
|
AdornmentIcon = Icons.Material.Filled.AccessTime;
|
||||||
AdornmentAriaLabel = "Open Time Picker";
|
AdornmentAriaLabel = "Open Time Picker";
|
||||||
}
|
}
|
||||||
@ -30,7 +33,7 @@ public partial class TimePicker : Picker<TimeSpan?>
|
|||||||
|
|
||||||
var time = DateTime.Today.Add(timespan.Value);
|
var time = DateTime.Today.Add(timespan.Value);
|
||||||
|
|
||||||
return time.ToString(((DefaultConverter<TimeSpan?>)Converter).Format, Culture);
|
return time.ToString(_timeFormat, Culture);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimeSpan? OnGet(string value)
|
private TimeSpan? OnGet(string value)
|
||||||
@ -38,7 +41,7 @@ public partial class TimePicker : Picker<TimeSpan?>
|
|||||||
if (string.IsNullOrEmpty(value))
|
if (string.IsNullOrEmpty(value))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (DateTime.TryParseExact(value, ((DefaultConverter<TimeSpan?>)Converter).Format, Culture, DateTimeStyles.None, out var time))
|
if (DateTime.TryParseExact(value, _timeFormat, Culture, DateTimeStyles.None, out var time))
|
||||||
{
|
{
|
||||||
return time.TimeOfDay;
|
return time.TimeOfDay;
|
||||||
}
|
}
|
||||||
@ -105,13 +108,10 @@ public partial class TimePicker : Picker<TimeSpan?>
|
|||||||
|
|
||||||
_amPm = value;
|
_amPm = value;
|
||||||
|
|
||||||
if (Converter is DefaultConverter<TimeSpan?> defaultConverter && string.IsNullOrWhiteSpace(_timeFormat))
|
_timeFormat = AmPm ? format12Hours : format24Hours;
|
||||||
{
|
|
||||||
defaultConverter.Format = AmPm ? format12Hours : format24Hours;
|
|
||||||
}
|
|
||||||
|
|
||||||
Touched = true;
|
Modified = true;
|
||||||
SetTextAsync(Converter.Set(_value), false).AndForget();
|
SetTextAsync(Converter.Convert(_value), false).AndForget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,11 +129,9 @@ public partial class TimePicker : Picker<TimeSpan?>
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_timeFormat = value;
|
_timeFormat = value;
|
||||||
if (Converter is DefaultConverter<TimeSpan?> defaultConverter)
|
|
||||||
defaultConverter.Format = _timeFormat;
|
|
||||||
|
|
||||||
Touched = true;
|
Modified = true;
|
||||||
SetTextAsync(Converter.Set(_value), false).AndForget();
|
SetTextAsync(Converter.Convert(_value), false).AndForget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +153,7 @@ public partial class TimePicker : Picker<TimeSpan?>
|
|||||||
TimeIntermediate = time;
|
TimeIntermediate = time;
|
||||||
_value = time;
|
_value = time;
|
||||||
if (updateValue)
|
if (updateValue)
|
||||||
await SetTextAsync(Converter.Set(_value), false);
|
await SetTextAsync(Converter.Convert(_value), false);
|
||||||
UpdateTimeSetFromTime();
|
UpdateTimeSetFromTime();
|
||||||
await TimeChanged.InvokeAsync(_value);
|
await TimeChanged.InvokeAsync(_value);
|
||||||
BeginValidate();
|
BeginValidate();
|
||||||
@ -170,9 +168,9 @@ public partial class TimePicker : Picker<TimeSpan?>
|
|||||||
|
|
||||||
protected override Task StringValueChanged(string value)
|
protected override Task StringValueChanged(string value)
|
||||||
{
|
{
|
||||||
Touched = true;
|
Modified = true;
|
||||||
// Update the time property (without updating back the Value property)
|
// Update the time property (without updating back the Value property)
|
||||||
return SetTimeAsync(Converter.Get(value), false);
|
return SetTimeAsync(Converter.ConvertBack(value), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//The last line cannot be tested
|
//The last line cannot be tested
|
||||||
|
@ -12,7 +12,7 @@ public partial class TreeViewItem<T> : UIComponent
|
|||||||
private string _text;
|
private string _text;
|
||||||
private bool _disabled;
|
private bool _disabled;
|
||||||
private bool _isChecked, _isSelected, _isServerLoaded;
|
private bool _isChecked, _isSelected, _isServerLoaded;
|
||||||
private Converter<T> _converter = new DefaultConverter<T>();
|
private ToStringConverter<T> _converter = new DefaultConverter<T>();
|
||||||
private readonly List<TreeViewItem<T>> _childItems = new();
|
private readonly List<TreeViewItem<T>> _childItems = new();
|
||||||
|
|
||||||
protected string Classname =>
|
protected string Classname =>
|
||||||
@ -68,7 +68,7 @@ public partial class TreeViewItem<T> : UIComponent
|
|||||||
[Category(CategoryTypes.TreeView.Behavior)]
|
[Category(CategoryTypes.TreeView.Behavior)]
|
||||||
public string Text
|
public string Text
|
||||||
{
|
{
|
||||||
get => string.IsNullOrEmpty(_text) ? _converter.Set(Value) : _text;
|
get => string.IsNullOrEmpty(_text) ? _converter.Convert(Value) : _text;
|
||||||
set => _text = value;
|
set => _text = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user