如何在Blazor中从集合/列表绑定到元素?

16

我想在循环中将我的列表中的值绑定到元素上,但我找不到合适的解决方案。

<EditForm Model="@dailyReport" OnValidSubmit="@SubmitDailyReport">
        <p>
            <label>Count: </label>
            <InputNumber min="1" id="numberOfEffects" @bind-Value="numberOfEffects" />
        </p>
        @{
            for (int i = 1; i <= numberOfEffects; i++)
            {
                if (effects.Count < i)
                {
                    effects.Add("");
                }

                if (effects.Count > i)
                {
                    effects.RemoveAt(effects.Count - 1);
                }

                string concatId = "effect" + i.ToString();

                <p>
                    <label for="@concatId">@i</label>
                    <InputText id="@concatId" @bind-Value="effects.ElementAt(i-1)" />
                </p>
            }
         }
//rest code
 </EditForm>

当我尝试从列表中将值绑定到元素时,出现错误:

  1. 错误 CS0131:赋值运算符左侧必须是变量、属性或索引器错误
  2. 错误 CS1662:无法将 lambda 表达式转换为预期的委托类型,因为块中的某些返回类型不是委托返回类型的隐式可转换项

我想知道是否有可能将数据绑定到集合。我需要这样做是因为我的模型具有 List 类型的属性。在我的输入表单中,我希望允许用户添加尽可能多的字符串。

编辑:

@code
{
    private DailyReport dailyReport = new DailyReport();
    private List<string> effects = new List<string>();
}

我也尝试着在 foreach 循环中完成它,但是出现了另外一个错误: 无法对“效果”进行赋值,因为它是“foreach 迭代变量”

foreach (var effect in effects)
            {
                index++;
                Console.WriteLine(index);

                string concatId = "effect" + index.ToString();

                <p>
                    <label for="@concatId">@index</label>
                    <InputText id="@concatId" @bind-Value="effect" />
                </p>
            }

我在@code部分声明它们。 - scarybook
请尝试修改您的代码片段,使其变得最小化,参见 https://stackoverflow.com/help/minimal-reproducible-example - Paolo Fulgoni
1个回答

21

绑定无法工作:当输入文本的值发生变化时,您希望修改列表而不是元素本身。

相反,您必须将绑定操作“拆分”为两个方向:

  • 根据模型的值设置输入字段的值
  • 在输入字段的值更改时设置模型

下面的代码显示了如何解决主要问题,然后您需要根据自己的需求进行调整。

@foreach (var element in effects.Select((e, i) => new { Effect = e, Index = i}))
{
    <p>
        <label for="@($"effect{element.Index}")">@element.Index</label>
        <input id="@($"effect{element.Index}")" value="@element.Effect"
               @onchange="@(e => effects[element.Index] = e.Value.ToString())" />
    </p>
}

@code {

    private List<string> effects = new List<string>() { "a", "b", "c" };

}

第一行代码起到了关键作用:它将列表转换为可枚举对象,其中每个元素都是一个新对象,该对象封装了其在effects列表中的索引和值。你需要索引主要是因为@onchange事件需要知道在原始列表中哪个位置应该更新该值。

如果您愿意,也可以使用for循环:

@for (int i = 0; i < effects.Count; i++)
{
    // see https://dev59.com/wrTma4cB1Zd3GeqP3kJv#56426146
    var iCopy = i;

    <p>
        <label for="@($"effect{i}")">@i</label>
        <input id="@($"effect{i}")" value="@effects[i]"
               @onchange="@(e => effects[iCopy] = e.Value.ToString())" />
    </p>
}

@code {

    private List<string> effects = new List<string>() { "a", "b", "c" };

}

我已经尝试过这个方法,效果非常好。但是在我的onchange函数中,我有一些验证,如果验证通过,则会更新列表中的数据。 但是当验证失败时,UI中的值仍然没有重置为原始值。 它仍然显示编辑后的值。尝试使用StateHasChange(),但它不起作用。 - Ameerudheen.K
@Ameerudheen.K 我建议您发布一个新问题,其中包含一个最小的代码示例,以展示您的问题。 - Paolo Fulgoni
我已经解决了那个问题。这是我的问题链接:https://stackoverflow.com/questions/68901935/reset-input-field-value-if-value-is-invalid-in-blazor/68905769?noredirect=1#comment121784489_68905769 - Ameerudheen.K

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接