diff --git a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs b/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs
index 7376cf6b87..fa82390216 100644
--- a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs
+++ b/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs
@@ -46,6 +46,9 @@ namespace Microsoft.AspNetCore.Components
public static partial class BindMethods
{
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 value) { throw null; }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false, Inherited=true)]
@@ -124,6 +127,8 @@ namespace Microsoft.AspNetCore.Components
public static partial class EventCallbackFactoryBinderExtensions
{
public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, bool existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
+ public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTimeOffset existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
+ public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTimeOffset existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTime existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTime existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, decimal existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
@@ -131,7 +136,10 @@ namespace Microsoft.AspNetCore.Components
public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, int existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, long existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, bool? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
+ public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTimeOffset? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
+ public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTimeOffset? existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTime? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
+ public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, System.DateTime? existingValue, string format, System.Globalization.CultureInfo culture = null) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, decimal? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, double? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, int? existingValue, System.Globalization.CultureInfo culture = null) { throw null; }
diff --git a/src/Components/Components/src/BindMethods.cs b/src/Components/Components/src/BindMethods.cs
index 13ca0e3fa0..702b0c74b2 100644
--- a/src/Components/Components/src/BindMethods.cs
+++ b/src/Components/Components/src/BindMethods.cs
@@ -23,6 +23,25 @@ namespace Microsoft.AspNetCore.Components
value == default ? null
: (format == null ? value.ToString() : value.ToString(format));
+ ///
+ /// Not intended to be used directly.
+ ///
+ public static string GetValue(DateTime? value, string format) =>
+ value == default ? null
+ : (format == null ? value.ToString() : value.Value.ToString(format));
+ ///
+ /// Not intended to be used directly.
+ ///
+ public static string GetValue(DateTimeOffset value, string format) =>
+ value == default ? null
+ : (format == null ? value.ToString() : value.ToString(format));
+
+ ///
+ /// Not intended to be used directly.
+ ///
+ public static string GetValue(DateTimeOffset? value, string format) =>
+ value == default ? null
+ : (format == null ? value.ToString() : value.Value.ToString(format));
}
}
diff --git a/src/Components/Components/src/EventCallbackFactoryBinderExtensions.cs b/src/Components/Components/src/EventCallbackFactoryBinderExtensions.cs
index c8c8d9a0ec..0f8a6d547e 100644
--- a/src/Components/Components/src/EventCallbackFactoryBinderExtensions.cs
+++ b/src/Components/Components/src/EventCallbackFactoryBinderExtensions.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Concurrent;
using System.ComponentModel;
-using System.Diagnostics;
using System.Globalization;
using System.Reflection;
@@ -26,6 +25,7 @@ namespace Microsoft.AspNetCore.Components
public static class EventCallbackFactoryBinderExtensions
{
private delegate bool BindConverter(object obj, CultureInfo culture, out T value);
+ private delegate bool BindConverterWithFormat(object obj, CultureInfo culture, string format, out T value);
// Perf: conversion delegates are written as static funcs so we can prevent
// allocations for these simple cases.
@@ -261,9 +261,16 @@ namespace Microsoft.AspNetCore.Components
}
private static BindConverter ConvertToDateTime = ConvertToDateTimeCore;
+ private static BindConverterWithFormat ConvertToDateTimeWithFormat = ConvertToDateTimeCore;
private static BindConverter ConvertToNullableDateTime = ConvertToNullableDateTimeCore;
+ private static BindConverterWithFormat ConvertToNullableDateTimeWithFormat = ConvertToNullableDateTimeCore;
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;
if (string.IsNullOrEmpty(text))
@@ -272,17 +279,27 @@ namespace Microsoft.AspNetCore.Components
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;
- return false;
+ value = converted;
+ return true;
+ }
+ else if (format == null && DateTime.TryParse(text, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.None, out converted))
+ {
+ value = converted;
+ return true;
}
- value = converted;
- return true;
+ value = default;
+ return false;
}
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;
if (string.IsNullOrEmpty(text))
@@ -291,14 +308,82 @@ namespace Microsoft.AspNetCore.Components
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 ConvertToDateTimeOffset = ConvertToDateTimeOffsetCore;
+ private static BindConverterWithFormat ConvertToDateTimeOffsetWithFormat = ConvertToDateTimeOffsetCore;
+ private static BindConverter ConvertToNullableDateTimeOffset = ConvertToNullableDateTimeOffsetCore;
+ private static BindConverterWithFormat 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;
return false;
}
- value = converted;
- 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 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(object obj, CultureInfo culture, out T value) where T : struct, Enum
@@ -602,26 +687,7 @@ namespace Microsoft.AspNetCore.Components
DateTime existingValue,
CultureInfo culture = null)
{
- return CreateBinderCore(factory, receiver, setter, culture, ConvertToDateTime);
- }
-
- ///
- /// For internal use only.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static EventCallback CreateBinder(
- this EventCallbackFactory factory,
- object receiver,
- Action setter,
- DateTime? existingValue,
- CultureInfo culture = null)
- {
- return CreateBinderCore(factory, receiver, setter, culture, ConvertToNullableDateTime);
+ return CreateBinderCore(factory, receiver, setter, culture, format: null, ConvertToDateTimeWithFormat);
}
///
@@ -642,45 +708,127 @@ namespace Microsoft.AspNetCore.Components
string format,
CultureInfo culture = null)
{
- // Avoiding CreateBinderCore so we can avoid an extra allocating lambda
- // when a format is used.
- Action callback = (e) =>
- {
- DateTime value = default;
- var converted = false;
- try
- {
- value = ConvertDateTime(e.Value, culture, format);
- converted = true;
- }
- catch
- {
- }
+ return CreateBinderCore(factory, receiver, setter, culture, format, ConvertToDateTimeWithFormat);
+ }
- // See comments in CreateBinderCore
- if (converted)
- {
- setter(value);
- }
- };
- return factory.Create(receiver, callback);
+ ///
+ /// For internal use only.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static EventCallback CreateBinder(
+ this EventCallbackFactory factory,
+ object receiver,
+ Action setter,
+ DateTime? existingValue,
+ CultureInfo culture = null)
+ {
+ return CreateBinderCore(factory, receiver, setter, culture, format: null, ConvertToNullableDateTimeWithFormat);
+ }
- static DateTime ConvertDateTime(object obj, CultureInfo culture, string format)
- {
- var text = (string)obj;
- if (string.IsNullOrEmpty(text))
- {
- return default;
- }
- else if (format != null && DateTime.TryParseExact(text, format, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.RoundtripKind, out var value))
- {
- return value;
- }
- else
- {
- return DateTime.Parse(text, culture ?? CultureInfo.CurrentCulture, DateTimeStyles.RoundtripKind);
- }
- }
+ ///
+ /// For internal use only.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static EventCallback CreateBinder(
+ this EventCallbackFactory factory,
+ object receiver,
+ Action setter,
+ DateTime? existingValue,
+ string format,
+ CultureInfo culture = null)
+ {
+ return CreateBinderCore(factory, receiver, setter, culture, format, ConvertToNullableDateTimeWithFormat);
+ }
+
+ ///
+ /// For internal use only.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static EventCallback CreateBinder(
+ this EventCallbackFactory factory,
+ object receiver,
+ Action setter,
+ DateTimeOffset existingValue,
+ CultureInfo culture = null)
+ {
+ return CreateBinderCore(factory, receiver, setter, culture, format: null, ConvertToDateTimeOffsetWithFormat);
+ }
+
+ ///
+ /// For internal use only.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static EventCallback CreateBinder(
+ this EventCallbackFactory factory,
+ object receiver,
+ Action setter,
+ DateTimeOffset existingValue,
+ string format,
+ CultureInfo culture = null)
+ {
+ return CreateBinderCore(factory, receiver, setter, culture, format, ConvertToDateTimeOffsetWithFormat);
+ }
+
+ ///
+ /// For internal use only.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static EventCallback CreateBinder(
+ this EventCallbackFactory factory,
+ object receiver,
+ Action setter,
+ DateTimeOffset? existingValue,
+ CultureInfo culture = null)
+ {
+ return CreateBinderCore(factory, receiver, setter, culture, format: null, ConvertToNullableDateTimeOffsetWithFormat);
+ }
+
+ ///
+ /// For internal use only.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static EventCallback CreateBinder(
+ this EventCallbackFactory factory,
+ object receiver,
+ Action setter,
+ DateTimeOffset? existingValue,
+ string format,
+ CultureInfo culture = null)
+ {
+ return CreateBinderCore(factory, receiver, setter, culture, format, ConvertToNullableDateTimeOffsetWithFormat);
}
///
@@ -746,6 +894,50 @@ namespace Microsoft.AspNetCore.Components
return factory.Create(receiver, callback);
}
+ private static EventCallback CreateBinderCore(
+ this EventCallbackFactory factory,
+ object receiver,
+ Action setter,
+ CultureInfo culture,
+ string format,
+ BindConverterWithFormat converter)
+ {
+ Action 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(receiver, callback);
+ }
+
// 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.
private static class BinderConverterCache
@@ -821,6 +1013,14 @@ namespace Microsoft.AspNetCore.Components
{
converter = ConvertToNullableDateTime;
}
+ else if (typeof(T) == typeof(DateTimeOffset))
+ {
+ converter = ConvertToDateTimeOffset;
+ }
+ else if (typeof(T) == typeof(DateTimeOffset?))
+ {
+ converter = ConvertToNullableDateTimeOffset;
+ }
else if (typeof(T).IsEnum)
{
// We have to deal invoke this dynamically to work around the type constraint on Enum.TryParse.
diff --git a/src/Components/Components/test/EventCallbackFactoryBinderExtensionsTest.cs b/src/Components/Components/test/EventCallbackFactoryBinderExtensionsTest.cs
index 6136b5b439..62402f2265 100644
--- a/src/Components/Components/test/EventCallbackFactoryBinderExtensionsTest.cs
+++ b/src/Components/Components/test/EventCallbackFactoryBinderExtensionsTest.cs
@@ -421,7 +421,6 @@ namespace Microsoft.AspNetCore.Components
Assert.Equal(1, component.Count);
}
- // For now format is only supported by this specific method.
[Fact]
public async Task CreateBinder_DateTime_Format()
{
@@ -442,6 +441,104 @@ namespace Microsoft.AspNetCore.Components
Assert.Equal(1, component.Count);
}
+ [Fact]
+ public async Task CreateBinder_NullableDateTime_Format()
+ {
+ // Arrange
+ var value = (DateTime?)DateTime.Now;
+ var component = new EventCountingComponent();
+ Action 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 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 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 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 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
[Fact]
public async Task CreateBinder_Guid()
diff --git a/src/Components/test/E2ETest/ServerExecutionTests/GlobalizationTest.cs b/src/Components/test/E2ETest/ServerExecutionTests/GlobalizationTest.cs
index 3e62e34857..bb3e633204 100644
--- a/src/Components/test/E2ETest/ServerExecutionTests/GlobalizationTest.cs
+++ b/src/Components/test/E2ETest/ServerExecutionTests/GlobalizationTest.cs
@@ -91,6 +91,88 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
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();
+ 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
//
// Calling Clear() can trigger onchange, which will revert the value to its default.
diff --git a/src/Components/test/E2ETest/Tests/BindTest.cs b/src/Components/test/E2ETest/Tests/BindTest.cs
index 3d17faf792..172c6973bc 100644
--- a/src/Components/test/E2ETest/Tests/BindTest.cs
+++ b/src/Components/test/E2ETest/Tests/BindTest.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Globalization;
using BasicTestApp;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
@@ -640,5 +641,241 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
Browser.Equal(newValue, () => boundValue.Text);
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"));
+ }
}
}
diff --git a/src/Components/test/testassets/BasicTestApp/BindCasesComponent.razor b/src/Components/test/testassets/BasicTestApp/BindCasesComponent.razor
index 113bfd3846..7b827d633f 100644
--- a/src/Components/test/testassets/BasicTestApp/BindCasesComponent.razor
+++ b/src/Components/test/testassets/BasicTestApp/BindCasesComponent.razor
@@ -110,6 +110,56 @@
+Date Textboxes (type=text)
+
+ DateTime:
+
+ @textboxDateTimeValue
+
+
+
+ Nullable DateTime:
+
+ @textboxNullableDateTimeValue
+
+
+
+ DateTimeOffset:
+
+ @textboxDateTimeOffsetValue
+
+
+
+ Nullable DateTimeOffset:
+
+ @textboxNullableDateTimeOffsetValue
+
+
+
+ DateTime (format):
+
+ @textboxDateTimeFormatValue
+
+
+
+ Nullable DateTime (format):
+
+ @textboxNullableDateTimeFormatValue
+
+
+
+ DateTimeOffset (format):
+
+ @textboxDateTimeOffsetFormatValue
+
+
+
+ Nullable DateTimeOffset (format):
+
+ @textboxNullableDateTimeOffsetFormatValue
+
+
+
Text Area
Initially blank:
@@ -145,7 +195,8 @@
Select
@code {
-string textboxInitiallyBlankValue = null;
-string textboxInitiallyPopulatedValue = "Hello";
+ string textboxInitiallyBlankValue = null;
+ string textboxInitiallyPopulatedValue = "Hello";
-string textAreaInitiallyBlankValue = null;
-string textAreaInitiallyPopulatedValue = "Hello";
+ string textAreaInitiallyBlankValue = null;
+ string textAreaInitiallyPopulatedValue = "Hello";
-bool? checkboxInitiallyNullValue = null;
-bool checkboxInitiallyUncheckedValue = false;
-bool checkboxInitiallyCheckedValue = true;
+ bool? checkboxInitiallyNullValue = null;
+ bool checkboxInitiallyUncheckedValue = false;
+ bool checkboxInitiallyCheckedValue = true;
-int textboxIntValue = -42;
-int? textboxNullableIntValue = null;
-long textboxLongValue = 3_000_000_000;
-long? textboxNullableLongValue = null;
-float textboxFloatValue = 3.141f;
-float? textboxNullableFloatValue = null;
-double textboxDoubleValue = 3.14159265359d;
-double? textboxNullableDoubleValue = null;
-decimal textboxDecimalValue = 0.0000000000000000000000000001M;
-decimal? textboxNullableDecimalValue = null;
-decimal textboxDecimalInvalidValue = 0.0000000000000000000000000001M;
-decimal? textboxNullableDecimalInvalidValue = null;
+ int textboxIntValue = -42;
+ int? textboxNullableIntValue = null;
+ long textboxLongValue = 3_000_000_000;
+ long? textboxNullableLongValue = null;
+ float textboxFloatValue = 3.141f;
+ float? textboxNullableFloatValue = null;
+ double textboxDoubleValue = 3.14159265359d;
+ double? textboxNullableDoubleValue = null;
+ decimal textboxDecimalValue = 0.0000000000000000000000000001M;
+ decimal? textboxNullableDecimalValue = null;
+ decimal textboxDecimalInvalidValue = 0.0000000000000000000000000001M;
+ decimal? textboxNullableDecimalInvalidValue = null;
-int textboxGenericIntValue = -42;
-Guid textboxGenericGuidValue = Guid.Empty;
+ int textboxGenericIntValue = -42;
+ Guid textboxGenericGuidValue = Guid.Empty;
-bool includeFourthOption = false;
-enum SelectableValue { First, Second, Third, Fourth }
-SelectableValue selectValue = SelectableValue.Second;
-SelectableValue selectMarkupValue = SelectableValue.Second;
+ DateTime textboxDateTimeValue = new DateTime(1985, 3, 4);
+ DateTime? textboxNullableDateTimeValue = null;
+ DateTimeOffset textboxDateTimeOffsetValue = new DateTimeOffset(new DateTime(1985, 3, 4), TimeSpan.FromHours(8));
+ DateTimeOffset? textboxNullableDateTimeOffsetValue = null;
-void AddAndSelectNewSelectOption()
-{
- includeFourthOption = true;
- selectValue = SelectableValue.Fourth;
-}
+ DateTime textboxDateTimeFormatValue = new DateTime(1985, 3, 4);
+ DateTime? textboxNullableDateTimeFormatValue = null;
+ DateTimeOffset textboxDateTimeOffsetFormatValue = new DateTimeOffset(new DateTime(1985, 3, 4), TimeSpan.FromHours(8));
+ 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;
+ }
}
diff --git a/src/Components/test/testassets/BasicTestApp/GlobalizationBindCases.razor b/src/Components/test/testassets/BasicTestApp/GlobalizationBindCases.razor
index bbab6ffde2..beb6ae4688 100644
--- a/src/Components/test/testassets/BasicTestApp/GlobalizationBindCases.razor
+++ b/src/Components/test/testassets/BasicTestApp/GlobalizationBindCases.razor
@@ -1,3 +1,5 @@
+@using System.Globalization
+@using Microsoft.AspNetCore.Components.Forms
Globalization Bind Cases
Culture is: @System.Globalization.CultureInfo.CurrentCulture.Name
@@ -25,6 +27,31 @@
+
+
Numbers using bind in number fields
+
+ int: inputTypeNumberInt = value, inputTypeNumberInt, CultureInfo.InvariantCulture)" />
+ @inputTypeNumberInt
+
+
+ decimal: inputTypeNumberDecimal = value, inputTypeNumberDecimal, CultureInfo.InvariantCulture)"/>
+ @inputTypeNumberDecimal
+
+
+
+
+
Dates using bind in date fields
+
+ DateTime:
+ inputTypeDateDateTime = value, inputTypeDateDateTime, "yyyy-MM-dd", CultureInfo.InvariantCulture)" />
+ @inputTypeDateDateTime
+
+
+ DateTimeOffset:
+ inputTypeDateDateTimeOffset = value, inputTypeDateDateTimeOffset, "yyyy-MM-dd", CultureInfo.InvariantCulture)"/>
+ @inputTypeDateDateTimeOffset
+
+
@code {
int inputTypeTextInt = 42;
@@ -32,4 +59,10 @@
DateTime inputTypeTextDateTime = 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));
}