Compare commits
No commits in common. "be914e4b2ed20924b0b1bbd0592dd6e48050d6bc" and "f62c1f267e04400f50b15b47f4cf2767feef48aa" have entirely different histories.
be914e4b2e
...
f62c1f267e
226
.editorconfig
226
.editorconfig
@ -1,226 +0,0 @@
|
|||||||
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
|
||||||
root = true
|
|
||||||
|
|
||||||
# C# files
|
|
||||||
[*.cs]
|
|
||||||
|
|
||||||
#### Core EditorConfig Options ####
|
|
||||||
|
|
||||||
# Indentation and spacing
|
|
||||||
indent_size = 3
|
|
||||||
indent_style = tab
|
|
||||||
tab_width = 3
|
|
||||||
|
|
||||||
# New line preferences
|
|
||||||
end_of_line = crlf
|
|
||||||
insert_final_newline = false
|
|
||||||
|
|
||||||
#### .NET Coding Conventions ####
|
|
||||||
|
|
||||||
# Organize usings
|
|
||||||
dotnet_separate_import_directive_groups = false
|
|
||||||
dotnet_sort_system_directives_first = false
|
|
||||||
file_header_template = unset
|
|
||||||
|
|
||||||
# this. and Me. preferences
|
|
||||||
dotnet_style_qualification_for_event = false:suggestion
|
|
||||||
dotnet_style_qualification_for_field = false:suggestion
|
|
||||||
dotnet_style_qualification_for_method = false:suggestion
|
|
||||||
dotnet_style_qualification_for_property = false:suggestion
|
|
||||||
|
|
||||||
# Language keywords vs BCL types preferences
|
|
||||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
|
||||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
|
||||||
|
|
||||||
# Parentheses preferences
|
|
||||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:suggestion
|
|
||||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion
|
|
||||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion
|
|
||||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion
|
|
||||||
|
|
||||||
# Modifier preferences
|
|
||||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members
|
|
||||||
|
|
||||||
# Expression-level preferences
|
|
||||||
dotnet_style_coalesce_expression = true
|
|
||||||
dotnet_style_collection_initializer = true
|
|
||||||
dotnet_style_explicit_tuple_names = true
|
|
||||||
dotnet_style_namespace_match_folder = true
|
|
||||||
dotnet_style_null_propagation = true
|
|
||||||
dotnet_style_object_initializer = true
|
|
||||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
|
||||||
dotnet_style_prefer_auto_properties = true:suggestion
|
|
||||||
dotnet_style_prefer_compound_assignment = true
|
|
||||||
dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
|
|
||||||
dotnet_style_prefer_conditional_expression_over_return = true:suggestion
|
|
||||||
dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
|
|
||||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true
|
|
||||||
dotnet_style_prefer_inferred_tuple_names = false
|
|
||||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
|
|
||||||
dotnet_style_prefer_simplified_boolean_expressions = true
|
|
||||||
dotnet_style_prefer_simplified_interpolation = true
|
|
||||||
|
|
||||||
# Field preferences
|
|
||||||
dotnet_style_readonly_field = true
|
|
||||||
|
|
||||||
# Parameter preferences
|
|
||||||
dotnet_code_quality_unused_parameters = all
|
|
||||||
|
|
||||||
# Suppression preferences
|
|
||||||
dotnet_remove_unnecessary_suppression_exclusions = 0
|
|
||||||
|
|
||||||
# New line preferences
|
|
||||||
dotnet_style_allow_multiple_blank_lines_experimental = false:suggestion
|
|
||||||
dotnet_style_allow_statement_immediately_after_block_experimental = false:suggestion
|
|
||||||
|
|
||||||
#### C# Coding Conventions ####
|
|
||||||
|
|
||||||
# var preferences
|
|
||||||
csharp_style_var_elsewhere = true:warning
|
|
||||||
csharp_style_var_for_built_in_types = true:warning
|
|
||||||
csharp_style_var_when_type_is_apparent = true:warning
|
|
||||||
|
|
||||||
# Expression-bodied members
|
|
||||||
csharp_style_expression_bodied_accessors = when_on_single_line:suggestion
|
|
||||||
csharp_style_expression_bodied_constructors = when_on_single_line:suggestion
|
|
||||||
csharp_style_expression_bodied_indexers = when_on_single_line:suggestion
|
|
||||||
csharp_style_expression_bodied_lambdas = when_on_single_line:suggestion
|
|
||||||
csharp_style_expression_bodied_local_functions = when_on_single_line:suggestion
|
|
||||||
csharp_style_expression_bodied_methods = when_on_single_line:suggestion
|
|
||||||
csharp_style_expression_bodied_operators = when_on_single_line:suggestion
|
|
||||||
csharp_style_expression_bodied_properties = when_on_single_line:suggestion
|
|
||||||
|
|
||||||
# Pattern matching preferences
|
|
||||||
csharp_style_pattern_matching_over_as_with_null_check = true
|
|
||||||
csharp_style_pattern_matching_over_is_with_cast_check = true
|
|
||||||
csharp_style_prefer_extended_property_pattern = true
|
|
||||||
csharp_style_prefer_not_pattern = true
|
|
||||||
csharp_style_prefer_pattern_matching = true:suggestion
|
|
||||||
csharp_style_prefer_switch_expression = true
|
|
||||||
|
|
||||||
# Null-checking preferences
|
|
||||||
csharp_style_conditional_delegate_call = true
|
|
||||||
|
|
||||||
# Modifier preferences
|
|
||||||
csharp_prefer_static_local_function = true
|
|
||||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async
|
|
||||||
csharp_style_prefer_readonly_struct = true
|
|
||||||
|
|
||||||
# Code-block preferences
|
|
||||||
csharp_prefer_braces = when_multiline:suggestion
|
|
||||||
csharp_prefer_simple_using_statement = true
|
|
||||||
csharp_style_namespace_declarations = file_scoped:warning
|
|
||||||
csharp_style_prefer_method_group_conversion = true:suggestion
|
|
||||||
csharp_style_prefer_top_level_statements = false:suggestion
|
|
||||||
|
|
||||||
# Expression-level preferences
|
|
||||||
csharp_prefer_simple_default_expression = true
|
|
||||||
csharp_style_deconstructed_variable_declaration = true
|
|
||||||
csharp_style_implicit_object_creation_when_type_is_apparent = true
|
|
||||||
csharp_style_inlined_variable_declaration = true
|
|
||||||
csharp_style_prefer_index_operator = true
|
|
||||||
csharp_style_prefer_local_over_anonymous_function = true
|
|
||||||
csharp_style_prefer_null_check_over_type_check = true
|
|
||||||
csharp_style_prefer_range_operator = true
|
|
||||||
csharp_style_prefer_tuple_swap = true
|
|
||||||
csharp_style_prefer_utf8_string_literals = true
|
|
||||||
csharp_style_throw_expression = true
|
|
||||||
csharp_style_unused_value_assignment_preference = discard_variable
|
|
||||||
csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion
|
|
||||||
|
|
||||||
# 'using' directive preferences
|
|
||||||
csharp_using_directive_placement = outside_namespace:suggestion
|
|
||||||
|
|
||||||
# New line preferences
|
|
||||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:suggestion
|
|
||||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:suggestion
|
|
||||||
csharp_style_allow_embedded_statements_on_same_line_experimental = false:suggestion
|
|
||||||
|
|
||||||
#### C# Formatting Rules ####
|
|
||||||
|
|
||||||
# New line preferences
|
|
||||||
csharp_new_line_before_catch = true
|
|
||||||
csharp_new_line_before_else = true
|
|
||||||
csharp_new_line_before_finally = true
|
|
||||||
csharp_new_line_before_members_in_anonymous_types = true
|
|
||||||
csharp_new_line_before_members_in_object_initializers = true
|
|
||||||
csharp_new_line_before_open_brace = all
|
|
||||||
csharp_new_line_between_query_expression_clauses = true
|
|
||||||
|
|
||||||
# Indentation preferences
|
|
||||||
csharp_indent_block_contents = true
|
|
||||||
csharp_indent_braces = false
|
|
||||||
csharp_indent_case_contents = true
|
|
||||||
csharp_indent_case_contents_when_block = true
|
|
||||||
csharp_indent_labels = no_change
|
|
||||||
csharp_indent_switch_labels = true
|
|
||||||
|
|
||||||
# Space preferences
|
|
||||||
csharp_space_after_cast = false
|
|
||||||
csharp_space_after_colon_in_inheritance_clause = true
|
|
||||||
csharp_space_after_comma = true
|
|
||||||
csharp_space_after_dot = false
|
|
||||||
csharp_space_after_keywords_in_control_flow_statements = true
|
|
||||||
csharp_space_after_semicolon_in_for_statement = true
|
|
||||||
csharp_space_around_binary_operators = before_and_after
|
|
||||||
csharp_space_around_declaration_statements = false
|
|
||||||
csharp_space_before_colon_in_inheritance_clause = true
|
|
||||||
csharp_space_before_comma = false
|
|
||||||
csharp_space_before_dot = false
|
|
||||||
csharp_space_before_open_square_brackets = false
|
|
||||||
csharp_space_before_semicolon_in_for_statement = false
|
|
||||||
csharp_space_between_empty_square_brackets = false
|
|
||||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
|
||||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
|
||||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_parentheses = false
|
|
||||||
csharp_space_between_square_brackets = false
|
|
||||||
|
|
||||||
# Wrapping preferences
|
|
||||||
csharp_preserve_single_line_blocks = true
|
|
||||||
csharp_preserve_single_line_statements = true
|
|
||||||
|
|
||||||
#### Naming styles ####
|
|
||||||
|
|
||||||
# Naming rules
|
|
||||||
|
|
||||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
|
||||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
|
||||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
|
||||||
|
|
||||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
|
||||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
|
||||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
|
||||||
|
|
||||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
|
||||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
|
||||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
|
||||||
|
|
||||||
# Symbol specifications
|
|
||||||
|
|
||||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
|
||||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
|
||||||
dotnet_naming_symbols.interface.required_modifiers =
|
|
||||||
|
|
||||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
|
||||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
|
||||||
dotnet_naming_symbols.types.required_modifiers =
|
|
||||||
|
|
||||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
|
||||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
|
||||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
|
||||||
|
|
||||||
# Naming styles
|
|
||||||
|
|
||||||
dotnet_naming_style.pascal_case.required_prefix =
|
|
||||||
dotnet_naming_style.pascal_case.required_suffix =
|
|
||||||
dotnet_naming_style.pascal_case.word_separator =
|
|
||||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
|
||||||
|
|
||||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
|
||||||
dotnet_naming_style.begins_with_i.required_suffix =
|
|
||||||
dotnet_naming_style.begins_with_i.word_separator =
|
|
||||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
|
@ -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="@HasError" ErrorText="@ErrorText" Disabled="@Disabled" @onclick="@ToggleMenu" Required="@Required" ForId="@FieldId">
|
Error="@Error" 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="@HasError"
|
Disabled="@Disabled" ReadOnly="@ReadOnly" Error="@Error"
|
||||||
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"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -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.Convert(Checked);
|
protected bool? BoolValue => Converter.Set(Checked);
|
||||||
|
|
||||||
protected virtual Task OnChange(ChangeEventArgs args)
|
protected virtual Task OnChange(ChangeEventArgs args)
|
||||||
{
|
{
|
||||||
Modified = true;
|
Touched = true;
|
||||||
return SetBoolValueAsync((bool?)args.Value);
|
return SetBoolValueAsync((bool?)args.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Task SetBoolValueAsync(bool? value)
|
protected Task SetBoolValueAsync(bool? value)
|
||||||
{
|
{
|
||||||
return SetCheckedAsync(Converter.ConvertBack(value));
|
return SetCheckedAsync(Converter.Get(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.Convert(Checked)).AndForget();
|
SetBoolValueAsync(Converter.Set(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)
|
||||||
{
|
{
|
||||||
Modified = true;
|
Touched = 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?))
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -30,7 +30,7 @@ public class DatePicker : DatePickerBase
|
|||||||
{
|
{
|
||||||
if (_value != date)
|
if (_value != date)
|
||||||
{
|
{
|
||||||
Modified = true;
|
Touched = true;
|
||||||
|
|
||||||
if (date is not null && IsDateDisabledFunc(date.Value.Date))
|
if (date is not null && IsDateDisabledFunc(date.Value.Date))
|
||||||
{
|
{
|
||||||
@ -40,8 +40,10 @@ 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);
|
||||||
@ -50,15 +52,15 @@ public class DatePicker : DatePickerBase
|
|||||||
|
|
||||||
protected override Task DateFormatChanged(string newFormat)
|
protected override Task DateFormatChanged(string newFormat)
|
||||||
{
|
{
|
||||||
Modified = true;
|
Touched = true;
|
||||||
return SetTextAsync(Converter.Convert(_value), false);
|
return SetTextAsync(Converter.Set(_value), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Task StringValueChanged(string value)
|
protected override Task StringValueChanged(string value)
|
||||||
{
|
{
|
||||||
Modified = true;
|
Touched = true;
|
||||||
// Update the date property (without updating back the Value property)
|
// Update the date property (without updating back the Value property)
|
||||||
return SetDateAsync(Converter.ConvertBack(value), false);
|
return SetDateAsync(Converter.Get(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.ConvertBack(Text);
|
DateTime? a = Converter.Get(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,7 +1,4 @@
|
|||||||
using Connected.Extensions;
|
namespace Connected.Components;
|
||||||
using Connected.Utilities.BindingConverters;
|
|
||||||
|
|
||||||
namespace Connected.Components;
|
|
||||||
|
|
||||||
public class DateRange : Range<DateTime?>, IEquatable<DateRange>
|
public class DateRange : Range<DateTime?>, IEquatable<DateRange>
|
||||||
{
|
{
|
||||||
@ -18,7 +15,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.Convert(Start.Value), converter.Convert(End.Value));
|
return RangeConverter<DateTime>.Join(converter.Set(Start.Value), converter.Set(End.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ToIsoDateString()
|
public string ToIsoDateString()
|
||||||
@ -43,14 +40,12 @@ public class DateRange : Range<DateTime?>, IEquatable<DateRange>
|
|||||||
{
|
{
|
||||||
date = null;
|
date = null;
|
||||||
|
|
||||||
var endDate = converter.ConvertBack(end);
|
var endDate = converter.Get(end);
|
||||||
|
if (converter.GetError)
|
||||||
if (endDate is null)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var startDate = converter.ConvertBack(start);
|
var startDate = converter.Get(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="@HasError"
|
@<InputControl Label="@Label" Variant="@Variant" HelperText="@HelperText" Error="@Error"
|
||||||
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="@HasError" ErrorText="@ErrorText" Margin="@Margin" AdornmentAriaLabel="@AdornmentAriaLabel"/>
|
Required="@Required" RequiredError="@RequiredError" Error="@Error" ErrorText="@ErrorText" Margin="@Margin" AdornmentAriaLabel="@AdornmentAriaLabel"/>
|
||||||
</InputContent>
|
</InputContent>
|
||||||
</InputControl>;
|
</InputControl>;
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@ public partial class DateRangePicker : DatePickerBase
|
|||||||
|
|
||||||
if (updateValue)
|
if (updateValue)
|
||||||
{
|
{
|
||||||
|
Converter.GetError = false;
|
||||||
if (_dateRange == null)
|
if (_dateRange == null)
|
||||||
{
|
{
|
||||||
_rangeText = null;
|
_rangeText = null;
|
||||||
@ -65,8 +66,8 @@ public partial class DateRangePicker : DatePickerBase
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_rangeText = new Range<string>(
|
_rangeText = new Range<string>(
|
||||||
Converter.Convert(_dateRange.Start),
|
Converter.Set(_dateRange.Start),
|
||||||
Converter.Convert(_dateRange.End));
|
Converter.Set(_dateRange.End));
|
||||||
await SetTextAsync(_dateRange.ToString(Converter), false);
|
await SetTextAsync(_dateRange.ToString(Converter), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,7 +85,7 @@ public partial class DateRangePicker : DatePickerBase
|
|||||||
if (_rangeText?.Equals(value) ?? value == null)
|
if (_rangeText?.Equals(value) ?? value == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Modified = true;
|
Touched = true;
|
||||||
_rangeText = value;
|
_rangeText = value;
|
||||||
SetDateRangeAsync(ParseDateRangeValue(value?.Start, value?.End), false).AndForget();
|
SetDateRangeAsync(ParseDateRangeValue(value?.Start, value?.End), false).AndForget();
|
||||||
}
|
}
|
||||||
@ -134,13 +135,13 @@ public partial class DateRangePicker : DatePickerBase
|
|||||||
|
|
||||||
protected override Task DateFormatChanged(string newFormat)
|
protected override Task DateFormatChanged(string newFormat)
|
||||||
{
|
{
|
||||||
Modified = true;
|
Touched = 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)
|
||||||
{
|
{
|
||||||
Modified = true;
|
Touched = 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 (!HasError || !SuppressOnChangeWhenInvalid) //only trigger FilesChanged if validation passes or SuppressOnChangeWhenInvalid is false
|
if (!Error || !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.Modified);
|
var required_all_touched = _formControls.Where(x => x.Required).All(x => x.Touched);
|
||||||
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.Modified);
|
_touched = _formControls.Any(x => x.Touched);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_shouldRender = false;
|
_shouldRender = false;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -3,9 +3,9 @@
|
|||||||
public interface IFormComponent
|
public interface IFormComponent
|
||||||
{
|
{
|
||||||
public bool Required { get; set; }
|
public bool Required { get; set; }
|
||||||
public bool HasError { get; set; }
|
public bool Error { get; set; }
|
||||||
public bool HasErrors { get; }
|
public bool HasErrors { get; }
|
||||||
public bool Modified { get; }
|
public bool Touched { 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; }
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System.Timers;
|
using System.Timers;
|
||||||
using Connected.Annotations;
|
using Connected.Annotations;
|
||||||
using Connected.Utilities.BindingConverters;
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace Connected.Components;
|
namespace Connected.Components;
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
@onkeyup:preventDefault="@KeyUpPreventDefault"
|
@onkeyup:preventDefault="@KeyUpPreventDefault"
|
||||||
@onmousewheel="@OnMouseWheel"
|
@onmousewheel="@OnMouseWheel"
|
||||||
@onwheel="@OnMouseWheel"
|
@onwheel="@OnMouseWheel"
|
||||||
aria-invalid="@HasError.ToString().ToLower()"
|
aria-invalid="@Error.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="@HasError.ToString().ToLower()"
|
aria-invalid="@Error.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))
|
||||||
Modified = true;
|
Touched = 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.Convert(Value), updateValue);
|
return SetTextAsync(Converter.Set(Value), updateValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -266,7 +266,7 @@ public abstract class InputBase<T> : FormComponent<T, string>
|
|||||||
|
|
||||||
if (!OnlyValidateIfDirty || _isDirty)
|
if (!OnlyValidateIfDirty || _isDirty)
|
||||||
{
|
{
|
||||||
Modified = true;
|
Touched = 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.ConvertBack(Text), updateText);
|
return SetValueAsync(Converter.Get(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 => ((ToStringConverter<T>)Converter).Format;
|
get => ((Converter<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)
|
||||||
{
|
{
|
||||||
((ToStringConverter<T>)Converter).Format = value;
|
((Converter<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;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using Connected.Extensions;
|
using Connected.Extensions;
|
||||||
using Connected.Utilities.BindingConverters;
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace Connected.Components;
|
namespace Connected.Components;
|
||||||
@ -11,7 +10,7 @@ public partial class RangeInput<T> : InputBase<Range<T>>
|
|||||||
public RangeInput()
|
public RangeInput()
|
||||||
{
|
{
|
||||||
Value = new Range<T>();
|
Value = new Range<T>();
|
||||||
SetConverter(new RangeConverter<T>());
|
Converter = new RangeConverter<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected string Classname => InputCssHelper.GetClassname(this,
|
protected string Classname => InputCssHelper.GetClassname(this,
|
||||||
|
@ -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.ConvertBack(cleanText);
|
var v = Converter.Get(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.Convert(Value);
|
var text = Converter.Set(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="@HasError"
|
Error="@Error"
|
||||||
Immediate="@(Immediate)"
|
Immediate="@(Immediate)"
|
||||||
Margin="@Margin"
|
Margin="@Margin"
|
||||||
MaxLength="@MaxLength"
|
MaxLength="@MaxLength"
|
||||||
|
@ -8,7 +8,6 @@ using System.Globalization;
|
|||||||
using Connected.Annotations;
|
using Connected.Annotations;
|
||||||
using Connected.Services;
|
using Connected.Services;
|
||||||
using Connected.Utilities;
|
using Connected.Utilities;
|
||||||
using Connected.Utilities.BindingConverters;
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Web;
|
using Microsoft.AspNetCore.Components.Web;
|
||||||
|
|
||||||
@ -209,7 +208,7 @@ public partial class NumericField<T> : DebouncedInput<T>
|
|||||||
return (T)(object)Convert.ToInt64(FromInt64(Value) + FromInt64(Step) * factor);
|
return (T)(object)Convert.ToInt64(FromInt64(Value) + FromInt64(Step) * factor);
|
||||||
if (typeof(T) == typeof(ulong) || typeof(T) == typeof(ulong?))
|
if (typeof(T) == typeof(ulong) || typeof(T) == typeof(ulong?))
|
||||||
return (T)(object)Convert.ToUInt64(FromUInt64(Value) + FromUInt64(Step) * factor);
|
return (T)(object)Convert.ToUInt64(FromUInt64(Value) + FromUInt64(Step) * factor);
|
||||||
return Number.To<T>(Number.From(Value) + Number.From(Step) * factor);
|
return Num.To<T>(Num.From(Value) + Num.From(Step) * factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
Margin="@Margin"
|
Margin="@Margin"
|
||||||
Required="@Required"
|
Required="@Required"
|
||||||
RequiredError="@RequiredError"
|
RequiredError="@RequiredError"
|
||||||
Error="@HasError"
|
Error="@Error"
|
||||||
ErrorText="@ErrorText"
|
ErrorText="@ErrorText"
|
||||||
Clearable="@(ReadOnly ? false : Clearable)"
|
Clearable="@(ReadOnly ? false : Clearable)"
|
||||||
OnClearButtonClick="@(() => Clear())"
|
OnClearButtonClick="@(() => Clear())"
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
using Connected.Annotations;
|
using Connected.Annotations;
|
||||||
using Connected.Extensions;
|
using Connected.Extensions;
|
||||||
using Connected.Utilities;
|
using Connected.Utilities;
|
||||||
using Connected.Utilities.BindingConverters;
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace Connected.Components;
|
namespace Connected.Components;
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
Modified = true;
|
Touched = 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="@HasError" ErrorText="@ErrorText" ErrorId="@ErrorId" Disabled="@Disabled" @onclick="@ToggleMenu" Required="@Required" ForId="@FieldId">
|
Error="@Error" 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="@HasError" ErrorId="@ErrorId"
|
Disabled="@Disabled" ReadOnly="true" Error="@Error" 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))"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -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.Convert(Value);
|
return converter.Set(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.ConvertBack(_min);
|
get => Converter.Get(_min);
|
||||||
set => _min = Converter.Convert(value);
|
set => _min = Converter.Set(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.ConvertBack(_max);
|
get => Converter.Get(_max);
|
||||||
set => _max = Converter.Convert(value);
|
set => _max = Converter.Set(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.ConvertBack(_step);
|
get => Converter.Get(_step);
|
||||||
set => _step = Converter.Convert(value);
|
set => _step = Converter.Set(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -73,7 +73,7 @@ public partial class Slider<T> : UIComponent
|
|||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
[Category(CategoryTypes.Slider.Behavior)]
|
[Category(CategoryTypes.Slider.Behavior)]
|
||||||
public ToStringConverter<T> Converter { get; set; } = new DefaultConverter<T>() { Culture = CultureInfo.InvariantCulture };
|
public Converter<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.ConvertBack(_value);
|
get => Converter.Get(_value);
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
var d = Converter.Convert(value);
|
var d = Converter.Set(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="@ClassList"
|
Class="@Classname"
|
||||||
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="@HasError"
|
Error="@Error"
|
||||||
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="@HasError"
|
Error="@Error"
|
||||||
Immediate="@Immediate"
|
Immediate="@Immediate"
|
||||||
Margin="@Margin" OnBlur="@OnBlurred"
|
Margin="@Margin" OnBlur="@OnBlurred"
|
||||||
Clearable="@Clearable"
|
Clearable="@Clearable"
|
||||||
|
@ -7,9 +7,13 @@ namespace Connected.Components;
|
|||||||
|
|
||||||
public partial class TextField<T> : DebouncedInput<T>
|
public partial class TextField<T> : DebouncedInput<T>
|
||||||
{
|
{
|
||||||
private Mask? _maskReference;
|
protected string Classname =>
|
||||||
|
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.
|
||||||
@ -34,11 +38,6 @@ 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)
|
||||||
@ -131,10 +130,10 @@ public partial class TextField<T> : DebouncedInput<T>
|
|||||||
{
|
{
|
||||||
if (_mask != null)
|
if (_mask != null)
|
||||||
{
|
{
|
||||||
var textValue = Converter.Convert(value);
|
var textValue = Converter.Set(value);
|
||||||
_mask.SetText(textValue);
|
_mask.SetText(textValue);
|
||||||
textValue = Mask.GetCleanText();
|
textValue = Mask.GetCleanText();
|
||||||
value = Converter.ConvertBack(textValue);
|
value = Converter.Get(textValue);
|
||||||
}
|
}
|
||||||
return base.SetValueAsync(value, updateText);
|
return base.SetValueAsync(value, updateText);
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,11 @@ 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()
|
|
||||||
{
|
{
|
||||||
_timeFormat = format24Hours;
|
Converter.GetFunc = OnGet;
|
||||||
|
Converter.SetFunc = OnSet;
|
||||||
SetConverter(new LambdaConverter<TimeSpan?, string>((e) => OnSet(e), (e) => OnGet(e)));
|
((DefaultConverter<TimeSpan?>)Converter).Format = format24Hours;
|
||||||
|
|
||||||
AdornmentIcon = Icons.Material.Filled.AccessTime;
|
AdornmentIcon = Icons.Material.Filled.AccessTime;
|
||||||
AdornmentAriaLabel = "Open Time Picker";
|
AdornmentAriaLabel = "Open Time Picker";
|
||||||
}
|
}
|
||||||
@ -32,7 +30,7 @@ public partial class TimePicker : Picker<TimeSpan?>
|
|||||||
|
|
||||||
var time = DateTime.Today.Add(timespan.Value);
|
var time = DateTime.Today.Add(timespan.Value);
|
||||||
|
|
||||||
return time.ToString(_timeFormat, Culture);
|
return time.ToString(((DefaultConverter<TimeSpan?>)Converter).Format, Culture);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimeSpan? OnGet(string value)
|
private TimeSpan? OnGet(string value)
|
||||||
@ -40,7 +38,7 @@ public partial class TimePicker : Picker<TimeSpan?>
|
|||||||
if (string.IsNullOrEmpty(value))
|
if (string.IsNullOrEmpty(value))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (DateTime.TryParseExact(value, _timeFormat, Culture, DateTimeStyles.None, out var time))
|
if (DateTime.TryParseExact(value, ((DefaultConverter<TimeSpan?>)Converter).Format, Culture, DateTimeStyles.None, out var time))
|
||||||
{
|
{
|
||||||
return time.TimeOfDay;
|
return time.TimeOfDay;
|
||||||
}
|
}
|
||||||
@ -107,10 +105,13 @@ public partial class TimePicker : Picker<TimeSpan?>
|
|||||||
|
|
||||||
_amPm = value;
|
_amPm = value;
|
||||||
|
|
||||||
_timeFormat = AmPm ? format12Hours : format24Hours;
|
if (Converter is DefaultConverter<TimeSpan?> defaultConverter && string.IsNullOrWhiteSpace(_timeFormat))
|
||||||
|
{
|
||||||
|
defaultConverter.Format = AmPm ? format12Hours : format24Hours;
|
||||||
|
}
|
||||||
|
|
||||||
Modified = true;
|
Touched = true;
|
||||||
SetTextAsync(Converter.Convert(_value), false).AndForget();
|
SetTextAsync(Converter.Set(_value), false).AndForget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,9 +129,11 @@ public partial class TimePicker : Picker<TimeSpan?>
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_timeFormat = value;
|
_timeFormat = value;
|
||||||
|
if (Converter is DefaultConverter<TimeSpan?> defaultConverter)
|
||||||
Modified = true;
|
defaultConverter.Format = _timeFormat;
|
||||||
SetTextAsync(Converter.Convert(_value), false).AndForget();
|
|
||||||
|
Touched = true;
|
||||||
|
SetTextAsync(Converter.Set(_value), false).AndForget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +155,7 @@ public partial class TimePicker : Picker<TimeSpan?>
|
|||||||
TimeIntermediate = time;
|
TimeIntermediate = time;
|
||||||
_value = time;
|
_value = time;
|
||||||
if (updateValue)
|
if (updateValue)
|
||||||
await SetTextAsync(Converter.Convert(_value), false);
|
await SetTextAsync(Converter.Set(_value), false);
|
||||||
UpdateTimeSetFromTime();
|
UpdateTimeSetFromTime();
|
||||||
await TimeChanged.InvokeAsync(_value);
|
await TimeChanged.InvokeAsync(_value);
|
||||||
BeginValidate();
|
BeginValidate();
|
||||||
@ -167,9 +170,9 @@ public partial class TimePicker : Picker<TimeSpan?>
|
|||||||
|
|
||||||
protected override Task StringValueChanged(string value)
|
protected override Task StringValueChanged(string value)
|
||||||
{
|
{
|
||||||
Modified = true;
|
Touched = true;
|
||||||
// Update the time property (without updating back the Value property)
|
// Update the time property (without updating back the Value property)
|
||||||
return SetTimeAsync(Converter.ConvertBack(value), false);
|
return SetTimeAsync(Converter.Get(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 ToStringConverter<T> _converter = new DefaultConverter<T>();
|
private Converter<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.Convert(Value) : _text;
|
get => string.IsNullOrEmpty(_text) ? _converter.Set(Value) : _text;
|
||||||
set => _text = value;
|
set => _text = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,10 @@
|
|||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="7.0.0-rc.2.22476.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="7.0.0-rc.2.22476.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Connected.Client\Connected.Client.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Colors\" />
|
<Folder Include="Colors\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -1,48 +1,38 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace Connected;
|
namespace Connected
|
||||||
|
|
||||||
public enum InputType
|
|
||||||
{
|
{
|
||||||
[Description("text")]
|
public enum InputType
|
||||||
Text,
|
{
|
||||||
|
[Description("text")]
|
||||||
[Description("password")]
|
Text,
|
||||||
Password,
|
[Description("password")]
|
||||||
|
Password,
|
||||||
[Description("email")]
|
[Description("email")]
|
||||||
Email,
|
Email,
|
||||||
|
[Description("hidden")]
|
||||||
[Description("hidden")]
|
Hidden,
|
||||||
Hidden,
|
[Description("number")]
|
||||||
|
Number,
|
||||||
[Description("number")]
|
[Description("search")]
|
||||||
Number,
|
Search,
|
||||||
|
[Description("tel")]
|
||||||
[Description("search")]
|
Telephone,
|
||||||
Search,
|
[Description("url")]
|
||||||
|
Url,
|
||||||
[Description("tel")]
|
[Description("color")]
|
||||||
Telephone,
|
Color,
|
||||||
|
[Description("date")]
|
||||||
[Description("url")]
|
Date,
|
||||||
Url,
|
[Description("datetime-local")]
|
||||||
|
DateTimeLocal,
|
||||||
[Description("color")]
|
[Description("month")]
|
||||||
Color,
|
Month,
|
||||||
|
[Description("time")]
|
||||||
[Description("date")]
|
Time,
|
||||||
Date,
|
[Description("week")]
|
||||||
|
Week
|
||||||
[Description("datetime-local")]
|
|
||||||
DateTimeLocal,
|
|
||||||
|
}
|
||||||
[Description("month")]
|
|
||||||
Month,
|
|
||||||
|
|
||||||
[Description("time")]
|
|
||||||
Time,
|
|
||||||
|
|
||||||
[Description("week")]
|
|
||||||
Week
|
|
||||||
}
|
}
|
||||||
|
63
Instance.cs
Normal file
63
Instance.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
using Connected.Middleware;
|
||||||
|
using Connected.Startup;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.AspNetCore.Components.Web;
|
||||||
|
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Connected;
|
||||||
|
|
||||||
|
public static class Instance
|
||||||
|
{
|
||||||
|
public static WebAssemblyHost Host { get; private set; } = default!;
|
||||||
|
private static IServiceProvider ServiceProvider { get; set; } = default!;
|
||||||
|
|
||||||
|
internal static T? GetService<T>()
|
||||||
|
{
|
||||||
|
return ServiceProvider.GetService<T>();
|
||||||
|
}
|
||||||
|
public static async Task Start<TApp>(List<IStartup> startups, Dictionary<string, string> args) where TApp : IComponent
|
||||||
|
{
|
||||||
|
var builder = WebAssemblyHostBuilder.CreateDefault(UnpackArguments(args));
|
||||||
|
|
||||||
|
builder.RootComponents.Add<TApp>("#app");
|
||||||
|
builder.RootComponents.Add<HeadOutlet>("head::after");
|
||||||
|
|
||||||
|
builder.Services.AddHttpClient();
|
||||||
|
|
||||||
|
builder.Services.AddSingleton(typeof(IComponentMiddlewareService), typeof(ComponentMiddlewareService));
|
||||||
|
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
|
||||||
|
|
||||||
|
foreach (var startup in startups)
|
||||||
|
await startup.ConfigureServices(builder.Services);
|
||||||
|
|
||||||
|
Host = builder.Build();
|
||||||
|
|
||||||
|
foreach (var startup in startups)
|
||||||
|
await startup.Configure(Host);
|
||||||
|
|
||||||
|
await Host.RunAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] UnpackArguments(Dictionary<string, string> args)
|
||||||
|
{
|
||||||
|
var result = new string[args.Count];
|
||||||
|
|
||||||
|
for (var i = 0; i < args.Count; i++)
|
||||||
|
{
|
||||||
|
var arg = args.ElementAt(i);
|
||||||
|
|
||||||
|
result[i] = string.IsNullOrWhiteSpace(arg.Value) ? arg.Key : $"{arg.Key}={arg.Value}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UseMiddlewareComponent<TMiddleware, TComponent>(this WebAssemblyHost app)
|
||||||
|
{
|
||||||
|
if (app.Services.GetService<IComponentMiddlewareService>() is not IComponentMiddlewareService service)
|
||||||
|
throw new NullReferenceException(nameof(IComponentMiddlewareService));
|
||||||
|
|
||||||
|
service.Add<TMiddleware, TComponent>();
|
||||||
|
}
|
||||||
|
}
|
6
Routes.cs
Normal file
6
Routes.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace Connected;
|
||||||
|
|
||||||
|
public static class UIRoutes
|
||||||
|
{
|
||||||
|
public const string Management = "management";
|
||||||
|
}
|
@ -11,19 +11,11 @@ namespace Connected
|
|||||||
|
|
||||||
public BoolConverter()
|
public BoolConverter()
|
||||||
{
|
{
|
||||||
|
SetFunc = OnSet;
|
||||||
|
GetFunc = OnGet;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool? ConvertValue(T? value)
|
private T OnGet(bool? value)
|
||||||
{
|
|
||||||
return OnSet(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override T? ConvertValueBack(bool? value)
|
|
||||||
{
|
|
||||||
return OnGet(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private T OnGet(bool? value)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -39,12 +31,12 @@ namespace Connected
|
|||||||
return (T)(object)(value == true ? 1 : (value == false ? (int?)0 : null));
|
return (T)(object)(value == true ? 1 : (value == false ? (int?)0 : null));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TriggerError($"Conversion to type {typeof(T)} not implemented");
|
UpdateGetError($"Conversion to type {typeof(T)} not implemented");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
TriggerError("Conversion error: " + e.Message);
|
UpdateGetError("Conversion error: " + e.Message);
|
||||||
return default(T);
|
return default(T);
|
||||||
}
|
}
|
||||||
return default(T);
|
return default(T);
|
||||||
@ -77,13 +69,13 @@ namespace Connected
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TriggerError("Unable to convert to bool? from type " + typeof(T).Name);
|
UpdateSetError("Unable to convert to bool? from type " + typeof(T).Name);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (FormatException e)
|
catch (FormatException e)
|
||||||
{
|
{
|
||||||
TriggerError("Conversion error: " + e.Message);
|
UpdateSetError("Conversion error: " + e.Message);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,111 +1,88 @@
|
|||||||
using System.Globalization;
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace Connected;
|
namespace Connected
|
||||||
|
|
||||||
public class Converter<TSourceType, TDestinationType>
|
|
||||||
{
|
{
|
||||||
public event EventHandler<string?>? ErrorOccured;
|
public class Converter<T, U>
|
||||||
|
{
|
||||||
|
public Func<T, U> SetFunc { get; set; }
|
||||||
|
public Func<U, T> GetFunc { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The culture info being used for decimal points, date and time format, etc.
|
/// The culture info being used for decimal points, date and time format, etc.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CultureInfo Culture { get; set; } = Converters.DefaultCulture;
|
public CultureInfo Culture { get; set; } = Converters.DefaultCulture;
|
||||||
|
|
||||||
public TDestinationType? Convert(TSourceType value)
|
public Action<string> OnError { get; set; }
|
||||||
{
|
public bool SetError { get; set; }
|
||||||
try
|
public bool GetError { get; set; }
|
||||||
{
|
public string SetErrorMessage { get; set; }
|
||||||
return ConvertValue(value);
|
public string GetErrorMessage { get; set; }
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
TriggerError($"Conversion from {typeof(TSourceType).Name} to {typeof(TDestinationType).Name} failed: {e.Message}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return default;
|
public U Set(T value)
|
||||||
}
|
{
|
||||||
|
SetError = false;
|
||||||
|
SetErrorMessage = null;
|
||||||
|
if (SetFunc == null)
|
||||||
|
return default(U);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return SetFunc(value);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
SetError = true;
|
||||||
|
SetErrorMessage = $"Conversion from {typeof(T).Name} to {typeof(U).Name} failed: {e.Message}";
|
||||||
|
}
|
||||||
|
return default(U);
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual TDestinationType? ConvertValue(TSourceType? value)
|
public T Get(U value)
|
||||||
{
|
{
|
||||||
return default;
|
GetError = false;
|
||||||
}
|
GetErrorMessage = null;
|
||||||
|
if (GetFunc == null)
|
||||||
|
return default(T);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return GetFunc(value);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
GetError = true;
|
||||||
|
GetErrorMessage = $"Conversion from {typeof(U).Name} to {typeof(T).Name} failed: {e.Message}";
|
||||||
|
}
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
|
||||||
public TSourceType? ConvertBack(TDestinationType value)
|
protected void UpdateSetError(string msg)
|
||||||
{
|
{
|
||||||
try
|
SetError = true;
|
||||||
{
|
SetErrorMessage = msg;
|
||||||
return ConvertValueBack(value);
|
OnError?.Invoke(msg);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
TriggerError($"Conversion from {typeof(TDestinationType).Name} to {typeof(TSourceType).Name} failed: {e.Message}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return default;
|
protected void UpdateGetError(string msg)
|
||||||
}
|
{
|
||||||
|
GetError = true;
|
||||||
|
GetErrorMessage = msg;
|
||||||
|
OnError?.Invoke(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual TSourceType? ConvertValueBack(TDestinationType? value)
|
/// <summary>
|
||||||
{
|
/// Converter from T to string
|
||||||
return default;
|
///
|
||||||
}
|
/// Set converts to string
|
||||||
|
/// Get converts from string
|
||||||
|
/// </summary>
|
||||||
|
public class Converter<T> : Converter<T, string>
|
||||||
|
{
|
||||||
|
|
||||||
protected void TriggerError(string? msg, Exception? e = null)
|
/// <summary>
|
||||||
{
|
/// Custom Format to be applied on bidirectional way.
|
||||||
ErrorOccured?.Invoke(this, msg);
|
/// </summary>
|
||||||
|
public string Format { get; set; } = null;
|
||||||
|
|
||||||
OnErrorOccured(msg, e);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnErrorOccured(string? msg, Exception? e)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts values using the supplied lambda functions.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TSourceType">The source type</typeparam>
|
|
||||||
/// <typeparam name="TDestinationType">The destination type</typeparam>
|
|
||||||
public class LambdaConverter<TSourceType, TDestinationType> : Converter<TSourceType, TDestinationType>
|
|
||||||
{
|
|
||||||
private readonly Func<TSourceType, TDestinationType?>? _convertFunction;
|
|
||||||
private readonly Func<TDestinationType, TSourceType?>? _convertBackFunction;
|
|
||||||
|
|
||||||
public LambdaConverter(Func<TSourceType, TDestinationType?>? convertFunction = null, Func<TDestinationType, TSourceType?>? convertBackFunction = null)
|
|
||||||
{
|
|
||||||
_convertFunction = convertFunction;
|
|
||||||
_convertBackFunction = convertBackFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override TDestinationType? ConvertValue(TSourceType? value)
|
|
||||||
{
|
|
||||||
if (_convertFunction is null)
|
|
||||||
return base.ConvertValue(value);
|
|
||||||
|
|
||||||
return _convertFunction.Invoke(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override TSourceType? ConvertValueBack(TDestinationType? value)
|
|
||||||
{
|
|
||||||
if (_convertFunction is null)
|
|
||||||
return base.ConvertValueBack(value);
|
|
||||||
|
|
||||||
return _convertBackFunction.Invoke(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converter from T to string
|
|
||||||
///
|
|
||||||
/// Set converts to string
|
|
||||||
/// Get converts from string
|
|
||||||
/// </summary>
|
|
||||||
public class ToStringConverter<T> : Converter<T, string>
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Custom Format to be applied on bidirectional way.
|
|
||||||
/// </summary>
|
|
||||||
public string? Format { get; set; } = null;
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,55 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
namespace Connected;
|
namespace Connected
|
||||||
|
|
||||||
public static class Converters
|
|
||||||
{
|
{
|
||||||
public static CultureInfo DefaultCulture { get; set; } = CultureInfo.CurrentUICulture;
|
public static class Converters
|
||||||
|
{
|
||||||
|
public static CultureInfo DefaultCulture = CultureInfo.CurrentUICulture;
|
||||||
|
|
||||||
|
#region --> Date converters
|
||||||
|
public static Converter<DateTime> IsoDate
|
||||||
|
=> new()
|
||||||
|
{ SetFunc = SetIsoDate, GetFunc = GetIsoDate };
|
||||||
|
|
||||||
|
private static DateTime GetIsoDate(string value)
|
||||||
|
{
|
||||||
|
if (DateTime.TryParse(value, out var dateTime))
|
||||||
|
return dateTime;
|
||||||
|
return DateTime.MinValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string SetIsoDate(DateTime value)
|
||||||
|
{
|
||||||
|
return value.ToIsoDateString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Converter<DateTime?> NullableIsoDate
|
||||||
|
=> new()
|
||||||
|
{ SetFunc = SetNullableIsoDate, GetFunc = GetNullableIsoDate };
|
||||||
|
|
||||||
|
private static DateTime? GetNullableIsoDate(string value)
|
||||||
|
{
|
||||||
|
if (DateTime.TryParse(value, out var dateTime))
|
||||||
|
return dateTime;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string SetNullableIsoDate(DateTime? value)
|
||||||
|
{
|
||||||
|
return value.ToIsoDateString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateConverter DateFormat(string format)
|
||||||
|
{
|
||||||
|
format ??= "yyyy-MM-dd";
|
||||||
|
return new DateConverter(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateConverter DateFormat(string format, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return new DateConverter(format) { Culture = culture };
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,90 @@
|
|||||||
namespace Connected;
|
using System;
|
||||||
|
|
||||||
/// <summary>
|
namespace Connected
|
||||||
/// A ready made DateTime? to string binding converter with configurable date format and culture
|
|
||||||
/// </summary>
|
|
||||||
public class NullableDateConverter : ToStringConverter<DateTime?>
|
|
||||||
{
|
{
|
||||||
public string DateFormat { get; set; }
|
|
||||||
|
|
||||||
public NullableDateConverter(string format = "yyyy-MM-dd") => DateFormat = format;
|
/// <summary>
|
||||||
|
/// A ready made DateTime? to string binding converter with configurable date format and culture
|
||||||
|
/// </summary>
|
||||||
|
public class NullableDateConverter : Converter<DateTime?>
|
||||||
|
{
|
||||||
|
public string DateFormat { get; set; }
|
||||||
|
|
||||||
protected override string? ConvertValue(DateTime? value) => value?.ToString(DateFormat, Culture);
|
public NullableDateConverter(string format = "yyyy-MM-dd")
|
||||||
|
{
|
||||||
|
DateFormat = format;
|
||||||
|
SetFunc = OnSet;
|
||||||
|
GetFunc = OnGet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DateTime? OnGet(string arg)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return DateTime.ParseExact(arg, DateFormat, Culture);
|
||||||
|
}
|
||||||
|
catch (FormatException e)
|
||||||
|
{
|
||||||
|
UpdateGetError(e.Message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string OnSet(DateTime? arg)
|
||||||
|
{
|
||||||
|
if (arg == null)
|
||||||
|
return null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return arg.Value.ToString(DateFormat, Culture);
|
||||||
|
}
|
||||||
|
catch (FormatException e)
|
||||||
|
{
|
||||||
|
UpdateSetError(e.Message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A ready made DateTime to string binding converter with configurable date format and culture
|
||||||
|
/// </summary>
|
||||||
|
public class DateConverter : Converter<DateTime>
|
||||||
|
{
|
||||||
|
public string DateFormat { get; set; } = "yyyy-MM-dd";
|
||||||
|
|
||||||
|
public DateConverter(string format)
|
||||||
|
{
|
||||||
|
DateFormat = format;
|
||||||
|
SetFunc = OnSet;
|
||||||
|
GetFunc = OnGet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DateTime OnGet(string arg)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return DateTime.ParseExact(arg, DateFormat, Culture);
|
||||||
|
}
|
||||||
|
catch (FormatException e)
|
||||||
|
{
|
||||||
|
UpdateGetError(e.Message);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string OnSet(DateTime arg)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return arg.ToString(DateFormat, Culture);
|
||||||
|
}
|
||||||
|
catch (FormatException e)
|
||||||
|
{
|
||||||
|
UpdateSetError(e.Message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override DateTime? ConvertValueBack(string? value) => DateTime.ParseExact(value, DateFormat, Culture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A ready made DateTime to string binding converter with configurable date format and culture
|
|
||||||
/// </summary>
|
|
||||||
public class DateConverter : ToStringConverter<DateTime>
|
|
||||||
{
|
|
||||||
public string DateFormat { get; set; }
|
|
||||||
|
|
||||||
public DateConverter(string format = "yyyy-MM-dd") => DateFormat = format;
|
|
||||||
|
|
||||||
protected override string? ConvertValue(DateTime value) => value.ToString(DateFormat, Culture);
|
|
||||||
|
|
||||||
protected override DateTime ConvertValueBack(string? value) => DateTime.ParseExact(value, DateFormat, Culture);
|
|
||||||
}
|
|
@ -1,464 +1,315 @@
|
|||||||
using System.Globalization;
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace Connected;
|
namespace Connected
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A universal T to string binding converter
|
|
||||||
/// </summary>
|
|
||||||
public class DefaultConverter<T> : ToStringConverter<T>
|
|
||||||
{
|
{
|
||||||
protected override string? ConvertValue(T? value) => ConvertToString(value);
|
|
||||||
|
|
||||||
protected override T? ConvertValueBack(string? value) => ConvertFromString(value);
|
/// <summary>
|
||||||
|
/// A universal T to string binding converter
|
||||||
|
/// </summary>
|
||||||
|
public class DefaultConverter<T> : Converter<T>
|
||||||
|
{
|
||||||
|
|
||||||
public string DefaultTimeSpanFormat { get; set; } = "c";
|
public DefaultConverter()
|
||||||
|
{
|
||||||
|
SetFunc = ConvertToString;
|
||||||
|
GetFunc = ConvertFromString;
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual T? ConvertFromString(string? value)
|
public string DefaultTimeSpanFormat { get; set; } = "c";
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* This is important, or otherwise all the TryParse down there might fail.
|
|
||||||
*/
|
|
||||||
if (string.IsNullOrEmpty(value))
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* String
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(string))
|
|
||||||
{
|
|
||||||
return (T)(object)value;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Char
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(char) || typeof(T) == typeof(char?))
|
|
||||||
{
|
|
||||||
return (T)(object)value[0];
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Bool
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(bool) || typeof(T) == typeof(bool?))
|
|
||||||
{
|
|
||||||
var lowerValue = value.ToLowerInvariant();
|
|
||||||
|
|
||||||
if (lowerValue is "true" or "on")
|
protected virtual T ConvertFromString(string value)
|
||||||
return (T)(object)true;
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// string
|
||||||
|
if (typeof(T) == typeof(string))
|
||||||
|
return (T)(object)value;
|
||||||
|
|
||||||
if (lowerValue is "false" or "off")
|
// this is important, or otherwise all the TryParse down there might fail.
|
||||||
return (T)(object)false;
|
if (string.IsNullOrEmpty(value))
|
||||||
|
return default(T);
|
||||||
|
// char
|
||||||
|
else if (typeof(T) == typeof(char) || typeof(T) == typeof(char?))
|
||||||
|
{
|
||||||
|
return (T)(object)value[0];
|
||||||
|
}
|
||||||
|
// bool
|
||||||
|
else if (typeof(T) == typeof(bool) || typeof(T) == typeof(bool?))
|
||||||
|
{
|
||||||
|
var lowerValue = value.ToLowerInvariant();
|
||||||
|
if (lowerValue is "true" or "on")
|
||||||
|
return (T)(object)true;
|
||||||
|
if (lowerValue is "false" or "off")
|
||||||
|
return (T)(object)false;
|
||||||
|
UpdateGetError("Not a valid boolean");
|
||||||
|
}
|
||||||
|
// sbyte
|
||||||
|
else if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(sbyte?))
|
||||||
|
{
|
||||||
|
if (sbyte.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
||||||
|
return (T)(object)parsedValue;
|
||||||
|
UpdateGetError("Not a valid number");
|
||||||
|
}
|
||||||
|
// byte
|
||||||
|
else if (typeof(T) == typeof(byte) || typeof(T) == typeof(byte?))
|
||||||
|
{
|
||||||
|
if (byte.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
||||||
|
return (T)(object)parsedValue;
|
||||||
|
UpdateGetError("Not a valid number");
|
||||||
|
}
|
||||||
|
// short
|
||||||
|
else if (typeof(T) == typeof(short) || typeof(T) == typeof(short?))
|
||||||
|
{
|
||||||
|
if (short.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
||||||
|
return (T)(object)parsedValue;
|
||||||
|
UpdateGetError("Not a valid number");
|
||||||
|
}
|
||||||
|
// ushort
|
||||||
|
else if (typeof(T) == typeof(ushort) || typeof(T) == typeof(ushort?))
|
||||||
|
{
|
||||||
|
if (ushort.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
||||||
|
return (T)(object)parsedValue;
|
||||||
|
UpdateGetError("Not a valid number");
|
||||||
|
}
|
||||||
|
// int
|
||||||
|
else if (typeof(T) == typeof(int) || typeof(T) == typeof(int?))
|
||||||
|
{
|
||||||
|
if (int.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
||||||
|
return (T)(object)parsedValue;
|
||||||
|
UpdateGetError("Not a valid number");
|
||||||
|
}
|
||||||
|
// uint
|
||||||
|
else if (typeof(T) == typeof(uint) || typeof(T) == typeof(uint?))
|
||||||
|
{
|
||||||
|
if (uint.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
||||||
|
return (T)(object)parsedValue;
|
||||||
|
UpdateGetError("Not a valid number");
|
||||||
|
}
|
||||||
|
// long
|
||||||
|
else if (typeof(T) == typeof(long) || typeof(T) == typeof(long?))
|
||||||
|
{
|
||||||
|
if (long.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
||||||
|
return (T)(object)parsedValue;
|
||||||
|
UpdateGetError("Not a valid number");
|
||||||
|
}
|
||||||
|
// ulong
|
||||||
|
else if (typeof(T) == typeof(ulong) || typeof(T) == typeof(ulong?))
|
||||||
|
{
|
||||||
|
if (ulong.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
||||||
|
return (T)(object)parsedValue;
|
||||||
|
UpdateGetError("Not a valid number");
|
||||||
|
}
|
||||||
|
// float
|
||||||
|
else if (typeof(T) == typeof(float) || typeof(T) == typeof(float?))
|
||||||
|
{
|
||||||
|
if (float.TryParse(value, NumberStyles.Any, Culture, out var parsedValue))
|
||||||
|
return (T)(object)parsedValue;
|
||||||
|
UpdateGetError("Not a valid number");
|
||||||
|
}
|
||||||
|
// double
|
||||||
|
else if (typeof(T) == typeof(double) || typeof(T) == typeof(double?))
|
||||||
|
{
|
||||||
|
if (double.TryParse(value, NumberStyles.Any, Culture, out var parsedValue))
|
||||||
|
return (T)(object)parsedValue;
|
||||||
|
UpdateGetError("Not a valid number");
|
||||||
|
}
|
||||||
|
// decimal
|
||||||
|
else if (typeof(T) == typeof(decimal) || typeof(T) == typeof(decimal?))
|
||||||
|
{
|
||||||
|
if (decimal.TryParse(value, NumberStyles.Any, Culture, out var parsedValue))
|
||||||
|
return (T)(object)parsedValue;
|
||||||
|
UpdateGetError("Not a valid number");
|
||||||
|
}
|
||||||
|
// guid
|
||||||
|
else if (typeof(T) == typeof(Guid) || typeof(T) == typeof(Guid?))
|
||||||
|
{
|
||||||
|
if (Guid.TryParse(value, out var parsedValue))
|
||||||
|
return (T)(object)parsedValue;
|
||||||
|
UpdateGetError("Not a valid GUID");
|
||||||
|
}
|
||||||
|
// enum
|
||||||
|
else if (IsNullableEnum(typeof(T)))
|
||||||
|
{
|
||||||
|
var enum_type = Nullable.GetUnderlyingType(typeof(T));
|
||||||
|
if (Enum.TryParse(enum_type, value, out var parsedValue))
|
||||||
|
return (T)parsedValue;
|
||||||
|
UpdateGetError("Not a value of " + enum_type.Name);
|
||||||
|
}
|
||||||
|
else if (typeof(T).IsEnum)
|
||||||
|
{
|
||||||
|
if (Enum.TryParse(typeof(T), value, out var parsedValue))
|
||||||
|
return (T)parsedValue;
|
||||||
|
UpdateGetError("Not a value of " + typeof(T).Name);
|
||||||
|
}
|
||||||
|
// datetime
|
||||||
|
else if (typeof(T) == typeof(DateTime) || typeof(T) == typeof(DateTime?))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (T)(object)DateTime.ParseExact(value, Format ?? Culture.DateTimeFormat.ShortDatePattern, Culture);
|
||||||
|
}
|
||||||
|
catch (FormatException)
|
||||||
|
{
|
||||||
|
UpdateGetError("Not a valid date time");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// timespan
|
||||||
|
else if (typeof(T) == typeof(TimeSpan) || typeof(T) == typeof(TimeSpan?))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (T)(object)TimeSpan.ParseExact(value, Format ?? DefaultTimeSpanFormat, Culture);
|
||||||
|
}
|
||||||
|
catch (FormatException)
|
||||||
|
{
|
||||||
|
UpdateGetError("Not a valid time span");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateGetError($"Conversion to type {typeof(T)} not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
UpdateGetError("Conversion error: " + e.Message);
|
||||||
|
}
|
||||||
|
|
||||||
TriggerError("Not a valid boolean");
|
return default(T);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Sbyte
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(sbyte?))
|
|
||||||
{
|
|
||||||
if (sbyte.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
||||||
return (T)(object)parsedValue;
|
|
||||||
|
|
||||||
TriggerError("Not a valid number");
|
protected virtual string ConvertToString(T arg)
|
||||||
}
|
{
|
||||||
/*
|
if (arg == null)
|
||||||
* Byte
|
return null; // <-- this catches all nullable values which are null. no nullchecks necessary below!
|
||||||
*/
|
try
|
||||||
else if (typeof(T) == typeof(byte) || typeof(T) == typeof(byte?))
|
{
|
||||||
{
|
// string
|
||||||
if (byte.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
if (typeof(T) == typeof(string))
|
||||||
return (T)(object)parsedValue;
|
return (string)(object)arg;
|
||||||
|
// char
|
||||||
|
if (typeof(T) == typeof(char))
|
||||||
|
return ((char)(object)arg).ToString(Culture);
|
||||||
|
if (typeof(T) == typeof(char?))
|
||||||
|
return ((char?)(object)arg).Value.ToString(Culture);
|
||||||
|
// bool
|
||||||
|
if (typeof(T) == typeof(bool))
|
||||||
|
return ((bool)(object)arg).ToString(CultureInfo.InvariantCulture);
|
||||||
|
if (typeof(T) == typeof(bool?))
|
||||||
|
return ((bool?)(object)arg).Value.ToString(CultureInfo.InvariantCulture);
|
||||||
|
// sbyte
|
||||||
|
if (typeof(T) == typeof(sbyte))
|
||||||
|
return ((sbyte)(object)arg).ToString(Format, Culture);
|
||||||
|
if (typeof(T) == typeof(sbyte?))
|
||||||
|
return ((sbyte?)(object)arg).Value.ToString(Format, Culture);
|
||||||
|
// byte
|
||||||
|
if (typeof(T) == typeof(byte))
|
||||||
|
return ((byte)(object)arg).ToString(Format, Culture);
|
||||||
|
if (typeof(T) == typeof(byte?))
|
||||||
|
return ((byte?)(object)arg).Value.ToString(Format, Culture);
|
||||||
|
// short
|
||||||
|
if (typeof(T) == typeof(short))
|
||||||
|
return ((short)(object)arg).ToString(Format, Culture);
|
||||||
|
if (typeof(T) == typeof(short?))
|
||||||
|
return ((short?)(object)arg).Value.ToString(Format, Culture);
|
||||||
|
// ushort
|
||||||
|
if (typeof(T) == typeof(ushort))
|
||||||
|
return ((ushort)(object)arg).ToString(Format, Culture);
|
||||||
|
if (typeof(T) == typeof(ushort?))
|
||||||
|
return ((ushort?)(object)arg).Value.ToString(Format, Culture);
|
||||||
|
// int
|
||||||
|
else if (typeof(T) == typeof(int))
|
||||||
|
return ((int)(object)arg).ToString(Format, Culture);
|
||||||
|
else if (typeof(T) == typeof(int?))
|
||||||
|
return ((int?)(object)arg).Value.ToString(Format, Culture);
|
||||||
|
// uint
|
||||||
|
else if (typeof(T) == typeof(uint))
|
||||||
|
return ((uint)(object)arg).ToString(Format, Culture);
|
||||||
|
else if (typeof(T) == typeof(uint?))
|
||||||
|
return ((uint?)(object)arg).Value.ToString(Format, Culture);
|
||||||
|
// long
|
||||||
|
else if (typeof(T) == typeof(long))
|
||||||
|
return ((long)(object)arg).ToString(Format, Culture);
|
||||||
|
else if (typeof(T) == typeof(long?))
|
||||||
|
return ((long?)(object)arg).Value.ToString(Format, Culture);
|
||||||
|
// ulong
|
||||||
|
else if (typeof(T) == typeof(ulong))
|
||||||
|
return ((ulong)(object)arg).ToString(Format, Culture);
|
||||||
|
else if (typeof(T) == typeof(ulong?))
|
||||||
|
return ((ulong?)(object)arg).Value.ToString(Format, Culture);
|
||||||
|
// float
|
||||||
|
else if (typeof(T) == typeof(float))
|
||||||
|
return ((float)(object)arg).ToString(Format, Culture);
|
||||||
|
else if (typeof(T) == typeof(float?))
|
||||||
|
return ((float?)(object)arg).Value.ToString(Format, Culture);
|
||||||
|
// double
|
||||||
|
else if (typeof(T) == typeof(double))
|
||||||
|
return ((double)(object)arg).ToString(Format, Culture);
|
||||||
|
else if (typeof(T) == typeof(double?))
|
||||||
|
return ((double?)(object)arg).Value.ToString(Format, Culture);
|
||||||
|
// decimal
|
||||||
|
else if (typeof(T) == typeof(decimal))
|
||||||
|
return ((decimal)(object)arg).ToString(Format, Culture);
|
||||||
|
else if (typeof(T) == typeof(decimal?))
|
||||||
|
return ((decimal?)(object)arg).Value.ToString(Format, Culture);
|
||||||
|
// guid
|
||||||
|
else if (typeof(T) == typeof(Guid))
|
||||||
|
{
|
||||||
|
var value = (Guid)(object)arg;
|
||||||
|
return value.ToString();
|
||||||
|
}
|
||||||
|
else if (typeof(T) == typeof(Guid?))
|
||||||
|
{
|
||||||
|
var value = (Guid?)(object)arg;
|
||||||
|
return value.Value.ToString();
|
||||||
|
}
|
||||||
|
// enum
|
||||||
|
else if (IsNullableEnum(typeof(T)))
|
||||||
|
{
|
||||||
|
var value = (Enum)(object)arg;
|
||||||
|
return value.ToString();
|
||||||
|
}
|
||||||
|
else if (typeof(T).IsEnum)
|
||||||
|
{
|
||||||
|
var value = (Enum)(object)arg;
|
||||||
|
return value.ToString();
|
||||||
|
}
|
||||||
|
// datetime
|
||||||
|
else if (typeof(T) == typeof(DateTime))
|
||||||
|
{
|
||||||
|
var value = (DateTime)(object)arg;
|
||||||
|
return value.ToString(Format ?? Culture.DateTimeFormat.ShortDatePattern, Culture);
|
||||||
|
}
|
||||||
|
else if (typeof(T) == typeof(DateTime?))
|
||||||
|
{
|
||||||
|
var value = (DateTime?)(object)arg;
|
||||||
|
return value.Value.ToString(Format ?? Culture.DateTimeFormat.ShortDatePattern, Culture);
|
||||||
|
}
|
||||||
|
// timespan
|
||||||
|
else if (typeof(T) == typeof(TimeSpan))
|
||||||
|
{
|
||||||
|
var value = (TimeSpan)(object)arg;
|
||||||
|
return value.ToString(Format ?? DefaultTimeSpanFormat, Culture);
|
||||||
|
}
|
||||||
|
else if (typeof(T) == typeof(TimeSpan?))
|
||||||
|
{
|
||||||
|
var value = (TimeSpan?)(object)arg;
|
||||||
|
return value.Value.ToString(Format ?? DefaultTimeSpanFormat, Culture);
|
||||||
|
}
|
||||||
|
return arg.ToString();
|
||||||
|
}
|
||||||
|
catch (FormatException e)
|
||||||
|
{
|
||||||
|
UpdateSetError("Conversion error: " + e.Message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TriggerError("Not a valid number");
|
public static bool IsNullableEnum(Type t)
|
||||||
}
|
{
|
||||||
/*
|
var u = Nullable.GetUnderlyingType(t);
|
||||||
* Short
|
return (u != null) && u.IsEnum;
|
||||||
*/
|
}
|
||||||
else if (typeof(T) == typeof(short) || typeof(T) == typeof(short?))
|
}
|
||||||
{
|
|
||||||
if (short.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
||||||
return (T)(object)parsedValue;
|
|
||||||
|
|
||||||
TriggerError("Not a valid number");
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Ushort
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(ushort) || typeof(T) == typeof(ushort?))
|
|
||||||
{
|
|
||||||
if (ushort.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
||||||
return (T)(object)parsedValue;
|
|
||||||
|
|
||||||
TriggerError("Not a valid number");
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Int
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(int) || typeof(T) == typeof(int?))
|
|
||||||
{
|
|
||||||
if (int.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
||||||
return (T)(object)parsedValue;
|
|
||||||
|
|
||||||
TriggerError("Not a valid number");
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Uint
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(uint) || typeof(T) == typeof(uint?))
|
|
||||||
{
|
|
||||||
if (uint.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
||||||
return (T)(object)parsedValue;
|
|
||||||
|
|
||||||
TriggerError("Not a valid number");
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Long
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(long) || typeof(T) == typeof(long?))
|
|
||||||
{
|
|
||||||
if (long.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
||||||
return (T)(object)parsedValue;
|
|
||||||
|
|
||||||
TriggerError("Not a valid number");
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Ulong
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(ulong) || typeof(T) == typeof(ulong?))
|
|
||||||
{
|
|
||||||
if (ulong.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
||||||
return (T)(object)parsedValue;
|
|
||||||
|
|
||||||
TriggerError("Not a valid number");
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Float
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(float) || typeof(T) == typeof(float?))
|
|
||||||
{
|
|
||||||
if (float.TryParse(value, NumberStyles.Any, Culture, out var parsedValue))
|
|
||||||
return (T)(object)parsedValue;
|
|
||||||
|
|
||||||
TriggerError("Not a valid number");
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Double
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(double) || typeof(T) == typeof(double?))
|
|
||||||
{
|
|
||||||
if (double.TryParse(value, NumberStyles.Any, Culture, out var parsedValue))
|
|
||||||
return (T)(object)parsedValue;
|
|
||||||
|
|
||||||
TriggerError("Not a valid number");
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Decimal
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(decimal) || typeof(T) == typeof(decimal?))
|
|
||||||
{
|
|
||||||
if (decimal.TryParse(value, NumberStyles.Any, Culture, out var parsedValue))
|
|
||||||
return (T)(object)parsedValue;
|
|
||||||
|
|
||||||
TriggerError("Not a valid number");
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Guid
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(Guid) || typeof(T) == typeof(Guid?))
|
|
||||||
{
|
|
||||||
if (Guid.TryParse(value, out var parsedValue))
|
|
||||||
return (T)(object)parsedValue;
|
|
||||||
|
|
||||||
TriggerError("Not a valid GUID");
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Enum
|
|
||||||
*/
|
|
||||||
else if (IsNullableEnum(typeof(T)))
|
|
||||||
{
|
|
||||||
var enum_type = Nullable.GetUnderlyingType(typeof(T));
|
|
||||||
|
|
||||||
if (Enum.TryParse(enum_type, value, out var parsedValue))
|
|
||||||
return (T)parsedValue;
|
|
||||||
|
|
||||||
TriggerError("Not a value of " + enum_type.Name);
|
|
||||||
}
|
|
||||||
else if (typeof(T).IsEnum)
|
|
||||||
{
|
|
||||||
if (Enum.TryParse(typeof(T), value, out var parsedValue))
|
|
||||||
return (T)parsedValue;
|
|
||||||
|
|
||||||
TriggerError("Not a value of " + typeof(T).Name);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* DateTime
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(DateTime) || typeof(T) == typeof(DateTime?))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return (T)(object)DateTime.ParseExact(value, Format ?? Culture.DateTimeFormat.ShortDatePattern, Culture);
|
|
||||||
}
|
|
||||||
catch (FormatException)
|
|
||||||
{
|
|
||||||
TriggerError("Not a valid date time");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Timespan
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(TimeSpan) || typeof(T) == typeof(TimeSpan?))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return (T)(object)TimeSpan.ParseExact(value, Format ?? DefaultTimeSpanFormat, Culture);
|
|
||||||
}
|
|
||||||
catch (FormatException)
|
|
||||||
{
|
|
||||||
TriggerError("Not a valid time span");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TriggerError($"Conversion to type {typeof(T)} not implemented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
TriggerError("Conversion error: " + e.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual string? ConvertToString(T? arg)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* This catches all null values. No additional null checks necessary.
|
|
||||||
*/
|
|
||||||
if (arg is null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* String
|
|
||||||
*/
|
|
||||||
if (typeof(T) == typeof(string))
|
|
||||||
{
|
|
||||||
return (string)(object)arg;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Char
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(char))
|
|
||||||
{
|
|
||||||
return ((char)(object)arg).ToString(Culture);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(char?))
|
|
||||||
{
|
|
||||||
return ((char?)(object)arg).Value.ToString(Culture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Bool
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(bool))
|
|
||||||
{
|
|
||||||
return ((bool)(object)arg).ToString(CultureInfo.InvariantCulture);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(bool?))
|
|
||||||
{
|
|
||||||
return ((bool?)(object)arg).Value.ToString(CultureInfo.InvariantCulture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Sbyte
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(sbyte))
|
|
||||||
{
|
|
||||||
return ((sbyte)(object)arg).ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(sbyte?))
|
|
||||||
{
|
|
||||||
return ((sbyte?)(object)arg).Value.ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Byte
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(byte))
|
|
||||||
{
|
|
||||||
return ((byte)(object)arg).ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(byte?))
|
|
||||||
{
|
|
||||||
return ((byte?)(object)arg).Value.ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Short
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(short))
|
|
||||||
{
|
|
||||||
return ((short)(object)arg).ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(short?))
|
|
||||||
{
|
|
||||||
return ((short?)(object)arg).Value.ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Ushort
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(ushort))
|
|
||||||
{
|
|
||||||
return ((ushort)(object)arg).ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(ushort?))
|
|
||||||
{
|
|
||||||
return ((ushort?)(object)arg).Value.ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Int
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(int))
|
|
||||||
{
|
|
||||||
return ((int)(object)arg).ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(int?))
|
|
||||||
{
|
|
||||||
return ((int?)(object)arg).Value.ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Uint
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(uint))
|
|
||||||
{
|
|
||||||
return ((uint)(object)arg).ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(uint?))
|
|
||||||
{
|
|
||||||
return ((uint?)(object)arg).Value.ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Long
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(long))
|
|
||||||
{
|
|
||||||
return ((long)(object)arg).ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(long?))
|
|
||||||
{
|
|
||||||
return ((long?)(object)arg).Value.ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Ulong
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(ulong))
|
|
||||||
{
|
|
||||||
return ((ulong)(object)arg).ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(ulong?))
|
|
||||||
{
|
|
||||||
return ((ulong?)(object)arg).Value.ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Float
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(float))
|
|
||||||
{
|
|
||||||
return ((float)(object)arg).ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(float?))
|
|
||||||
{
|
|
||||||
return ((float?)(object)arg).Value.ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Double
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(double))
|
|
||||||
{
|
|
||||||
return ((double)(object)arg).ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(double?))
|
|
||||||
{
|
|
||||||
return ((double?)(object)arg).Value.ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Decimal
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(decimal))
|
|
||||||
{
|
|
||||||
return ((decimal)(object)arg).ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(decimal?))
|
|
||||||
{
|
|
||||||
return ((decimal?)(object)arg).Value.ToString(Format, Culture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Guid
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(Guid))
|
|
||||||
{
|
|
||||||
var value = (Guid)(object)arg;
|
|
||||||
return value.ToString();
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(Guid?))
|
|
||||||
{
|
|
||||||
var value = (Guid?)(object)arg;
|
|
||||||
return value.Value.ToString();
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Enum
|
|
||||||
*/
|
|
||||||
else if (IsNullableEnum(typeof(T)))
|
|
||||||
{
|
|
||||||
var value = (Enum)(object)arg;
|
|
||||||
return value.ToString();
|
|
||||||
}
|
|
||||||
else if (typeof(T).IsEnum)
|
|
||||||
{
|
|
||||||
var value = (Enum)(object)arg;
|
|
||||||
return value.ToString();
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* DateTime
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(DateTime))
|
|
||||||
{
|
|
||||||
var value = (DateTime)(object)arg;
|
|
||||||
return value.ToString(Format ?? Culture.DateTimeFormat.ShortDatePattern, Culture);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(DateTime?))
|
|
||||||
{
|
|
||||||
var value = (DateTime?)(object)arg;
|
|
||||||
return value.Value.ToString(Format ?? Culture.DateTimeFormat.ShortDatePattern, Culture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Timespan
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(TimeSpan))
|
|
||||||
{
|
|
||||||
var value = (TimeSpan)(object)arg;
|
|
||||||
return value.ToString(Format ?? DefaultTimeSpanFormat, Culture);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(TimeSpan?))
|
|
||||||
{
|
|
||||||
var value = (TimeSpan?)(object)arg;
|
|
||||||
return value.Value.ToString(Format ?? DefaultTimeSpanFormat, Culture);
|
|
||||||
}
|
|
||||||
|
|
||||||
return arg.ToString();
|
|
||||||
}
|
|
||||||
catch (FormatException e)
|
|
||||||
{
|
|
||||||
TriggerError("Conversion error: " + e.Message);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsNullableEnum(Type t)
|
|
||||||
{
|
|
||||||
var u = Nullable.GetUnderlyingType(t);
|
|
||||||
|
|
||||||
return (u is not null) && u.IsEnum;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
using Connected.Extensions;
|
|
||||||
|
|
||||||
namespace Connected;
|
|
||||||
|
|
||||||
public class IsoDateConverter : Converter<DateTime, string>
|
|
||||||
{
|
|
||||||
protected override string ConvertValue(DateTime value) => value.ToIsoDateString();
|
|
||||||
|
|
||||||
protected override DateTime ConvertValueBack(string? value) => DateTime.TryParse(value, out var dateTime) ? dateTime : DateTime.MinValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class NullableIsoDateConverter : Converter<DateTime?, string?>
|
|
||||||
{
|
|
||||||
protected override string? ConvertValue(DateTime? value) => value?.ToIsoDateString();
|
|
||||||
|
|
||||||
protected override DateTime? ConvertValueBack(string? value) => DateTime.TryParse(value, out var dateTime) ? dateTime : null;
|
|
||||||
}
|
|
@ -1,390 +1,285 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
namespace Connected;
|
namespace Connected
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A universal T to double binding converter
|
|
||||||
///
|
|
||||||
/// Note: currently not in use. Should we ever use it, remove
|
|
||||||
/// the [ExcludeFromCodeCoverage] attribute
|
|
||||||
/// </summary>
|
|
||||||
[ExcludeFromCodeCoverage]
|
|
||||||
public class NumericConverter<T> : Converter<T, double>
|
|
||||||
{
|
{
|
||||||
|
|
||||||
protected override double ConvertValue(T? value)
|
/// <summary>
|
||||||
{
|
/// A universal T to double binding converter
|
||||||
if (value is null)
|
///
|
||||||
{
|
/// Note: currently not in use. Should we ever use it, remove
|
||||||
return double.NaN;
|
/// the [ExcludeFromCodeCoverage] attribute
|
||||||
}
|
/// </summary>
|
||||||
/*
|
[ExcludeFromCodeCoverage]
|
||||||
* Double
|
public class NumericConverter<T> : Converter<T, double>
|
||||||
*/
|
{
|
||||||
else if (typeof(T) == typeof(double))
|
|
||||||
{
|
|
||||||
return (double)(object)value;
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(double?))
|
|
||||||
{
|
|
||||||
return ((double?)(object)value).Value;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* String
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(string))
|
|
||||||
{
|
|
||||||
return double.Parse((string)(object)value, NumberStyles.Any, Culture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* SByte
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(sbyte))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble((sbyte)(object)value);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(sbyte?))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble(((sbyte?)(object)value).Value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Byte
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(byte))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble((byte)(object)value);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(byte?))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble(((byte?)(object)value).Value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Short
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(short))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble((short)(object)value);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(short?))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble(((short?)(object)value).Value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Ushort
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(ushort))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble((ushort)(object)value);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(ushort?))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble(((ushort?)(object)value).Value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Int
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(int))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble((int)(object)value);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(int?))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble(((int?)(object)value).Value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Uint
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(uint))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble((uint)(object)value);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(uint?))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble(((uint?)(object)value).Value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Long
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(long))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble((long)(object)value);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(long?))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble(((long?)(object)value).Value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Ulong
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(ulong))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble((ulong)(object)value);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(ulong?))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble(((ulong?)(object)value).Value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Float
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(float))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble((float)(object)value);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(float?))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble(((float?)(object)value).Value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Deimal
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(decimal))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble((decimal)(object)value);
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(decimal?))
|
|
||||||
{
|
|
||||||
return System.Convert.ToDouble(((decimal?)(object)value).Value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TriggerError("Unable to convert to double from type " + typeof(T).Name);
|
|
||||||
return double.NaN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override T? ConvertValueBack(double value)
|
public NumericConverter()
|
||||||
{
|
{
|
||||||
/*
|
SetFunc = OnSet;
|
||||||
* Double
|
GetFunc = OnGet;
|
||||||
*/
|
}
|
||||||
if (typeof(T) == typeof(double) || typeof(T) == typeof(double?))
|
|
||||||
{
|
|
||||||
return (T)(object)value;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* String
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(string))
|
|
||||||
{
|
|
||||||
return (T)(object)value.ToString(Culture);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Sbyte
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(sbyte?))
|
|
||||||
{
|
|
||||||
return (T)(object)System.Convert.ToSByte(value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Byte
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(byte) || typeof(T) == typeof(byte?))
|
|
||||||
{
|
|
||||||
return (T)(object)System.Convert.ToByte(value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Short
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(short) || typeof(T) == typeof(short?))
|
|
||||||
{
|
|
||||||
return (T)(object)System.Convert.ToInt16(value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Ushort
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(ushort) || typeof(T) == typeof(ushort?))
|
|
||||||
{
|
|
||||||
return (T)(object)System.Convert.ToUInt16(value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Int
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(int) || typeof(T) == typeof(int?))
|
|
||||||
{
|
|
||||||
return (T)(object)System.Convert.ToInt32(value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Uint
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(uint) || typeof(T) == typeof(uint?))
|
|
||||||
{
|
|
||||||
return (T)(object)System.Convert.ToUInt32(value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Long
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(long) || typeof(T) == typeof(long?))
|
|
||||||
{
|
|
||||||
return (T)(object)System.Convert.ToInt64(value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Ulong
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(ulong) || typeof(T) == typeof(ulong?))
|
|
||||||
{
|
|
||||||
return (T)(object)System.Convert.ToUInt64(value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Float
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(float) || typeof(T) == typeof(float?))
|
|
||||||
{
|
|
||||||
return (T)(object)System.Convert.ToSingle(value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Decimal
|
|
||||||
*/
|
|
||||||
else if (typeof(T) == typeof(decimal) || typeof(T) == typeof(decimal?))
|
|
||||||
{
|
|
||||||
return (T)(object)System.Convert.ToDecimal(value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TriggerError($"Conversion to type {typeof(T)} not implemented");
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Floating Point comparison
|
private T OnGet(double value)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// double
|
||||||
|
if (typeof(T) == typeof(double) || typeof(T) == typeof(double?))
|
||||||
|
return (T)(object)value;
|
||||||
|
// string
|
||||||
|
else if (typeof(T) == typeof(string))
|
||||||
|
return (T)(object)value.ToString(Culture);
|
||||||
|
// sbyte
|
||||||
|
else if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(sbyte?))
|
||||||
|
return (T)(object)Convert.ToSByte(value);
|
||||||
|
// byte
|
||||||
|
else if (typeof(T) == typeof(byte) || typeof(T) == typeof(byte?))
|
||||||
|
return (T)(object)Convert.ToByte(value);
|
||||||
|
// short
|
||||||
|
else if (typeof(T) == typeof(short) || typeof(T) == typeof(short?))
|
||||||
|
return (T)(object)Convert.ToInt16(value);
|
||||||
|
// ushort
|
||||||
|
else if (typeof(T) == typeof(ushort) || typeof(T) == typeof(ushort?))
|
||||||
|
return (T)(object)Convert.ToUInt16(value);
|
||||||
|
// int
|
||||||
|
else if (typeof(T) == typeof(int) || typeof(T) == typeof(int?))
|
||||||
|
return (T)(object)Convert.ToInt32(value);
|
||||||
|
// uint
|
||||||
|
else if (typeof(T) == typeof(uint) || typeof(T) == typeof(uint?))
|
||||||
|
return (T)(object)Convert.ToUInt32(value);
|
||||||
|
// long
|
||||||
|
else if (typeof(T) == typeof(long) || typeof(T) == typeof(long?))
|
||||||
|
return (T)(object)Convert.ToInt64(value);
|
||||||
|
// ulong
|
||||||
|
else if (typeof(T) == typeof(ulong) || typeof(T) == typeof(ulong?))
|
||||||
|
return (T)(object)Convert.ToUInt64(value);
|
||||||
|
// float
|
||||||
|
else if (typeof(T) == typeof(float) || typeof(T) == typeof(float?))
|
||||||
|
return (T)(object)Convert.ToSingle(value);
|
||||||
|
// decimal
|
||||||
|
else if (typeof(T) == typeof(decimal) || typeof(T) == typeof(decimal?))
|
||||||
|
return (T)(object)Convert.ToDecimal(value);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateGetError($"Conversion to type {typeof(T)} not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
UpdateGetError("Conversion error: " + e.Message);
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
|
||||||
private const double MinNormal = 2.2250738585072014E-308d;
|
private double OnSet(T arg)
|
||||||
|
{
|
||||||
|
if (arg == null)
|
||||||
|
return double.NaN; // <-- this catches all nullable values which are null. no nullchecks necessary below!
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// double
|
||||||
|
if (typeof(T) == typeof(double))
|
||||||
|
return (double)(object)arg;
|
||||||
|
else if (typeof(T) == typeof(double?))
|
||||||
|
return ((double?)(object)arg).Value;
|
||||||
|
// string
|
||||||
|
if (typeof(T) == typeof(string))
|
||||||
|
return double.Parse((string)(object)arg, NumberStyles.Any, Culture);
|
||||||
|
// sbyte
|
||||||
|
if (typeof(T) == typeof(sbyte))
|
||||||
|
return Convert.ToDouble((sbyte)(object)arg);
|
||||||
|
if (typeof(T) == typeof(sbyte?))
|
||||||
|
return Convert.ToDouble(((sbyte?)(object)arg).Value);
|
||||||
|
// byte
|
||||||
|
if (typeof(T) == typeof(byte))
|
||||||
|
return Convert.ToDouble((byte)(object)arg);
|
||||||
|
if (typeof(T) == typeof(byte?))
|
||||||
|
return Convert.ToDouble(((byte?)(object)arg).Value);
|
||||||
|
// short
|
||||||
|
if (typeof(T) == typeof(short))
|
||||||
|
return Convert.ToDouble((short)(object)arg);
|
||||||
|
if (typeof(T) == typeof(short?))
|
||||||
|
return Convert.ToDouble(((short?)(object)arg).Value);
|
||||||
|
// ushort
|
||||||
|
if (typeof(T) == typeof(ushort))
|
||||||
|
return Convert.ToDouble((ushort)(object)arg);
|
||||||
|
if (typeof(T) == typeof(ushort?))
|
||||||
|
return Convert.ToDouble(((ushort?)(object)arg).Value);
|
||||||
|
// int
|
||||||
|
else if (typeof(T) == typeof(int))
|
||||||
|
return Convert.ToDouble((int)(object)arg);
|
||||||
|
else if (typeof(T) == typeof(int?))
|
||||||
|
return Convert.ToDouble(((int?)(object)arg).Value);
|
||||||
|
// uint
|
||||||
|
else if (typeof(T) == typeof(uint))
|
||||||
|
return Convert.ToDouble((uint)(object)arg);
|
||||||
|
else if (typeof(T) == typeof(uint?))
|
||||||
|
return Convert.ToDouble(((uint?)(object)arg).Value);
|
||||||
|
// long
|
||||||
|
else if (typeof(T) == typeof(long))
|
||||||
|
return Convert.ToDouble((long)(object)arg);
|
||||||
|
else if (typeof(T) == typeof(long?))
|
||||||
|
return Convert.ToDouble(((long?)(object)arg).Value);
|
||||||
|
// ulong
|
||||||
|
else if (typeof(T) == typeof(ulong))
|
||||||
|
return Convert.ToDouble((ulong)(object)arg);
|
||||||
|
else if (typeof(T) == typeof(ulong?))
|
||||||
|
return Convert.ToDouble(((ulong?)(object)arg).Value);
|
||||||
|
// float
|
||||||
|
else if (typeof(T) == typeof(float))
|
||||||
|
return Convert.ToDouble((float)(object)arg);
|
||||||
|
else if (typeof(T) == typeof(float?))
|
||||||
|
return Convert.ToDouble(((float?)(object)arg).Value);
|
||||||
|
// decimal
|
||||||
|
else if (typeof(T) == typeof(decimal))
|
||||||
|
return Convert.ToDouble((decimal)(object)arg);
|
||||||
|
else if (typeof(T) == typeof(decimal?))
|
||||||
|
return Convert.ToDouble(((decimal?)(object)arg).Value);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateSetError("Unable to convert to double from type " + typeof(T).Name);
|
||||||
|
return double.NaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (FormatException e)
|
||||||
|
{
|
||||||
|
UpdateSetError("Conversion error: " + e.Message);
|
||||||
|
return double.NaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static bool AreEqual(double a, double b, double epsilon = MinNormal)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Copyright (c) Michael Borgwardt
|
|
||||||
*/
|
|
||||||
var absA = Math.Abs(a);
|
|
||||||
var absB = Math.Abs(b);
|
|
||||||
var diff = Math.Abs(a - b);
|
|
||||||
/*
|
|
||||||
* Shortcut, handles infinities
|
|
||||||
*/
|
|
||||||
if (a.Equals(b))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (a == 0 || b == 0 || absA + absB < MinNormal)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* a or b is zero or both are extremely close to it
|
|
||||||
* relative error is less meaningful here
|
|
||||||
*/
|
|
||||||
return diff < epsilon * MinNormal;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Use relative error
|
|
||||||
*/
|
|
||||||
return diff / (absA + absB) < epsilon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#region --> Floating Point comparison
|
||||||
}
|
|
||||||
|
const double MinNormal = 2.2250738585072014E-308d;
|
||||||
[ExcludeFromCodeCoverage]
|
|
||||||
internal static class Number
|
public static bool AreEqual(double a, double b, double epsilon = MinNormal)
|
||||||
{
|
{
|
||||||
public static T? To<T>(double d)
|
// Copyright (c) Michael Borgwardt
|
||||||
{
|
var absA = Math.Abs(a);
|
||||||
if (typeof(T) == typeof(sbyte) && d >= sbyte.MinValue && sbyte.MaxValue >= d)
|
var absB = Math.Abs(b);
|
||||||
return (T)(object)Convert.ToSByte(d);
|
var diff = Math.Abs(a - b);
|
||||||
if (typeof(T) == typeof(byte) && d >= byte.MinValue && byte.MaxValue >= d)
|
|
||||||
return (T)(object)Convert.ToByte(d);
|
if (a.Equals(b))
|
||||||
if (typeof(T) == typeof(short) && d >= short.MinValue && short.MaxValue >= d)
|
{ // shortcut, handles infinities
|
||||||
return (T)(object)Convert.ToInt16(d);
|
return true;
|
||||||
if (typeof(T) == typeof(ushort) && d >= ushort.MinValue && ushort.MaxValue >= d)
|
}
|
||||||
return (T)(object)Convert.ToUInt16(d);
|
else if (a == 0 || b == 0 || absA + absB < MinNormal)
|
||||||
if (typeof(T) == typeof(int) && d >= int.MinValue && int.MaxValue >= d)
|
{
|
||||||
return (T)(object)Convert.ToInt32(d);
|
// a or b is zero or both are extremely close to it
|
||||||
if (typeof(T) == typeof(uint) && d >= uint.MinValue && uint.MaxValue >= d)
|
// relative error is less meaningful here
|
||||||
return (T)(object)Convert.ToUInt32(d);
|
return diff < (epsilon * MinNormal);
|
||||||
if (typeof(T) == typeof(long) && d >= long.MinValue && long.MaxValue >= d)
|
}
|
||||||
return (T)(object)Convert.ToInt64(d);
|
else
|
||||||
if (typeof(T) == typeof(ulong) && d >= ulong.MinValue && ulong.MaxValue >= d)
|
{ // use relative error
|
||||||
return (T)(object)Convert.ToUInt64(d);
|
return diff / (absA + absB) < epsilon;
|
||||||
if (typeof(T) == typeof(float) && d >= float.MinValue && float.MaxValue >= d)
|
}
|
||||||
return (T)(object)Convert.ToSingle(d);
|
}
|
||||||
if (typeof(T) == typeof(double) && d >= double.MinValue && double.MaxValue >= d)
|
|
||||||
return (T)(object)Convert.ToDouble(d);
|
#endregion
|
||||||
if (typeof(T) == typeof(decimal) && (decimal)d >= decimal.MinValue && decimal.MaxValue >= (decimal)d)
|
}
|
||||||
return (T)(object)Convert.ToDecimal(d);
|
|
||||||
if (typeof(T) == typeof(sbyte?) && d >= sbyte.MinValue && sbyte.MaxValue >= d)
|
[ExcludeFromCodeCoverage]
|
||||||
return (T)(object)Convert.ToSByte(d);
|
internal static class Num
|
||||||
if (typeof(T) == typeof(byte?) && d >= byte.MinValue && byte.MaxValue >= d)
|
{
|
||||||
return (T)(object)Convert.ToByte(d);
|
public static T To<T>(double d)
|
||||||
if (typeof(T) == typeof(short?) && d >= short.MinValue && short.MaxValue >= d)
|
{
|
||||||
return (T)(object)Convert.ToInt16(d);
|
if (typeof(T) == typeof(sbyte) && d >= sbyte.MinValue && sbyte.MaxValue >= d)
|
||||||
if (typeof(T) == typeof(ushort?) && d >= ushort.MinValue && ushort.MaxValue >= d)
|
return (T)(object)Convert.ToSByte(d);
|
||||||
return (T)(object)Convert.ToUInt16(d);
|
if (typeof(T) == typeof(byte) && d >= byte.MinValue && byte.MaxValue >= d)
|
||||||
if (typeof(T) == typeof(int?) && d >= int.MinValue && int.MaxValue >= d)
|
return (T)(object)Convert.ToByte(d);
|
||||||
return (T)(object)Convert.ToInt32(d);
|
if (typeof(T) == typeof(short) && d >= short.MinValue && short.MaxValue >= d)
|
||||||
if (typeof(T) == typeof(uint?) && d >= uint.MinValue && uint.MaxValue >= d)
|
return (T)(object)Convert.ToInt16(d);
|
||||||
return (T)(object)Convert.ToUInt32(d);
|
if (typeof(T) == typeof(ushort) && d >= ushort.MinValue && ushort.MaxValue >= d)
|
||||||
if (typeof(T) == typeof(long?) && d >= long.MinValue && long.MaxValue >= d)
|
return (T)(object)Convert.ToUInt16(d);
|
||||||
return (T)(object)Convert.ToInt64(d);
|
if (typeof(T) == typeof(int) && d >= int.MinValue && int.MaxValue >= d)
|
||||||
if (typeof(T) == typeof(ulong?) && d >= ulong.MinValue && ulong.MaxValue >= d)
|
return (T)(object)Convert.ToInt32(d);
|
||||||
return (T)(object)Convert.ToUInt64(d);
|
if (typeof(T) == typeof(uint) && d >= uint.MinValue && uint.MaxValue >= d)
|
||||||
if (typeof(T) == typeof(float?) && d >= float.MinValue && float.MaxValue >= d)
|
return (T)(object)Convert.ToUInt32(d);
|
||||||
return (T)(object)Convert.ToSingle(d);
|
if (typeof(T) == typeof(long) && d >= long.MinValue && long.MaxValue >= d)
|
||||||
if (typeof(T) == typeof(double?) && d >= double.MinValue && double.MaxValue >= d)
|
return (T)(object)Convert.ToInt64(d);
|
||||||
return (T)(object)Convert.ToDouble(d);
|
if (typeof(T) == typeof(ulong) && d >= ulong.MinValue && ulong.MaxValue >= d)
|
||||||
if (typeof(T) == typeof(decimal?) && (decimal)d >= decimal.MinValue && decimal.MaxValue >= (decimal)d)
|
return (T)(object)Convert.ToUInt64(d);
|
||||||
return (T)(object)Convert.ToDecimal(d);
|
if (typeof(T) == typeof(float) && d >= float.MinValue && float.MaxValue >= d)
|
||||||
|
return (T)(object)Convert.ToSingle(d);
|
||||||
return default;
|
if (typeof(T) == typeof(double) && d >= double.MinValue && double.MaxValue >= d)
|
||||||
}
|
return (T)(object)Convert.ToDouble(d);
|
||||||
public static double From<T>(T v)
|
if (typeof(T) == typeof(decimal) && (decimal)d >= decimal.MinValue && decimal.MaxValue >= (decimal)d)
|
||||||
{
|
return (T)(object)Convert.ToDecimal(d);
|
||||||
if (typeof(T) == typeof(sbyte))
|
if (typeof(T) == typeof(sbyte?) && d >= sbyte.MinValue && sbyte.MaxValue >= d)
|
||||||
return Convert.ToDouble((sbyte)(object)v);
|
return (T)(object)Convert.ToSByte(d);
|
||||||
if (typeof(T) == typeof(byte))
|
if (typeof(T) == typeof(byte?) && d >= byte.MinValue && byte.MaxValue >= d)
|
||||||
return Convert.ToDouble((byte)(object)v);
|
return (T)(object)Convert.ToByte(d);
|
||||||
if (typeof(T) == typeof(short))
|
if (typeof(T) == typeof(short?) && d >= short.MinValue && short.MaxValue >= d)
|
||||||
return Convert.ToDouble((short)(object)v);
|
return (T)(object)Convert.ToInt16(d);
|
||||||
if (typeof(T) == typeof(ushort))
|
if (typeof(T) == typeof(ushort?) && d >= ushort.MinValue && ushort.MaxValue >= d)
|
||||||
return Convert.ToDouble((ushort)(object)v);
|
return (T)(object)Convert.ToUInt16(d);
|
||||||
if (typeof(T) == typeof(int))
|
if (typeof(T) == typeof(int?) && d >= int.MinValue && int.MaxValue >= d)
|
||||||
return Convert.ToDouble((int)(object)v);
|
return (T)(object)Convert.ToInt32(d);
|
||||||
if (typeof(T) == typeof(uint))
|
if (typeof(T) == typeof(uint?) && d >= uint.MinValue && uint.MaxValue >= d)
|
||||||
return Convert.ToDouble((uint)(object)v);
|
return (T)(object)Convert.ToUInt32(d);
|
||||||
if (typeof(T) == typeof(long))
|
if (typeof(T) == typeof(long?) && d >= long.MinValue && long.MaxValue >= d)
|
||||||
return Convert.ToDouble((long)(object)v);
|
return (T)(object)Convert.ToInt64(d);
|
||||||
if (typeof(T) == typeof(ulong))
|
if (typeof(T) == typeof(ulong?) && d >= ulong.MinValue && ulong.MaxValue >= d)
|
||||||
return Convert.ToDouble((ulong)(object)v);
|
return (T)(object)Convert.ToUInt64(d);
|
||||||
if (typeof(T) == typeof(float))
|
if (typeof(T) == typeof(float?) && d >= float.MinValue && float.MaxValue >= d)
|
||||||
return Convert.ToDouble((float)(object)v);
|
return (T)(object)Convert.ToSingle(d);
|
||||||
if (typeof(T) == typeof(double))
|
if (typeof(T) == typeof(double?) && d >= double.MinValue && double.MaxValue >= d)
|
||||||
return Convert.ToDouble((double)(object)v);
|
return (T)(object)Convert.ToDouble(d);
|
||||||
if (typeof(T) == typeof(decimal))
|
if (typeof(T) == typeof(decimal?) && (decimal)d >= decimal.MinValue && decimal.MaxValue >= (decimal)d)
|
||||||
return Convert.ToDouble((decimal)(object)v);
|
return (T)(object)Convert.ToDecimal(d);
|
||||||
if (typeof(T) == typeof(sbyte?))
|
return default;
|
||||||
return Convert.ToDouble((sbyte?)(object)v);
|
}
|
||||||
if (typeof(T) == typeof(byte?))
|
public static double From<T>(T v)
|
||||||
return Convert.ToDouble((byte?)(object)v);
|
{
|
||||||
if (typeof(T) == typeof(short?))
|
if (typeof(T) == typeof(sbyte))
|
||||||
return Convert.ToDouble((short?)(object)v);
|
return Convert.ToDouble((sbyte)(object)v);
|
||||||
if (typeof(T) == typeof(ushort?))
|
if (typeof(T) == typeof(byte))
|
||||||
return Convert.ToDouble((ushort?)(object)v);
|
return Convert.ToDouble((byte)(object)v);
|
||||||
if (typeof(T) == typeof(int?))
|
if (typeof(T) == typeof(short))
|
||||||
return Convert.ToDouble((int?)(object)v);
|
return Convert.ToDouble((short)(object)v);
|
||||||
if (typeof(T) == typeof(uint?))
|
if (typeof(T) == typeof(ushort))
|
||||||
return Convert.ToDouble((uint?)(object)v);
|
return Convert.ToDouble((ushort)(object)v);
|
||||||
if (typeof(T) == typeof(long?))
|
if (typeof(T) == typeof(int))
|
||||||
return Convert.ToDouble((long?)(object)v);
|
return Convert.ToDouble((int)(object)v);
|
||||||
if (typeof(T) == typeof(ulong?))
|
if (typeof(T) == typeof(uint))
|
||||||
return Convert.ToDouble((ulong?)(object)v);
|
return Convert.ToDouble((uint)(object)v);
|
||||||
if (typeof(T) == typeof(float?))
|
if (typeof(T) == typeof(long))
|
||||||
return Convert.ToDouble((float?)(object)v);
|
return Convert.ToDouble((long)(object)v);
|
||||||
if (typeof(T) == typeof(double?))
|
if (typeof(T) == typeof(ulong))
|
||||||
return Convert.ToDouble((double?)(object)v);
|
return Convert.ToDouble((ulong)(object)v);
|
||||||
if (typeof(T) == typeof(decimal?))
|
if (typeof(T) == typeof(float))
|
||||||
return Convert.ToDouble((decimal?)(object)v);
|
return Convert.ToDouble((float)(object)v);
|
||||||
|
if (typeof(T) == typeof(double))
|
||||||
return default;
|
return Convert.ToDouble((double)(object)v);
|
||||||
}
|
if (typeof(T) == typeof(decimal))
|
||||||
|
return Convert.ToDouble((decimal)(object)v);
|
||||||
|
if (typeof(T) == typeof(sbyte?))
|
||||||
|
return Convert.ToDouble((sbyte?)(object)v);
|
||||||
|
if (typeof(T) == typeof(byte?))
|
||||||
|
return Convert.ToDouble((byte?)(object)v);
|
||||||
|
if (typeof(T) == typeof(short?))
|
||||||
|
return Convert.ToDouble((short?)(object)v);
|
||||||
|
if (typeof(T) == typeof(ushort?))
|
||||||
|
return Convert.ToDouble((ushort?)(object)v);
|
||||||
|
if (typeof(T) == typeof(int?))
|
||||||
|
return Convert.ToDouble((int?)(object)v);
|
||||||
|
if (typeof(T) == typeof(uint?))
|
||||||
|
return Convert.ToDouble((uint?)(object)v);
|
||||||
|
if (typeof(T) == typeof(long?))
|
||||||
|
return Convert.ToDouble((long?)(object)v);
|
||||||
|
if (typeof(T) == typeof(ulong?))
|
||||||
|
return Convert.ToDouble((ulong?)(object)v);
|
||||||
|
if (typeof(T) == typeof(float?))
|
||||||
|
return Convert.ToDouble((float?)(object)v);
|
||||||
|
if (typeof(T) == typeof(double?))
|
||||||
|
return Convert.ToDouble((double?)(object)v);
|
||||||
|
if (typeof(T) == typeof(decimal?))
|
||||||
|
return Convert.ToDouble((decimal?)(object)v);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,61 @@
|
|||||||
using Connected.Components;
|
namespace Connected
|
||||||
|
|
||||||
namespace Connected.Utilities.BindingConverters;
|
|
||||||
|
|
||||||
public class RangeConverter<T> : ToStringConverter<Range<T>>
|
|
||||||
{
|
{
|
||||||
private readonly DefaultConverter<T> _converter;
|
public class RangeConverter<T> : Converter<Components.Range<T>>
|
||||||
|
{
|
||||||
|
readonly DefaultConverter<T> _converter;
|
||||||
|
|
||||||
public RangeConverter() => _converter = new DefaultConverter<T>();
|
public RangeConverter()
|
||||||
|
{
|
||||||
|
_converter = new DefaultConverter<T>();
|
||||||
|
|
||||||
protected override string? ConvertValue(Range<T>? value) => value is not null
|
SetFunc = OnSet;
|
||||||
? Join(_converter.Convert(value.Start), _converter.Convert(value.End))
|
GetFunc = OnGet;
|
||||||
: string.Empty;
|
}
|
||||||
|
|
||||||
protected override Range<T>? ConvertValueBack(string? value)
|
private Components.Range<T> OnGet(string value)
|
||||||
{
|
{
|
||||||
return !Split(value, out var valueStart, out var valueEnd)
|
if (!Split(value, out var valueStart, out var valueEnd))
|
||||||
? null
|
return null;
|
||||||
: new Range<T>(_converter.ConvertBack(valueStart), _converter.ConvertBack(valueEnd));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Join(string? valueStart, string? valueEnd) => string.IsNullOrEmpty(valueStart) && string.IsNullOrEmpty(valueEnd) ? string.Empty : $"[{valueStart};{valueEnd}]";
|
return new Components.Range<T>(_converter.Get(valueStart), _converter.Get(valueEnd));
|
||||||
|
}
|
||||||
|
|
||||||
public static bool Split(string? value, out string? valueStart, out string? valueEnd)
|
private string OnSet(Components.Range<T> arg)
|
||||||
{
|
{
|
||||||
valueStart = valueEnd = string.Empty;
|
if (arg == null)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(value) || value[0] != '[' || value[^1] != ']')
|
return Join(_converter.Set(arg.Start), _converter.Set(arg.End));
|
||||||
return false;
|
}
|
||||||
|
|
||||||
var idx = value.IndexOf(';');
|
public static string Join(string valueStart, string valueEnd)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(valueStart) && string.IsNullOrEmpty(valueEnd))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
if (idx < 1)
|
return $"[{valueStart};{valueEnd}]";
|
||||||
return false;
|
}
|
||||||
|
|
||||||
valueStart = value[1..idx];
|
public static bool Split(string value, out string valueStart, out string valueEnd)
|
||||||
valueEnd = value[(idx + 1)..^1];
|
{
|
||||||
|
valueStart = valueEnd = string.Empty;
|
||||||
|
|
||||||
return true;
|
if (string.IsNullOrEmpty(value) || value[0] != '[' || value[^1] != ']')
|
||||||
}
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var idx = value.IndexOf(';');
|
||||||
|
|
||||||
|
if (idx < 1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
valueStart = value[1..idx];
|
||||||
|
valueEnd = value[(idx + 1)..^1];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user