使用可为空和不可为空的日期值创建 Blazor 自定义日期选择器组件

Posted

技术标签:

【中文标题】使用可为空和不可为空的日期值创建 Blazor 自定义日期选择器组件【英文标题】:Create Blazor custom date picker component with nullable and non-nullable date value 【发布时间】:2021-05-01 13:15:00 【问题描述】:

我想在 Blazor 中创建自定义日期选择器组件。我的代码是这样的

<div class="form-group">
<label>@Title</label>
<input type="date" class="form-control" @bind="Value" />
</div>

@code
        [Parameter]
        public string Title  get;set; 
        private DateTime? _value;
        [Parameter]
        public DateTime? Value
        
            get
            
                return _value;
            
            set
            
                if (Value == _value)
                
                    return;
                
                _value = value;
                ValueChanged.InvokeAsync(value);

            
        

        [Parameter]
        public EventCallback<DateTime?> ValueChanged  get; set; 


问题是该组件仅在值为可为空的 DateTime (DateTime?) 时才有效,如果值为 DateTime,则会引发错误

cannot convert from 'Microsoft.AspNetCore.Components.EventCallback<System.DateTime>' to 'Microsoft.AspNetCore.Components.EventCallback'

我决定让绑定值接受可为空的,因为我认为它会接受这两种类型。它与 int、double ... 等一起工作。 所以我想让它接受 DateTime 和 DateTime? 有什么想法吗?

更新: 我试图让组件接受泛型类型,但它会抛出错误 无法将 T 转换为 DateTime

【问题讨论】:

【参考方案1】:

这里是你的泛型组件:

@using System.Globalization
@using System

@typeparam TValue

<div class="form-group">
<label>@Title</label>
<input 
    type="date"
    class="form-control" 
    value="@FormatValueAsString(Value)"
    @onchange="@OnChange"
/>
</div>

@code 
    private const string DateFormat = "yyyy-MM-dd";
    CultureInfo provider = CultureInfo.InvariantCulture;
    private TValue _value;
    [Parameter] public string Title get; set;
    [Parameter] public TValue Value
    
        get
        
            return _value;
        
        set
        
            if (EqualityComparer<TValue>.Default.Equals(value , _value))
            
                return;
            
            _value = value;
            ValueChanged.InvokeAsync(value);

        
    

    [Parameter] public EventCallback<TValue> ValueChanged  get; set; 
    private void OnChange( ChangeEventArgs args)
    
        try
        
            Value = 
                (TValue)(object)
                DateTime
                .ParseExact(args.Value.ToString(),DateFormat, provider);
        
        catch 
            Value = default(TValue); // not sure you want this
                
    
    protected string FormatValueAsString(TValue? value)
    
        switch (value)
        
            case DateTime dateTimeValue:
                var r = BindConverter.FormatValue(dateTimeValue, DateFormat, provider);
                return r;
            default:
                return string.Empty; 
        
        

但是……我建议你继承InputDate。

看看"Option 2 (recomended): Through inheritance from InputBase "

在https://blazorrepl.com/repl/QlYPQBFj03U9ITNe13查看我

【讨论】:

谢谢,这是我正在寻找的解决方案。我会检查建议的链接【参考方案2】:

更简单的方法是继承微软的 InputDate 组件。我在 Blazor 中实现了 Bootstrap4 验证样式,请参见以下 sn-ps:

@inherits InputDate<TValue>

@typeparam TValue

<input @attributes="AdditionalAttributes"
        type="date"
        class="@Bs4InputHelpers.FixClassNames(CssClass)"
        value="@BindConverter.FormatValue(CurrentValueAsString)"
        @oninput="EventCallback.Factory.CreateBinder<string>(
    this, value => CurrentValueAsString = value, CurrentValueAsString)" />

@code 


对于帮助者:

public static class Bs4InputHelpers
    
        public static string FixClassNames(string inputClassNames)
        
            //NOTE: Notice the space in front of the class name, this is to ensure we get
            // the suffix to our existing form-control class set from the mark up and NOT
            // half of an invalid tag.  We could use a reg-ex but that might be a bit
            // too slow for the UI rendering to stay smooth.

            // The invalid string shall always be fixed up, as we can never get it until the
            // element has checked at least once by an attempted submit.
            string result = inputClassNames.Replace(" invalid", " is-invalid");

            // The valid tag is on by default, and to keep consistency with BS4 we only want
            // it to appear either when our field is modified, or we've tried a submit
            if (inputClassNames.Contains("modified"))
            
                result = result.Replace(" valid", " is-valid");
            

            return result;
        


    

【讨论】:

以上是关于使用可为空和不可为空的日期值创建 Blazor 自定义日期选择器组件的主要内容,如果未能解决你的问题,请参考以下文章

输入数据集可为空的日期值存在问题

如何在 Linq 的 where 条件下从可为空的日期时间中删除时间部分

混合 Blazor 组件、DI 和 C# 8 可为空

退出构造函数时,不可为空的属性必须包含非空值。考虑将属性声明为可为空

处理 Net 6 的可为空和实体框架实体 [关闭]

检查可为空的布尔值是不是为空[重复]