Blazor TwoWay在自定义组件上的绑定

时间:2019-10-02 07:14:32

标签: c# .net-core blazor blazor-server-side blazor-client-side

我正在创建一个blazor服务器端应用程序,在将值绑定到两个自定义组件之间时遇到问题。

我通过另一个示例了解了bind或@bind应该如何工作,但是我无法弄清有关此问题的最新信息。

给出一个模型类用户:

ids <- c(20, 30, 40)
regex <- paste(ids, collapse="|")
fileList <- list.files(pattern=paste0("^Start_(", regex, ")_end\\.csv$"))

我想构建一个显示该用户所有属性的表单,并将它们输入到输入中,以便可以对其进行编辑并最终保存到数据库中。

我的表单(父组件)如下:

public class User
    {
        [Mapping(ColumnName = "short_id")]
        public string ShortId { get; set; }

        public User()
        {

        }
    }

<div class="edit-user-form"> <AnimatedUserInput TbText="@User.ShortId" Placeholder="MHTEE Id"/> <button class="btn btn-secondary" @onclick="Hide" style="{display:inline-block;}">Back</button> <button class="btn btn-primary" @onclick="SaveUser" style="{display:inline-block;}">Save</button> </div> @code { [Parameter] public vUser User { get; set; } [Parameter] public Action Hide { get; set; } bool _error = false; void SaveUser() { ValidateUserData(); } void ValidateUserData() { _error = string.IsNullOrWhiteSpace(User.ShortId); } } 是如下所示的自定义组件:

AnimatedUserInput

现在在“输入”文本框中,我可以在父组件中正确看到<div class="edit-area @FocusClass @WiggleClass"> <input type="text" @bind="@TbText" /> <span data-placeholder="@Placeholder"></span> </div> @code { [Parameter] public string TbText { get; set; } [Parameter] public string Placeholder { get; set; } } 对象的ShortId

但是,如果我更改输入中的文本并单击User按钮,该按钮会触发Save方法,并允许我查看当前的ValidateUserData对象,那么我看不到任何更改已经在实际的User属性中完成了,但仅在输入上完成了。

有什么方法可以绑定它,以便将输入中的更改自动应用于绑定的属性?

我有几种这样的属性,需要以表格的形式显示,这就是为什么我不想为每个属性都挂接到自定义User.ShortId事件的原因。

3 个答案:

答案 0 :(得分:0)

好吧,对于任何对此绊脚石的人。我尝试了更多,找到了解决方案。 因此,在我的自定义输入组件TextField( onSubmitted: (value){ print(value); // or do whatever you want when you are done editing // call your method/print values etc } ) 中,我添加了一个EventCallback,每次输入值更新时都会调用该事件:

AnimatedUserInput

父组件上的绑定看起来像这样:

@code {

    [Parameter]
    public string TbText
    {
        get => _tbText;
        set
        {
            if (_tbText == value) return;

            _tbText = value;
            TbTextChanged.InvokeAsync(value);
        }
    }

    [Parameter]
    public EventCallback<string> TbTextChanged { get; set; }

    [Parameter]
    public string Placeholder { get; set; }

    private string _tbText;
}

通过这种方式,blazor可以将值正确绑定在一起,并按照我希望它们绑定的方式从两侧进行更新。

答案 1 :(得分:0)

这就是我如何实现双向绑定

父组件

<LabelledField Class=""
   Label="Label value"
   DateValue="@Model.Value"
   OnDateChange="@((e) => Model.Value = e )"
   Type="InputType.date" />

子组件

<div class="@Class">
<div class="ft-07 mb-03 field-label @LabelClass">@Label</div>
@switch (Type)
{
    case InputType.constant:
        <div class="label-field-value @ValueClass">@Value</div>
        break;
    case InputType.text:
        <input class="form-control input @ValueClass"
               type="text"
               @bind="Value" />

        break;
    case InputType.date:
        <input class="form-control input @ValueClass"
               type="date"
               @bind="DateValue" />

        break;
    default:
        break;
}
@code{
private string _tbText;
private DateTime? _tbDate;

[Parameter]
public string Class { get; set; }

[Parameter]
public string Label { get; set; }

[Parameter]
public string LabelClass { get; set; }

[Parameter]
public string Value
{
    get => _tbText;
    set
    {
        if (_tbText == value) return;

        _tbText = value;
        OnTextChange.InvokeAsync(value);
    }
}

[Parameter]
public DateTime? DateValue
{
    get => _tbDate;
    set
    {
        if (_tbDate == value) return;

        _tbDate = value;
        OnDateChange.InvokeAsync(_tbDate);
    }
}

[Parameter]
public string ValueClass { get; set; }

[Parameter]
public InputType Type { get; set; } = InputType.constant;

[Parameter]
public EventCallback<string> OnTextChange { get; set; }

[Parameter]
public EventCallback<DateTime?> OnDateChange { get; set; }
}

答案 2 :(得分:0)

感谢你们在这里发布的例子。使用它们,我基于 W3schools' How TO-Toggle Switch 中的 Toggle Switch 示例做了一个自定义输入复选框双向绑定组件,如下所示:

enter image description here

当它改变状态时触发事件。

组件

<div class="@Class">
    <label class="switch">
        <input id="@Id" type="checkbox" @bind="IsOn" />
        <span class="slider round"></span>
    </label>
</div>

@code {
    [Parameter] public EventCallback<bool> OnToggle { get; set; }
    [Parameter] public string Id { get; set; }
    [Parameter] public string Class { get; set; }
    [Parameter] public bool SetAsChecked { get; set; }

    private bool _isSettingUp = true;
    private bool _isOn;

    protected override Task OnInitializedAsync()
    {
        IsOn = SetAsChecked;
        return base.OnInitializedAsync();
    }

    private bool IsOn
    {
        get => _isOn;
        set
        {
            _isOn = value;
            if (!_isSettingUp)
            {
                OnToggle.InvokeAsync(value);
            }
            _isSettingUp = false;
        }
    }
}

_isSettingUp 标志是我发现在最初设置检查时不会触发 EventCallback 的方式。也许有人会找到更好的方法来解决这个问题。

父母

(这里是你使用组件的地方)

<ToggleSwitch Id="mySwitch" OnToggle="((isChecked)=>DoSomething(isChecked))" SetAsChecked="isChecked" />

@code {
    private bool isChecked;

    protected override void OnInitialized()
    {
        isChecked = true;
    }

    protected void DoSomething(bool isChecked)
    {
        Console.WriteLine($">>>> {isChecked} <<<<");
    }
}

CSS

CSS 改编自 W3Scholl 示例 here。 如果您想利用 Blazor CSS Isolation,它应该放在一个名为组件的 .razor.css 文件中(在同一文件夹中)。然后就可以使用组件的Class参数来适应不同的需求。

.switch {
    position: relative;
    display: inline-block;
    width: 60px;
    margin-top: 7px;
}

    .switch input {
        opacity: 0;
        width: 0;
        height: 0;
    }

.slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    padding-top: 2px;
    background-color: #737272;
    -webkit-transition: .7s;
    transition: .7s;
    width: 62px;
    height: 29px;
}

    .slider:before {
        position: absolute;
        content: "\2716";
        text-align: center;
        color: dimgrey;
        height: 25px;
        width: 25px;
        left: 2px;
        bottom: 2px;
        padding-top: 1px;
        background-color: white;
        -webkit-transition: .8s;
        transition: .8s;
    }

input:checked + .slider {
    background-color: limegreen;
}

    input:checked + .slider:before {
        -webkit-transform: translateX(33px);
        -ms-transform: translateX(33px);
        transform: translateX(33px);
        content: "\2714";
        text-align: center;
        color: dodgerblue;
    }

.slider.round {
    border-radius: 20px;
}

    .slider.round:before {
        border-radius: 50%;
    }

顺便说一下,您可以在开关中放置任何 HTML Symbol。我确实从具有搜索和 CSS 代码的 this cool page 中挑选了这些,如果我们在 CSS 内容中添加符号,这就是我们所需要的,如下所示。

希望这对某人有用。