【问题标题】:input text value: revert to previous value输入文本值:恢复到以前的值
【发布时间】:2021-08-06 09:53:46
【问题描述】:

我正在构建一个 @inherits InputBase<string[]> 的自定义 Blazor 组件。

在内部,输入 String[] 被解析并转换为对象列表。

迭代该对象列表并为每个项目输入生成:

<input type="text" value="@_list[j].Value" @onchange="(e => UpdateItem(j, e))" />

UpdateItem 方法做了几件事。例如,它更新集合中的项目并检查新值是否为空字符串,如果是则从集合中删除项目。

但是,当用户在输入文本中添加无效字符时,UpdateItem 会删除它们并执行list[index] = v,但因为list[index] == v 它不会更改底层项目或列表。 CurrentValue 保持正确,但界面没有更新,例如输入文本保持无效值,这是误导。如果我删除该项目并将其插入同一索引,它仍然无法正常工作。删除和添加它确实会更新界面,但最后添加的项目令人困惑。

我尝试在 UpdateItem 方法和其他地方调用StateHasChanged(),但没有帮助。

如何“告诉”输入值进行自我更新?或者如何将值“标记”为已更新,尽管它是相同的以触发界面更新。

也许我对这个问题有完全错误的方法。我从&lt;input @bind="@_list[j].Value"... /&gt; 开始,效果很好,但我需要控制绑定以验证输入并最终更改它。这就是我选择上述路线的原因。

【问题讨论】:

    标签: blazor blazor-webassembly


    【解决方案1】:

    我认为有几个问题让您感到困惑。

    首先这是一个工作演示页面,我认为它封装了您想要实现的目标:

    @page "/StringTester"
    <h3>String Test Page</h3>
    
    @foreach (var str in MyStrings)
    {
        <div class="form">
            <input @key="str" class="form-control" value="@str.Value" @onchange="(e) => StringChanged(e, str.Key )" />
        </div>
    }
    
    @code {
    
        SortedList<int, string> MyStrings = new SortedList<int, string> { { 1, "UK" }, { 2, "Australia" }, { 3, "Spain" } };
    
        string[] invalidchars = { "=", "+" };
    
        //  Must be async and Task based for the Yield to work
        async Task StringChanged(ChangeEventArgs e, int key)
        {
            var val = e.Value.ToString();
            if (string.IsNullOrEmpty(val))
                MyStrings.Remove(key);
            else
            {
                var newvalue = InvalidCharStripper(val);
                if (MyStrings[key].Equals(newvalue))
                {
                    MyStrings[key] = val;
                    await Task.Yield();
                }
                MyStrings[key] = newvalue;
            }
        }
    
        //  quick and dirty method to do some input manipulation  - remove invalid chars from the string
        string InvalidCharStripper(string value)
        {
            foreach (var x in invalidchars)
            {
                value = value.Replace(x, string.Empty);
            }
            return value;
        }
    }
    
    1. “字符串是对象但按值传递”问题。

    2. Blazor 渲染器。当您创建输入时,它会呈现为&lt;input value="Australia"&gt;。当用户将其更改为“Austalia+”时,处理移除“+”并将其设置为“Australia”。显示值“Austalia+”仅存在于实际浏览器 DOM 中,而不存在于 Renderer DOM 中。渲染器仍然认为它是“Austalia”,所以不会重新渲染它。

    我通过将字符串数组设置为有序列表解决了第一个问题。它现在是一个对象并且有秩序。

    我通过检查新值(已删除无效字符)是否与旧值相同来解决的第二个问题。如果是这样,那么我将MyStrings 值设置为无效值并将Yield 控制返回给任务调度程序。现在,事件处理程序在最终的 MyStrings[key] = newvalue 代码块运行之前重新渲染组件。最后一次渲染组件,并为输入分配正确的值。

    如果您想了解更多关于 Blazor 事件流程的信息,您可以阅读更多内容here

    【讨论】:

    • await Task.Yield(); 是关键。感谢您的帮助和您为清楚地解释这一点所付出的所有努力。期待阅读您的博客。
    猜你喜欢
    • 1970-01-01
    • 2012-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多