Support more cases for date parsing
We didn't have support for DateTimeOffset, nor support for parsing formats with nullable DateTime. Added E2E tests for bind + DateTime/DateTimeOffset. Added E2E tests for 'manual bind' with number and date field. These can't use `@bind` without a compiler update. This PR will add the runtime support we need, so we can update the compiler.
This commit is contained in:
parent
1e6739f108
commit
80f71bcd1f
|
|
@ -46,6 +46,9 @@ namespace Microsoft.AspNetCore.Components
|
||||||
public static partial class BindMethods
|
public static partial class BindMethods
|
||||||
{
|
{
|
||||||
public static string GetValue(System.DateTime value, string format) { throw null; }
|
public static string GetValue(System.DateTime value, string format) { throw null; }
|
||||||
|
public static string GetValue(System.DateTimeOffset value, string format) { throw null; }
|
||||||
|
public static string GetValue(System.DateTimeOffset? value, string format) { throw null; }
|
||||||
|
public static string GetValue(System.DateTime? value, string format) { throw null; }
|
||||||
public static T GetValue<T>(T value) { throw null; }
|
public static T GetValue<T>(T value) { throw null; }
|
||||||
}
|
}
|
||||||
[System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false, Inherited=true)]
|
[System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false, Inherited=true)]
|
||||||
|
|
@ -124,6 +127,8 @@ namespace Microsoft.AspNetCore.Components
|
||||||
public static partial class EventCallbackFactoryBinderExtensions
|
public static partial class EventCallbackFactoryBinderExtensions
|
||||||
{
|
{
|
||||||
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<bool> setter, bool existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<bool> setter, bool existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<System.DateTimeOffset> setter, System.DateTimeOffset existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<System.DateTimeOffset> setter, System.DateTimeOffset existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<System.DateTime> setter, System.DateTime existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<System.DateTime> setter, System.DateTime existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<System.DateTime> setter, System.DateTime existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; }
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<System.DateTime> setter, System.DateTime existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<decimal> setter, decimal existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<decimal> setter, decimal existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
|
|
@ -131,7 +136,10 @@ namespace Microsoft.AspNetCore.Components
|
||||||
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<int> setter, int existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<int> setter, int existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<long> setter, long existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<long> setter, long existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<bool?> setter, bool? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<bool?> setter, bool? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<System.DateTimeOffset?> setter, System.DateTimeOffset? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<System.DateTimeOffset?> setter, System.DateTimeOffset? existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<System.DateTime?> setter, System.DateTime? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<System.DateTime?> setter, System.DateTime? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<System.DateTime?> setter, System.DateTime? existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<decimal?> setter, decimal? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<decimal?> setter, decimal? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<double?> setter, double? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<double?> setter, double? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<int?> setter, int? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<int?> setter, int? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,25 @@ namespace Microsoft.AspNetCore.Components
|
||||||
value == default ? null
|
value == default ? null
|
||||||
: (format == null ? value.ToString() : value.ToString(format));
|
: (format == null ? value.ToString() : value.ToString(format));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Not intended to be used directly.
|
||||||
|
/// </summary>
|
||||||
|
public static string GetValue(DateTime? value, string format) =>
|
||||||
|
value == default ? null
|
||||||
|
: (format == null ? value.ToString() : value.Value.ToString(format));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Not intended to be used directly.
|
||||||
|
/// </summary>
|
||||||
|
public static string GetValue(DateTimeOffset value, string format) =>
|
||||||
|
value == default ? null
|
||||||
|
: (format == null ? value.ToString() : value.ToString(format));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Not intended to be used directly.
|
||||||
|
/// </summary>
|
||||||
|
public static string GetValue(DateTimeOffset? value, string format) =>
|
||||||
|
value == default ? null
|
||||||
|
: (format == null ? value.ToString() : value.Value.ToString(format));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
|
|
@ -26,6 +25,7 @@ namespace Microsoft.AspNetCore.Components
|
||||||
public static class EventCallbackFactoryBinderExtensions
|
public static class EventCallbackFactoryBinderExtensions
|
||||||
{
|
{
|
||||||
private delegate bool BindConverter<T>(object obj, CultureInfo culture, out T value);
|
private delegate bool BindConverter<T>(object obj, CultureInfo culture, out T value);
|
||||||
|
private delegate bool BindConverterWithFormat<T>(object obj, CultureInfo culture, string format, out T value);
|
||||||
|
|
||||||
// Perf: conversion delegates are written as static funcs so we can prevent
|
// Perf: conversion delegates are written as static funcs so we can prevent
|
||||||
// allocations for these simple cases.
|
// allocations for these simple cases.
|
||||||
|
|
@ -261,9 +261,16 @@ namespace Microsoft.AspNetCore.Components
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BindConverter<DateTime> ConvertToDateTime = ConvertToDateTimeCore;
|
private static BindConverter<DateTime> ConvertToDateTime = ConvertToDateTimeCore;
|
||||||
|
private static BindConverterWithFormat<DateTime> ConvertToDateTimeWithFormat = ConvertToDateTimeCore;
|
||||||
private static BindConverter<DateTime?> ConvertToNullableDateTime = ConvertToNullableDateTimeCore;
|
private static BindConverter<DateTime?> ConvertToNullableDateTime = ConvertToNullableDateTimeCore;
|
||||||
|
private static BindConverterWithFormat<DateTime?> ConvertToNullableDateTimeWithFormat = ConvertToNullableDateTimeCore;
|
||||||
|
|
||||||
private static bool ConvertToDateTimeCore(object obj, CultureInfo culture, out DateTime value)
|
private static bool ConvertToDateTimeCore(object obj, CultureInfo culture, out DateTime value)
|
||||||
|
{
|
||||||
|
return ConvertToDateTimeCore(obj, culture, format: null, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ConvertToDateTimeCore(object obj, CultureInfo culture, string format, out DateTime value)
|
||||||
{
|
{
|
||||||
var text = (string)obj;
|
var text = (string)obj;
|
||||||
if (string.IsNullOrEmpty(text))
|
if (string.IsNullOrEmpty(text))
|
||||||
|
|
@ -272,17 +279,27 @@ namespace Microsoft.AspNetCore.Components
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DateTime.TryParse(text, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out var converted))
|
if (format != null && DateTime.TryParseExact(text, format, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out var converted))
|
||||||
{
|
{
|
||||||
value = default;
|
value = converted;
|
||||||
return false;
|
return true;
|
||||||
|
}
|
||||||
|
else if (format == null && DateTime.TryParse(text, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out converted))
|
||||||
|
{
|
||||||
|
value = converted;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = converted;
|
value = default;
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ConvertToNullableDateTimeCore(object obj, CultureInfo culture, out DateTime? value)
|
private static bool ConvertToNullableDateTimeCore(object obj, CultureInfo culture, out DateTime? value)
|
||||||
|
{
|
||||||
|
return ConvertToNullableDateTimeCore(obj, culture, format: null, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ConvertToNullableDateTimeCore(object obj, CultureInfo culture, string format, out DateTime? value)
|
||||||
{
|
{
|
||||||
var text = (string)obj;
|
var text = (string)obj;
|
||||||
if (string.IsNullOrEmpty(text))
|
if (string.IsNullOrEmpty(text))
|
||||||
|
|
@ -291,14 +308,82 @@ namespace Microsoft.AspNetCore.Components
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DateTime.TryParse(text, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out var converted))
|
if (format != null && DateTime.TryParseExact(text, format, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out var converted))
|
||||||
|
{
|
||||||
|
value = converted;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (format == null && DateTime.TryParse(text, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out converted))
|
||||||
|
{
|
||||||
|
value = converted;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BindConverter<DateTimeOffset> ConvertToDateTimeOffset = ConvertToDateTimeOffsetCore;
|
||||||
|
private static BindConverterWithFormat<DateTimeOffset> ConvertToDateTimeOffsetWithFormat = ConvertToDateTimeOffsetCore;
|
||||||
|
private static BindConverter<DateTimeOffset?> ConvertToNullableDateTimeOffset = ConvertToNullableDateTimeOffsetCore;
|
||||||
|
private static BindConverterWithFormat<DateTimeOffset?> ConvertToNullableDateTimeOffsetWithFormat = ConvertToNullableDateTimeOffsetCore;
|
||||||
|
|
||||||
|
private static bool ConvertToDateTimeOffsetCore(object obj, CultureInfo culture, out DateTimeOffset value)
|
||||||
|
{
|
||||||
|
return ConvertToDateTimeOffsetCore(obj, culture, format: null, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ConvertToDateTimeOffsetCore(object obj, CultureInfo culture, string format, out DateTimeOffset value)
|
||||||
|
{
|
||||||
|
var text = (string)obj;
|
||||||
|
if (string.IsNullOrEmpty(text))
|
||||||
{
|
{
|
||||||
value = default;
|
value = default;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = converted;
|
if (format != null && DateTimeOffset.TryParseExact(text, format, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out var converted))
|
||||||
return true;
|
{
|
||||||
|
value = converted;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (format == null && DateTimeOffset.TryParse(text, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out converted))
|
||||||
|
{
|
||||||
|
value = converted;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ConvertToNullableDateTimeOffsetCore(object obj, CultureInfo culture, out DateTimeOffset? value)
|
||||||
|
{
|
||||||
|
return ConvertToNullableDateTimeOffsetCore(obj, culture, format: null, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ConvertToNullableDateTimeOffsetCore(object obj, CultureInfo culture, string format, out DateTimeOffset? value)
|
||||||
|
{
|
||||||
|
var text = (string)obj;
|
||||||
|
if (string.IsNullOrEmpty(text))
|
||||||
|
{
|
||||||
|
value = default;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format != null && DateTimeOffset.TryParseExact(text, format, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out var converted))
|
||||||
|
{
|
||||||
|
value = converted;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (format == null && DateTimeOffset.TryParse(text, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out converted))
|
||||||
|
{
|
||||||
|
value = converted;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = default;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ConvertToEnum<T>(object obj, CultureInfo culture, out T value) where T : struct, Enum
|
private static bool ConvertToEnum<T>(object obj, CultureInfo culture, out T value) where T : struct, Enum
|
||||||
|
|
@ -602,26 +687,7 @@ namespace Microsoft.AspNetCore.Components
|
||||||
DateTime existingValue,
|
DateTime existingValue,
|
||||||
CultureInfo culture = null)
|
CultureInfo culture = null)
|
||||||
{
|
{
|
||||||
return CreateBinderCore<DateTime>(factory, receiver, setter, culture, ConvertToDateTime);
|
return CreateBinderCore<DateTime>(factory, receiver, setter, culture, format: null, ConvertToDateTimeWithFormat);
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// For internal use only.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="factory"></param>
|
|
||||||
/// <param name="receiver"></param>
|
|
||||||
/// <param name="setter"></param>
|
|
||||||
/// <param name="existingValue"></param>
|
|
||||||
/// <param name="culture"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static EventCallback<UIChangeEventArgs> CreateBinder(
|
|
||||||
this EventCallbackFactory factory,
|
|
||||||
object receiver,
|
|
||||||
Action<DateTime?> setter,
|
|
||||||
DateTime? existingValue,
|
|
||||||
CultureInfo culture = null)
|
|
||||||
{
|
|
||||||
return CreateBinderCore<DateTime?>(factory, receiver, setter, culture, ConvertToNullableDateTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -642,45 +708,127 @@ namespace Microsoft.AspNetCore.Components
|
||||||
string format,
|
string format,
|
||||||
CultureInfo culture = null)
|
CultureInfo culture = null)
|
||||||
{
|
{
|
||||||
// Avoiding CreateBinderCore so we can avoid an extra allocating lambda
|
return CreateBinderCore<DateTime>(factory, receiver, setter, culture, format, ConvertToDateTimeWithFormat);
|
||||||
// when a format is used.
|
}
|
||||||
Action<UIChangeEventArgs> callback = (e) =>
|
|
||||||
{
|
|
||||||
DateTime value = default;
|
|
||||||
var converted = false;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
value = ConvertDateTime(e.Value, culture, format);
|
|
||||||
converted = true;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// See comments in CreateBinderCore
|
/// <summary>
|
||||||
if (converted)
|
/// For internal use only.
|
||||||
{
|
/// </summary>
|
||||||
setter(value);
|
/// <param name="factory"></param>
|
||||||
}
|
/// <param name="receiver"></param>
|
||||||
};
|
/// <param name="setter"></param>
|
||||||
return factory.Create<UIChangeEventArgs>(receiver, callback);
|
/// <param name="existingValue"></param>
|
||||||
|
/// <param name="culture"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static EventCallback<UIChangeEventArgs> CreateBinder(
|
||||||
|
this EventCallbackFactory factory,
|
||||||
|
object receiver,
|
||||||
|
Action<DateTime?> setter,
|
||||||
|
DateTime? existingValue,
|
||||||
|
CultureInfo culture = null)
|
||||||
|
{
|
||||||
|
return CreateBinderCore<DateTime?>(factory, receiver, setter, culture, format: null, ConvertToNullableDateTimeWithFormat);
|
||||||
|
}
|
||||||
|
|
||||||
static DateTime ConvertDateTime(object obj, CultureInfo culture, string format)
|
/// <summary>
|
||||||
{
|
/// For internal use only.
|
||||||
var text = (string)obj;
|
/// </summary>
|
||||||
if (string.IsNullOrEmpty(text))
|
/// <param name="factory"></param>
|
||||||
{
|
/// <param name="receiver"></param>
|
||||||
return default;
|
/// <param name="setter"></param>
|
||||||
}
|
/// <param name="existingValue"></param>
|
||||||
else if (format != null && DateTime.TryParseExact(text, format, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.RoundtripKind, out var value))
|
/// <param name="format"></param>
|
||||||
{
|
/// <param name="culture"></param>
|
||||||
return value;
|
/// <returns></returns>
|
||||||
}
|
public static EventCallback<UIChangeEventArgs> CreateBinder(
|
||||||
else
|
this EventCallbackFactory factory,
|
||||||
{
|
object receiver,
|
||||||
return DateTime.Parse(text, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.RoundtripKind);
|
Action<DateTime?> setter,
|
||||||
}
|
DateTime? existingValue,
|
||||||
}
|
string format,
|
||||||
|
CultureInfo culture = null)
|
||||||
|
{
|
||||||
|
return CreateBinderCore<DateTime?>(factory, receiver, setter, culture, format, ConvertToNullableDateTimeWithFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For internal use only.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="factory"></param>
|
||||||
|
/// <param name="receiver"></param>
|
||||||
|
/// <param name="setter"></param>
|
||||||
|
/// <param name="existingValue"></param>
|
||||||
|
/// <param name="culture"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static EventCallback<UIChangeEventArgs> CreateBinder(
|
||||||
|
this EventCallbackFactory factory,
|
||||||
|
object receiver,
|
||||||
|
Action<DateTimeOffset> setter,
|
||||||
|
DateTimeOffset existingValue,
|
||||||
|
CultureInfo culture = null)
|
||||||
|
{
|
||||||
|
return CreateBinderCore<DateTimeOffset>(factory, receiver, setter, culture, format: null, ConvertToDateTimeOffsetWithFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For internal use only.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="factory"></param>
|
||||||
|
/// <param name="receiver"></param>
|
||||||
|
/// <param name="setter"></param>
|
||||||
|
/// <param name="existingValue"></param>
|
||||||
|
/// <param name="format"></param>
|
||||||
|
/// <param name="culture"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static EventCallback<UIChangeEventArgs> CreateBinder(
|
||||||
|
this EventCallbackFactory factory,
|
||||||
|
object receiver,
|
||||||
|
Action<DateTimeOffset> setter,
|
||||||
|
DateTimeOffset existingValue,
|
||||||
|
string format,
|
||||||
|
CultureInfo culture = null)
|
||||||
|
{
|
||||||
|
return CreateBinderCore<DateTimeOffset>(factory, receiver, setter, culture, format, ConvertToDateTimeOffsetWithFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For internal use only.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="factory"></param>
|
||||||
|
/// <param name="receiver"></param>
|
||||||
|
/// <param name="setter"></param>
|
||||||
|
/// <param name="existingValue"></param>
|
||||||
|
/// <param name="culture"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static EventCallback<UIChangeEventArgs> CreateBinder(
|
||||||
|
this EventCallbackFactory factory,
|
||||||
|
object receiver,
|
||||||
|
Action<DateTimeOffset?> setter,
|
||||||
|
DateTimeOffset? existingValue,
|
||||||
|
CultureInfo culture = null)
|
||||||
|
{
|
||||||
|
return CreateBinderCore<DateTimeOffset?>(factory, receiver, setter, culture, format: null, ConvertToNullableDateTimeOffsetWithFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For internal use only.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="factory"></param>
|
||||||
|
/// <param name="receiver"></param>
|
||||||
|
/// <param name="setter"></param>
|
||||||
|
/// <param name="existingValue"></param>
|
||||||
|
/// <param name="format"></param>
|
||||||
|
/// <param name="culture"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static EventCallback<UIChangeEventArgs> CreateBinder(
|
||||||
|
this EventCallbackFactory factory,
|
||||||
|
object receiver,
|
||||||
|
Action<DateTimeOffset?> setter,
|
||||||
|
DateTimeOffset? existingValue,
|
||||||
|
string format,
|
||||||
|
CultureInfo culture = null)
|
||||||
|
{
|
||||||
|
return CreateBinderCore<DateTimeOffset?>(factory, receiver, setter, culture, format, ConvertToNullableDateTimeOffsetWithFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -746,6 +894,50 @@ namespace Microsoft.AspNetCore.Components
|
||||||
return factory.Create<UIChangeEventArgs>(receiver, callback);
|
return factory.Create<UIChangeEventArgs>(receiver, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static EventCallback<UIChangeEventArgs> CreateBinderCore<T>(
|
||||||
|
this EventCallbackFactory factory,
|
||||||
|
object receiver,
|
||||||
|
Action<T> setter,
|
||||||
|
CultureInfo culture,
|
||||||
|
string format,
|
||||||
|
BindConverterWithFormat<T> converter)
|
||||||
|
{
|
||||||
|
Action<UIChangeEventArgs> callback = e =>
|
||||||
|
{
|
||||||
|
T value = default;
|
||||||
|
var converted = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
converted = converter(e.Value, culture, format, out value);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only invoke the setter if the conversion didn't throw, or if the newly-entered value is empty.
|
||||||
|
// If the user entered some non-empty value we couldn't parse, we leave the state of the .NET field
|
||||||
|
// unchanged, which for a two-way binding results in the UI reverting to its previous valid state
|
||||||
|
// because the diff will see the current .NET output no longer matches the render tree since we
|
||||||
|
// patched it to reflect the state of the UI.
|
||||||
|
//
|
||||||
|
// This reversion behavior is valuable because alternatives are problematic:
|
||||||
|
// - If we assigned default(T) on failure, the user would lose whatever data they were editing,
|
||||||
|
// for example if they accidentally pressed an alphabetical key while editing a number with
|
||||||
|
// @bind:event="oninput"
|
||||||
|
// - If the diff mechanism didn't revert to the previous good value, the user wouldn't necessarily
|
||||||
|
// know that the data they are submitting is different from what they think they've typed
|
||||||
|
if (converted)
|
||||||
|
{
|
||||||
|
setter(value);
|
||||||
|
}
|
||||||
|
else if (string.Empty.Equals(e.Value))
|
||||||
|
{
|
||||||
|
setter(default);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return factory.Create<UIChangeEventArgs>(receiver, callback);
|
||||||
|
}
|
||||||
|
|
||||||
// We can't rely on generics + static to cache here unfortunately. That would require us to overload
|
// We can't rely on generics + static to cache here unfortunately. That would require us to overload
|
||||||
// CreateBinder on T : struct AND T : class, which is not allowed.
|
// CreateBinder on T : struct AND T : class, which is not allowed.
|
||||||
private static class BinderConverterCache
|
private static class BinderConverterCache
|
||||||
|
|
@ -821,6 +1013,14 @@ namespace Microsoft.AspNetCore.Components
|
||||||
{
|
{
|
||||||
converter = ConvertToNullableDateTime;
|
converter = ConvertToNullableDateTime;
|
||||||
}
|
}
|
||||||
|
else if (typeof(T) == typeof(DateTimeOffset))
|
||||||
|
{
|
||||||
|
converter = ConvertToDateTimeOffset;
|
||||||
|
}
|
||||||
|
else if (typeof(T) == typeof(DateTimeOffset?))
|
||||||
|
{
|
||||||
|
converter = ConvertToNullableDateTimeOffset;
|
||||||
|
}
|
||||||
else if (typeof(T).IsEnum)
|
else if (typeof(T).IsEnum)
|
||||||
{
|
{
|
||||||
// We have to deal invoke this dynamically to work around the type constraint on Enum.TryParse.
|
// We have to deal invoke this dynamically to work around the type constraint on Enum.TryParse.
|
||||||
|
|
|
||||||
|
|
@ -421,7 +421,6 @@ namespace Microsoft.AspNetCore.Components
|
||||||
Assert.Equal(1, component.Count);
|
Assert.Equal(1, component.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For now format is only supported by this specific method.
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CreateBinder_DateTime_Format()
|
public async Task CreateBinder_DateTime_Format()
|
||||||
{
|
{
|
||||||
|
|
@ -442,6 +441,104 @@ namespace Microsoft.AspNetCore.Components
|
||||||
Assert.Equal(1, component.Count);
|
Assert.Equal(1, component.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CreateBinder_NullableDateTime_Format()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var value = (DateTime?)DateTime.Now;
|
||||||
|
var component = new EventCountingComponent();
|
||||||
|
Action<DateTime?> setter = (_) => value = _;
|
||||||
|
var format = "ddd yyyy-MM-dd";
|
||||||
|
|
||||||
|
var binder = EventCallback.Factory.CreateBinder(component, setter, value, format);
|
||||||
|
|
||||||
|
var expectedValue = new DateTime(2018, 3, 4);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await binder.InvokeAsync(new UIChangeEventArgs() { Value = expectedValue.ToString(format), });
|
||||||
|
|
||||||
|
Assert.Equal(expectedValue, value);
|
||||||
|
Assert.Equal(1, component.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CreateBinder_DateTimeOffset()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var value = DateTimeOffset.Now;
|
||||||
|
var component = new EventCountingComponent();
|
||||||
|
Action<DateTimeOffset> setter = (_) => value = _;
|
||||||
|
|
||||||
|
var binder = EventCallback.Factory.CreateBinder(component, setter, value);
|
||||||
|
|
||||||
|
var expectedValue = new DateTime(2018, 3, 4, 1, 2, 3);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await binder.InvokeAsync(new UIChangeEventArgs() { Value = expectedValue.ToString(), });
|
||||||
|
|
||||||
|
Assert.Equal(expectedValue, value);
|
||||||
|
Assert.Equal(1, component.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CreateBinder_NullableDateTimeOffset()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var value = (DateTimeOffset?)DateTimeOffset.Now;
|
||||||
|
var component = new EventCountingComponent();
|
||||||
|
Action<DateTimeOffset?> setter = (_) => value = _;
|
||||||
|
|
||||||
|
var binder = EventCallback.Factory.CreateBinder(component, setter, value);
|
||||||
|
|
||||||
|
var expectedValue = new DateTime(2018, 3, 4, 1, 2, 3);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await binder.InvokeAsync(new UIChangeEventArgs() { Value = expectedValue.ToString(), });
|
||||||
|
|
||||||
|
Assert.Equal(expectedValue, value);
|
||||||
|
Assert.Equal(1, component.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CreateBinder_DateTimeOffset_Format()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var value = DateTimeOffset.Now;
|
||||||
|
var component = new EventCountingComponent();
|
||||||
|
Action<DateTimeOffset> setter = (_) => value = _;
|
||||||
|
var format = "ddd yyyy-MM-dd";
|
||||||
|
|
||||||
|
var binder = EventCallback.Factory.CreateBinder(component, setter, value, format);
|
||||||
|
|
||||||
|
var expectedValue = new DateTime(2018, 3, 4);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await binder.InvokeAsync(new UIChangeEventArgs() { Value = expectedValue.ToString(format), });
|
||||||
|
|
||||||
|
Assert.Equal(expectedValue, value);
|
||||||
|
Assert.Equal(1, component.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CreateBinder_NullableDateTimeOffset_Format()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var value = (DateTimeOffset?)DateTimeOffset.Now;
|
||||||
|
var component = new EventCountingComponent();
|
||||||
|
Action<DateTimeOffset?> setter = (_) => value = _;
|
||||||
|
var format = "ddd yyyy-MM-dd";
|
||||||
|
|
||||||
|
var binder = EventCallback.Factory.CreateBinder(component, setter, value, format);
|
||||||
|
|
||||||
|
var expectedValue = new DateTime(2018, 3, 4);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await binder.InvokeAsync(new UIChangeEventArgs() { Value = expectedValue.ToString(format), });
|
||||||
|
|
||||||
|
Assert.Equal(expectedValue, value);
|
||||||
|
Assert.Equal(1, component.Count);
|
||||||
|
}
|
||||||
|
|
||||||
// This uses a type converter
|
// This uses a type converter
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CreateBinder_Guid()
|
public async Task CreateBinder_Guid()
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,88 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
|
||||||
Browser.Equal(new DateTimeOffset(new DateTime(2000, 1, 2)).ToString(cultureInfo), () => display.Text);
|
Browser.Equal(new DateTimeOffset(new DateTime(2000, 1, 2)).ToString(cultureInfo), () => display.Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The logic is different for verifying culture-invariant fields. The problem is that the logic for what
|
||||||
|
// kinds of text a field accepts is determined by the browser and language - it's not general. So while
|
||||||
|
// type="number" and type="date" produce fixed-format and culture-invariant input/output via the "value"
|
||||||
|
// attribute - the actual input processing is harder to nail down. In practice this is only a problem
|
||||||
|
// with dates.
|
||||||
|
//
|
||||||
|
// For this reason we avoid sending keys directly to the field, and let two-way binding do its thing instead.
|
||||||
|
//
|
||||||
|
// A brief summary:
|
||||||
|
// 1. Input a value (invariant culture if using number field, or current culture to extra input if using date field)
|
||||||
|
// 2. trigger onchange
|
||||||
|
// 3. Verify "value" field (current culture)
|
||||||
|
// 4. Verify the input field's value attribute (invariant culture)
|
||||||
|
//
|
||||||
|
// We need to do step 4 to make sure that the value we're entering can "stick" in the form field.
|
||||||
|
// We can't use ".Text" because DOM reasons :(
|
||||||
|
[Theory]
|
||||||
|
[InlineData("en-US")]
|
||||||
|
[InlineData("fr-FR")]
|
||||||
|
public void CanSetCultureAndParseCultureInvariantNumbersAndDatesWithInputFields(string culture)
|
||||||
|
{
|
||||||
|
var cultureInfo = CultureInfo.GetCultureInfo(culture);
|
||||||
|
|
||||||
|
var selector = new SelectElement(Browser.FindElement(By.Id("culture-selector")));
|
||||||
|
selector.SelectByValue(culture);
|
||||||
|
|
||||||
|
// That should have triggered a redirect, wait for the main test selector to come up.
|
||||||
|
MountTestComponent<GlobalizationBindCases>();
|
||||||
|
WaitUntilExists(By.Id("globalization-cases"));
|
||||||
|
|
||||||
|
var cultureDisplay = WaitUntilExists(By.Id("culture-name-display"));
|
||||||
|
Assert.Equal($"Culture is: {culture}", cultureDisplay.Text);
|
||||||
|
|
||||||
|
// int
|
||||||
|
var input = Browser.FindElement(By.Id("input_type_number_int"));
|
||||||
|
var display = Browser.FindElement(By.Id("input_type_number_int_value"));
|
||||||
|
Browser.Equal(42.ToString(cultureInfo), () => display.Text);
|
||||||
|
Browser.Equal(42.ToString(CultureInfo.InvariantCulture), () => input.GetAttribute("value"));
|
||||||
|
|
||||||
|
input.Clear();
|
||||||
|
input.SendKeys(9000.ToString(CultureInfo.InvariantCulture));
|
||||||
|
input.SendKeys("\t");
|
||||||
|
Browser.Equal(9000.ToString(cultureInfo), () => display.Text);
|
||||||
|
Browser.Equal(9000.ToString(CultureInfo.InvariantCulture), () => input.GetAttribute("value"));
|
||||||
|
|
||||||
|
// decimal
|
||||||
|
input = Browser.FindElement(By.Id("input_type_number_decimal"));
|
||||||
|
display = Browser.FindElement(By.Id("input_type_number_decimal_value"));
|
||||||
|
Browser.Equal(4.2m.ToString(cultureInfo), () => display.Text);
|
||||||
|
Browser.Equal(4.2m.ToString(CultureInfo.InvariantCulture), () => input.GetAttribute("value"));
|
||||||
|
|
||||||
|
input.Clear();
|
||||||
|
input.SendKeys(9000.42m.ToString(CultureInfo.InvariantCulture));
|
||||||
|
input.SendKeys("\t");
|
||||||
|
Browser.Equal(9000.42m.ToString(cultureInfo), () => display.Text);
|
||||||
|
Browser.Equal(9000.42m.ToString(CultureInfo.InvariantCulture), () => input.GetAttribute("value"));
|
||||||
|
|
||||||
|
// datetime
|
||||||
|
input = Browser.FindElement(By.Id("input_type_date_datetime"));
|
||||||
|
display = Browser.FindElement(By.Id("input_type_date_datetime_value"));
|
||||||
|
var extraInput = Browser.FindElement(By.Id("input_type_date_datetime_extrainput"));
|
||||||
|
Browser.Equal(new DateTime(1985, 3, 4).ToString(cultureInfo), () => display.Text);
|
||||||
|
Browser.Equal(new DateTime(1985, 3, 4).ToString("yyyy-MM-dd", CultureInfo.InvariantCulture), () => input.GetAttribute("value"));
|
||||||
|
|
||||||
|
ReplaceText(extraInput, new DateTime(2000, 1, 2).ToString(cultureInfo));
|
||||||
|
extraInput.SendKeys("\t");
|
||||||
|
Browser.Equal(new DateTime(2000, 1, 2).ToString(cultureInfo), () => display.Text);
|
||||||
|
Browser.Equal(new DateTime(2000, 1, 2).ToString("yyyy-MM-dd", CultureInfo.InvariantCulture), () => input.GetAttribute("value"));
|
||||||
|
|
||||||
|
// datetimeoffset
|
||||||
|
input = Browser.FindElement(By.Id("input_type_date_datetimeoffset"));
|
||||||
|
display = Browser.FindElement(By.Id("input_type_date_datetimeoffset_value"));
|
||||||
|
extraInput = Browser.FindElement(By.Id("input_type_date_datetimeoffset_extrainput"));
|
||||||
|
Browser.Equal(new DateTimeOffset(new DateTime(1985, 3, 4)).ToString(cultureInfo), () => display.Text);
|
||||||
|
Browser.Equal(new DateTimeOffset(new DateTime(1985, 3, 4)).ToString("yyyy-MM-dd", CultureInfo.InvariantCulture), () => input.GetAttribute("value"));
|
||||||
|
|
||||||
|
ReplaceText(extraInput, new DateTimeOffset(new DateTime(2000, 1, 2)).ToString(cultureInfo));
|
||||||
|
extraInput.SendKeys("\t");
|
||||||
|
Browser.Equal(new DateTimeOffset(new DateTime(2000, 1, 2)).ToString(cultureInfo), () => display.Text);
|
||||||
|
Browser.Equal(new DateTimeOffset(new DateTime(2000, 1, 2)).ToString("yyyy-MM-dd", CultureInfo.InvariantCulture), () => input.GetAttribute("value"));
|
||||||
|
}
|
||||||
|
|
||||||
// see: https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/214
|
// see: https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/214
|
||||||
//
|
//
|
||||||
// Calling Clear() can trigger onchange, which will revert the value to its default.
|
// Calling Clear() can trigger onchange, which will revert the value to its default.
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
using BasicTestApp;
|
using BasicTestApp;
|
||||||
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
|
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
|
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
|
||||||
|
|
@ -640,5 +641,241 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
Browser.Equal(newValue, () => boundValue.Text);
|
Browser.Equal(newValue, () => boundValue.Text);
|
||||||
Assert.Equal(newValue, mirrorValue.GetAttribute("value"));
|
Assert.Equal(newValue, mirrorValue.GetAttribute("value"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
|
||||||
|
// Blazor have different formatting behaviour by default.
|
||||||
|
[Fact]
|
||||||
|
public void CanBindTextboxDateTime()
|
||||||
|
{
|
||||||
|
var target = Browser.FindElement(By.Id("textbox-datetime"));
|
||||||
|
var boundValue = Browser.FindElement(By.Id("textbox-datetime-value"));
|
||||||
|
var mirrorValue = Browser.FindElement(By.Id("textbox-datetime-mirror"));
|
||||||
|
var expected = new DateTime(1985, 3, 4);
|
||||||
|
Assert.Equal(expected, DateTime.Parse(target.GetAttribute("value")));
|
||||||
|
Assert.Equal(expected, DateTime.Parse(boundValue.Text));
|
||||||
|
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
|
||||||
|
|
||||||
|
// Clear textbox; value updates to 01/01/0001 because that's the default
|
||||||
|
target.Clear();
|
||||||
|
expected = default;
|
||||||
|
Browser.Equal(expected, () => DateTime.Parse(target.GetAttribute("value")));
|
||||||
|
Assert.Equal(expected, DateTime.Parse(boundValue.Text));
|
||||||
|
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
target.SendKeys(Keys.Control + "a"); // select all
|
||||||
|
target.SendKeys("01/02/2000 00:00:00\t");
|
||||||
|
expected = new DateTime(2000, 1, 2);
|
||||||
|
Browser.Equal(expected, () => DateTime.Parse(boundValue.Text));
|
||||||
|
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
|
||||||
|
// Blazor have different formatting behaviour by default.
|
||||||
|
[Fact]
|
||||||
|
public void CanBindTextboxNullableDateTime()
|
||||||
|
{
|
||||||
|
var target = Browser.FindElement(By.Id("textbox-nullable-datetime"));
|
||||||
|
var boundValue = Browser.FindElement(By.Id("textbox-nullable-datetime-value"));
|
||||||
|
var mirrorValue = Browser.FindElement(By.Id("textbox-nullable-datetime-mirror"));
|
||||||
|
Assert.Equal(string.Empty, target.GetAttribute("value"));
|
||||||
|
Assert.Equal(string.Empty, boundValue.Text);
|
||||||
|
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
target.Clear();
|
||||||
|
Browser.Equal("", () => boundValue.Text);
|
||||||
|
Assert.Equal("", mirrorValue.GetAttribute("value"));
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
var expected = new DateTime(2000, 1, 2);
|
||||||
|
target.SendKeys("01/02/2000 00:00:00\t");
|
||||||
|
Browser.Equal(expected, () => DateTime.Parse(boundValue.Text));
|
||||||
|
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
target.Clear();
|
||||||
|
target.SendKeys("\t");
|
||||||
|
Browser.Equal(string.Empty, () => boundValue.Text);
|
||||||
|
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
|
||||||
|
// Blazor have different formatting behaviour by default.
|
||||||
|
[Fact]
|
||||||
|
public void CanBindTextboxDateTimeOffset()
|
||||||
|
{
|
||||||
|
var target = Browser.FindElement(By.Id("textbox-datetimeoffset"));
|
||||||
|
var boundValue = Browser.FindElement(By.Id("textbox-datetimeoffset-value"));
|
||||||
|
var mirrorValue = Browser.FindElement(By.Id("textbox-datetimeoffset-mirror"));
|
||||||
|
var expected = new DateTimeOffset(new DateTime(1985, 3, 4), TimeSpan.FromHours(8));
|
||||||
|
Assert.Equal(expected, DateTimeOffset.Parse(target.GetAttribute("value")));
|
||||||
|
Assert.Equal(expected, DateTimeOffset.Parse(boundValue.Text));
|
||||||
|
Assert.Equal(expected, DateTimeOffset.Parse(mirrorValue.GetAttribute("value")));
|
||||||
|
|
||||||
|
// Clear textbox; value updates to 01/01/0001 because that's the default
|
||||||
|
target.Clear();
|
||||||
|
expected = default;
|
||||||
|
Browser.Equal(expected, () => DateTimeOffset.Parse(target.GetAttribute("value")));
|
||||||
|
Assert.Equal(expected, DateTimeOffset.Parse(boundValue.Text));
|
||||||
|
Assert.Equal(expected, DateTimeOffset.Parse(mirrorValue.GetAttribute("value")));
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
target.SendKeys(Keys.Control + "a"); // select all
|
||||||
|
target.SendKeys("01/02/2000 00:00:00 +08:00\t");
|
||||||
|
expected = new DateTimeOffset(new DateTime(2000, 1, 2), TimeSpan.FromHours(8));
|
||||||
|
Browser.Equal(expected, () => DateTimeOffset.Parse(boundValue.Text));
|
||||||
|
Assert.Equal(expected, DateTimeOffset.Parse(mirrorValue.GetAttribute("value")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
|
||||||
|
// Blazor have different formatting behaviour by default.
|
||||||
|
[Fact]
|
||||||
|
public void CanBindTextboxNullableDateTimeOffset()
|
||||||
|
{
|
||||||
|
var target = Browser.FindElement(By.Id("textbox-nullable-datetimeoffset"));
|
||||||
|
var boundValue = Browser.FindElement(By.Id("textbox-nullable-datetimeoffset-value"));
|
||||||
|
var mirrorValue = Browser.FindElement(By.Id("textbox-nullable-datetimeoffset-mirror"));
|
||||||
|
Assert.Equal(string.Empty, target.GetAttribute("value"));
|
||||||
|
Assert.Equal(string.Empty, boundValue.Text);
|
||||||
|
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
target.Clear();
|
||||||
|
Browser.Equal("", () => boundValue.Text);
|
||||||
|
Assert.Equal("", mirrorValue.GetAttribute("value"));
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
target.SendKeys("01/02/2000 00:00:00 +08:00" + "\t");
|
||||||
|
var expected = new DateTimeOffset(new DateTime(2000, 1, 2), TimeSpan.FromHours(8));
|
||||||
|
Browser.Equal(expected, () => DateTimeOffset.Parse(boundValue.Text));
|
||||||
|
Assert.Equal(expected, DateTimeOffset.Parse(mirrorValue.GetAttribute("value")));
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
target.Clear();
|
||||||
|
target.SendKeys("\t");
|
||||||
|
Browser.Equal(string.Empty, () => boundValue.Text);
|
||||||
|
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
|
||||||
|
// Blazor have different formatting behaviour by default.
|
||||||
|
[Fact]
|
||||||
|
public void CanBindTextboxDateTimeWithFormat()
|
||||||
|
{
|
||||||
|
var target = Browser.FindElement(By.Id("textbox-datetime-format"));
|
||||||
|
var boundValue = Browser.FindElement(By.Id("textbox-datetime-format-value"));
|
||||||
|
var mirrorValue = Browser.FindElement(By.Id("textbox-datetime-format-mirror"));
|
||||||
|
var expected = new DateTime(1985, 3, 4);
|
||||||
|
Assert.Equal("03-04", target.GetAttribute("value"));
|
||||||
|
Assert.Equal(expected, DateTime.Parse(boundValue.Text));
|
||||||
|
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
|
||||||
|
|
||||||
|
// Clear textbox; value updates to emtpy because that's what we do for `default` when there's a format
|
||||||
|
target.Clear();
|
||||||
|
target.SendKeys("\t");
|
||||||
|
expected = default;
|
||||||
|
Browser.Equal(string.Empty, () => target.GetAttribute("value"));
|
||||||
|
Assert.Equal(expected, DateTime.Parse(boundValue.Text));
|
||||||
|
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
target.SendKeys(Keys.Control + "a"); // select all
|
||||||
|
target.SendKeys("01-02\t");
|
||||||
|
expected = new DateTime(DateTime.Now.Year, 1, 2);
|
||||||
|
Browser.Equal(expected, () => DateTime.Parse(boundValue.Text));
|
||||||
|
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
|
||||||
|
// Blazor have different formatting behaviour by default.
|
||||||
|
[Fact]
|
||||||
|
public void CanBindTextboxNullableDateTimeWithFormat()
|
||||||
|
{
|
||||||
|
var target = Browser.FindElement(By.Id("textbox-nullable-datetime-format"));
|
||||||
|
var boundValue = Browser.FindElement(By.Id("textbox-nullable-datetime-format-value"));
|
||||||
|
var mirrorValue = Browser.FindElement(By.Id("textbox-nullable-datetime-format-mirror"));
|
||||||
|
Assert.Equal(string.Empty, target.GetAttribute("value"));
|
||||||
|
Assert.Equal(string.Empty, boundValue.Text);
|
||||||
|
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
target.Clear();
|
||||||
|
Browser.Equal("", () => boundValue.Text);
|
||||||
|
Assert.Equal("", mirrorValue.GetAttribute("value"));
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
target.SendKeys("01-02\t");
|
||||||
|
var expected = new DateTime(DateTime.Now.Year, 1, 2);
|
||||||
|
Browser.Equal(expected, () => DateTime.Parse(boundValue.Text));
|
||||||
|
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
target.Clear();
|
||||||
|
target.SendKeys("\t");
|
||||||
|
Browser.Equal(string.Empty, () => boundValue.Text);
|
||||||
|
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
|
||||||
|
// Blazor have different formatting behaviour by default.
|
||||||
|
[Fact]
|
||||||
|
public void CanBindTextboxDateTimeOffsetWithFormat()
|
||||||
|
{
|
||||||
|
var target = Browser.FindElement(By.Id("textbox-datetimeoffset-format"));
|
||||||
|
var boundValue = Browser.FindElement(By.Id("textbox-datetimeoffset-format-value"));
|
||||||
|
var mirrorValue = Browser.FindElement(By.Id("textbox-datetimeoffset-format-mirror"));
|
||||||
|
var expected = new DateTimeOffset(new DateTime(1985, 3, 4), TimeSpan.FromHours(8));
|
||||||
|
Assert.Equal("03-04", target.GetAttribute("value"));
|
||||||
|
Assert.Equal(expected, DateTimeOffset.Parse(boundValue.Text));
|
||||||
|
Assert.Equal(expected, DateTimeOffset.Parse(mirrorValue.GetAttribute("value")));
|
||||||
|
|
||||||
|
// Clear textbox; value updates to emtpy because that's what we do for `default` when there's a format
|
||||||
|
target.Clear();
|
||||||
|
expected = default;
|
||||||
|
Browser.Equal(string.Empty, () => target.GetAttribute("value"));
|
||||||
|
Assert.Equal(expected, DateTimeOffset.Parse(boundValue.Text));
|
||||||
|
Assert.Equal(expected, DateTimeOffset.Parse(mirrorValue.GetAttribute("value")));
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
target.SendKeys(Keys.Control + "a"); // select all
|
||||||
|
target.SendKeys("01-02\t");
|
||||||
|
expected = new DateTimeOffset(new DateTime(DateTime.Now.Year, 1, 2), TimeSpan.FromHours(0));
|
||||||
|
Browser.Equal(expected.DateTime, () => DateTimeOffset.Parse(boundValue.Text).DateTime);
|
||||||
|
Assert.Equal(expected.DateTime, DateTimeOffset.Parse(mirrorValue.GetAttribute("value")).DateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
|
||||||
|
// Blazor have different formatting behaviour by default.
|
||||||
|
//
|
||||||
|
// Guess what! Client-side and server-side also understand timezones differently. So for now we're comparing
|
||||||
|
// the parsed output without consideration for the timezone
|
||||||
|
[Fact]
|
||||||
|
public void CanBindTextboxNullableDateTimeOffsetWithFormat()
|
||||||
|
{
|
||||||
|
var target = Browser.FindElement(By.Id("textbox-nullable-datetimeoffset"));
|
||||||
|
var boundValue = Browser.FindElement(By.Id("textbox-nullable-datetimeoffset-value"));
|
||||||
|
var mirrorValue = Browser.FindElement(By.Id("textbox-nullable-datetimeoffset-mirror"));
|
||||||
|
Assert.Equal(string.Empty, target.GetAttribute("value"));
|
||||||
|
Assert.Equal(string.Empty, boundValue.Text);
|
||||||
|
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
target.Clear();
|
||||||
|
Browser.Equal("", () => boundValue.Text);
|
||||||
|
Assert.Equal("", mirrorValue.GetAttribute("value"));
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
target.SendKeys("01-02" + "\t");
|
||||||
|
var expected = new DateTimeOffset(new DateTime(DateTime.Now.Year, 1, 2), TimeSpan.FromHours(0));
|
||||||
|
Browser.Equal(expected.DateTime, () => DateTimeOffset.Parse(boundValue.Text).DateTime);
|
||||||
|
Assert.Equal(expected.DateTime, DateTimeOffset.Parse(mirrorValue.GetAttribute("value")).DateTime);
|
||||||
|
|
||||||
|
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||||
|
target.Clear();
|
||||||
|
target.SendKeys("\t");
|
||||||
|
Browser.Equal(string.Empty, () => boundValue.Text);
|
||||||
|
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,56 @@
|
||||||
<input id="textbox-generic-guid-mirror" @bind="textboxGenericGuidValue" readonly />
|
<input id="textbox-generic-guid-mirror" @bind="textboxGenericGuidValue" readonly />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h2>Date Textboxes (type=text)</h2>
|
||||||
|
<p>
|
||||||
|
DateTime:
|
||||||
|
<input id="textbox-datetime" @bind="textboxDateTimeValue" type="text" />
|
||||||
|
<span id="textbox-datetime-value">@textboxDateTimeValue</span>
|
||||||
|
<input id="textbox-datetime-mirror" @bind="textboxDateTimeValue" readonly />
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Nullable DateTime:
|
||||||
|
<input id="textbox-nullable-datetime" @bind="textboxNullableDateTimeValue" type="text" />
|
||||||
|
<span id="textbox-nullable-datetime-value">@textboxNullableDateTimeValue</span>
|
||||||
|
<input id="textbox-nullable-datetime-mirror" @bind="textboxNullableDateTimeValue" readonly />
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
DateTimeOffset:
|
||||||
|
<input id="textbox-datetimeoffset" @bind="textboxDateTimeOffsetValue" type="text" />
|
||||||
|
<span id="textbox-datetimeoffset-value">@textboxDateTimeOffsetValue</span>
|
||||||
|
<input id="textbox-datetimeoffset-mirror" @bind="textboxDateTimeOffsetValue" readonly />
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Nullable DateTimeOffset:
|
||||||
|
<input id="textbox-nullable-datetimeoffset" @bind="textboxNullableDateTimeOffsetValue" type="text" />
|
||||||
|
<span id="textbox-nullable-datetimeoffset-value">@textboxNullableDateTimeOffsetValue</span>
|
||||||
|
<input id="textbox-nullable-datetimeoffset-mirror" @bind="textboxNullableDateTimeOffsetValue" readonly />
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
DateTime (format):
|
||||||
|
<input id="textbox-datetime-format" @bind="textboxDateTimeFormatValue" type="text" @bind:format="MM-dd" />
|
||||||
|
<span id="textbox-datetime-format-value">@textboxDateTimeFormatValue</span>
|
||||||
|
<input id="textbox-datetime-format-mirror" @bind="textboxDateTimeFormatValue" readonly />
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Nullable DateTime (format):
|
||||||
|
<input id="textbox-nullable-datetime-format" @bind="textboxNullableDateTimeFormatValue" type="text" @bind:format="MM-dd" />
|
||||||
|
<span id="textbox-nullable-datetime-format-value">@textboxNullableDateTimeFormatValue</span>
|
||||||
|
<input id="textbox-nullable-datetime-format-mirror" @bind="textboxNullableDateTimeFormatValue" readonly />
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
DateTimeOffset (format):
|
||||||
|
<input id="textbox-datetimeoffset-format" @bind="textboxDateTimeOffsetFormatValue" type="text" @bind:format="MM-dd" />
|
||||||
|
<span id="textbox-datetimeoffset-format-value">@textboxDateTimeOffsetFormatValue</span>
|
||||||
|
<input id="textbox-datetimeoffset-format-mirror" @bind="textboxDateTimeOffsetFormatValue" readonly />
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Nullable DateTimeOffset (format):
|
||||||
|
<input id="textbox-nullable-datetimeoffset-format" @bind="textboxNullableDateTimeOffsetFormatValue" type="text" @bind:format="MM-dd" />
|
||||||
|
<span id="textbox-nullable-datetimeoffset-format-value">@textboxNullableDateTimeOffsetFormatValue</span>
|
||||||
|
<input id="textbox-nullable-datetimeoffset-format-mirror" @bind="textboxNullableDateTimeOffsetFormatValue" readonly />
|
||||||
|
</p>
|
||||||
|
|
||||||
<h2>Text Area</h2>
|
<h2>Text Area</h2>
|
||||||
<p>
|
<p>
|
||||||
Initially blank:
|
Initially blank:
|
||||||
|
|
@ -145,7 +195,8 @@
|
||||||
<h2>Select</h2>
|
<h2>Select</h2>
|
||||||
<p>
|
<p>
|
||||||
<select id="select-box" @bind="selectValue">
|
<select id="select-box" @bind="selectValue">
|
||||||
<optgroup label="Some choices"> <!-- Show it also works with optgroup -->
|
<optgroup label="Some choices">
|
||||||
|
<!-- Show it also works with optgroup -->
|
||||||
<option value=@SelectableValue.First>First choice</option>
|
<option value=@SelectableValue.First>First choice</option>
|
||||||
<option value=@SelectableValue.Second>Second choice</option>
|
<option value=@SelectableValue.Second>Second choice</option>
|
||||||
<option value=@SelectableValue.Third>Third choice</option>
|
<option value=@SelectableValue.Third>Third choice</option>
|
||||||
|
|
@ -172,40 +223,50 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
string textboxInitiallyBlankValue = null;
|
string textboxInitiallyBlankValue = null;
|
||||||
string textboxInitiallyPopulatedValue = "Hello";
|
string textboxInitiallyPopulatedValue = "Hello";
|
||||||
|
|
||||||
string textAreaInitiallyBlankValue = null;
|
string textAreaInitiallyBlankValue = null;
|
||||||
string textAreaInitiallyPopulatedValue = "Hello";
|
string textAreaInitiallyPopulatedValue = "Hello";
|
||||||
|
|
||||||
bool? checkboxInitiallyNullValue = null;
|
bool? checkboxInitiallyNullValue = null;
|
||||||
bool checkboxInitiallyUncheckedValue = false;
|
bool checkboxInitiallyUncheckedValue = false;
|
||||||
bool checkboxInitiallyCheckedValue = true;
|
bool checkboxInitiallyCheckedValue = true;
|
||||||
|
|
||||||
int textboxIntValue = -42;
|
int textboxIntValue = -42;
|
||||||
int? textboxNullableIntValue = null;
|
int? textboxNullableIntValue = null;
|
||||||
long textboxLongValue = 3_000_000_000;
|
long textboxLongValue = 3_000_000_000;
|
||||||
long? textboxNullableLongValue = null;
|
long? textboxNullableLongValue = null;
|
||||||
float textboxFloatValue = 3.141f;
|
float textboxFloatValue = 3.141f;
|
||||||
float? textboxNullableFloatValue = null;
|
float? textboxNullableFloatValue = null;
|
||||||
double textboxDoubleValue = 3.14159265359d;
|
double textboxDoubleValue = 3.14159265359d;
|
||||||
double? textboxNullableDoubleValue = null;
|
double? textboxNullableDoubleValue = null;
|
||||||
decimal textboxDecimalValue = 0.0000000000000000000000000001M;
|
decimal textboxDecimalValue = 0.0000000000000000000000000001M;
|
||||||
decimal? textboxNullableDecimalValue = null;
|
decimal? textboxNullableDecimalValue = null;
|
||||||
decimal textboxDecimalInvalidValue = 0.0000000000000000000000000001M;
|
decimal textboxDecimalInvalidValue = 0.0000000000000000000000000001M;
|
||||||
decimal? textboxNullableDecimalInvalidValue = null;
|
decimal? textboxNullableDecimalInvalidValue = null;
|
||||||
|
|
||||||
int textboxGenericIntValue = -42;
|
int textboxGenericIntValue = -42;
|
||||||
Guid textboxGenericGuidValue = Guid.Empty;
|
Guid textboxGenericGuidValue = Guid.Empty;
|
||||||
|
|
||||||
bool includeFourthOption = false;
|
DateTime textboxDateTimeValue = new DateTime(1985, 3, 4);
|
||||||
enum SelectableValue { First, Second, Third, Fourth }
|
DateTime? textboxNullableDateTimeValue = null;
|
||||||
SelectableValue selectValue = SelectableValue.Second;
|
DateTimeOffset textboxDateTimeOffsetValue = new DateTimeOffset(new DateTime(1985, 3, 4), TimeSpan.FromHours(8));
|
||||||
SelectableValue selectMarkupValue = SelectableValue.Second;
|
DateTimeOffset? textboxNullableDateTimeOffsetValue = null;
|
||||||
|
|
||||||
void AddAndSelectNewSelectOption()
|
DateTime textboxDateTimeFormatValue = new DateTime(1985, 3, 4);
|
||||||
{
|
DateTime? textboxNullableDateTimeFormatValue = null;
|
||||||
includeFourthOption = true;
|
DateTimeOffset textboxDateTimeOffsetFormatValue = new DateTimeOffset(new DateTime(1985, 3, 4), TimeSpan.FromHours(8));
|
||||||
selectValue = SelectableValue.Fourth;
|
DateTimeOffset? textboxNullableDateTimeOffsetFormatValue = null;
|
||||||
}
|
|
||||||
|
bool includeFourthOption = false;
|
||||||
|
enum SelectableValue { First, Second, Third, Fourth }
|
||||||
|
SelectableValue selectValue = SelectableValue.Second;
|
||||||
|
SelectableValue selectMarkupValue = SelectableValue.Second;
|
||||||
|
|
||||||
|
void AddAndSelectNewSelectOption()
|
||||||
|
{
|
||||||
|
includeFourthOption = true;
|
||||||
|
selectValue = SelectableValue.Fourth;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
@using System.Globalization
|
||||||
|
@using Microsoft.AspNetCore.Components.Forms
|
||||||
<h3 id="globalization-cases">Globalization Bind Cases</h3>
|
<h3 id="globalization-cases">Globalization Bind Cases</h3>
|
||||||
<h3 id="culture-name-display">Culture is: @System.Globalization.CultureInfo.CurrentCulture.Name</h3>
|
<h3 id="culture-name-display">Culture is: @System.Globalization.CultureInfo.CurrentCulture.Name</h3>
|
||||||
|
|
||||||
|
|
@ -25,6 +27,31 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p>Numbers using bind in number fields</p>
|
||||||
|
<div>
|
||||||
|
int: <input type="number" id="input_type_number_int" value="@inputTypeNumberInt.ToString(CultureInfo.InvariantCulture)" @onchange="@EventCallback.Factory.CreateBinder(this, (value) => inputTypeNumberInt = value, inputTypeNumberInt, CultureInfo.InvariantCulture)" />
|
||||||
|
<span id="input_type_number_int_value">@inputTypeNumberInt</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
decimal: <input type="number" id="input_type_number_decimal" value="@inputTypeNumberDecimal.ToString(CultureInfo.InvariantCulture)" @onchange="@EventCallback.Factory.CreateBinder(this, (value) => inputTypeNumberDecimal = value, inputTypeNumberDecimal, CultureInfo.InvariantCulture)"/>
|
||||||
|
<span id="input_type_number_decimal_value">@inputTypeNumberDecimal</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p>Dates using bind in date fields</p>
|
||||||
|
<div>
|
||||||
|
DateTime: <input type="text" id="input_type_date_datetime_extrainput" @bind="inputTypeDateDateTime" />
|
||||||
|
<input type="date" id="input_type_date_datetime" value="@inputTypeDateDateTime.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)" @onchange="@EventCallback.Factory.CreateBinder(this, (value) => inputTypeDateDateTime = value, inputTypeDateDateTime, "yyyy-MM-dd", CultureInfo.InvariantCulture)" />
|
||||||
|
<span id="input_type_date_datetime_value">@inputTypeDateDateTime</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
DateTimeOffset: <input type="text" id="input_type_date_datetimeoffset_extrainput" @bind="inputTypeDateDateTimeOffset" />
|
||||||
|
<input type="date" id="input_type_date_datetimeoffset" value="@inputTypeDateDateTimeOffset.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)" @onchange="@EventCallback.Factory.CreateBinder(this, (value) => inputTypeDateDateTimeOffset = value, inputTypeDateDateTimeOffset, "yyyy-MM-dd", CultureInfo.InvariantCulture)"/>
|
||||||
|
<span id="input_type_date_datetimeoffset_value">@inputTypeDateDateTimeOffset</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
int inputTypeTextInt = 42;
|
int inputTypeTextInt = 42;
|
||||||
|
|
@ -32,4 +59,10 @@
|
||||||
|
|
||||||
DateTime inputTypeTextDateTime = new DateTime(1985, 3, 4);
|
DateTime inputTypeTextDateTime = new DateTime(1985, 3, 4);
|
||||||
DateTimeOffset inputTypeTextDateTimeOffset = new DateTimeOffset(new DateTime(1985, 3, 4));
|
DateTimeOffset inputTypeTextDateTimeOffset = new DateTimeOffset(new DateTime(1985, 3, 4));
|
||||||
|
|
||||||
|
int inputTypeNumberInt = 42;
|
||||||
|
decimal inputTypeNumberDecimal = 4.2m;
|
||||||
|
|
||||||
|
DateTime inputTypeDateDateTime = new DateTime(1985, 3, 4);
|
||||||
|
DateTimeOffset inputTypeDateDateTimeOffset = new DateTimeOffset(new DateTime(1985, 3, 4));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue