循环遍历编号的属性以在 Razor Pages 中生成输入
Loop through numbered properties to generate inputs in Razor Pages
我有一个包含 34 个编号属性的模型,如下所示
Public Class ViewModel
{
public string RatingCategory01 { get; set; }
public string RatingCategory02 { get; set; }
public string RatingCategory03 { get; set; }
//...and so on until category #34
}
我不想在 Razor Pages 中为每个类别编写输入代码,而是使用循环遍历所有类别并生成适当的控制组。我试过下面的代码:
<tbody>
@for (var i = 1; i < 35; i++)
{
string n;
@if (i > 0 && i < 10)
{
n = "RatingCategory0" + i.ToString();
}
else
{
n = "RatingCateogry" + i.ToString();
}
<tr>
<td>
<label asp-for="@string.Format("RatingCategory" + n)" class="control-label"></label>
</td>
<td>
<select asp-for="@string.Format("RatingCategory" + n)" asp-items="Model.CategoryRatingSelectList">
<option value="">Select</option>
</select>
</td>
<td>
<input asp-for="@string.Format("RemedialTime" + n)" class="form-control" />
</td>
</tr>
}
</tbody>
当我构建项目并导航到页面时,出现此错误:
InvalidOperationException: Templates can be used only with field
access, property access, single-dimension array index, or
single-parameter custom indexer expressions.
我不确定我是否在正确的轨道上。我真的很想创建一个循环来生成这些输入,以便将来的维护和更改更容易。从我的 code/question 可以很明显地看出,我对此很陌生,因此非常感谢您的帮助。
编辑以添加解决方案:
我使用了 Ed Plunkett 提供的解决方案,我在下面进行了检查。我稍微修改了一下,最终创建了一个名为 'Rating' 的新 class,因为我发现在实践中我需要一个更复杂的对象。我现在的观点是
public List<Rating> Ratings = { get; set; }
在控制器中,我使用循环根据需要的数量向列表中添加尽可能多的空评级。
for (var i = 0; i < 34; i++)
{
vm.Ratings.Add(new Rating());
}
尽管随着应用程序的发展,这可能会更新为使用硬编码数字以外的其他内容。
最后,我在视图中使用了一个循环,为列表中的每个评级创建了一组控件。在这种情况下,它是一个 TableRow,在不同的列中包含不同的控件:
@for (var i = 0; i < Model.Ratings.Count; i++)
{
<tr>
<td>
@Html.DisplayFor(model => model.Ratings[i].Category)
</td>
<td>
<div class="form-group">
<select asp-for="Ratings[i].RatingValue" asp-items="Model.CategoryRatingSelectList">
<option value="">Select</option>
</select>
</div>
</td>
<td>
<input asp-for="Ratings[i].RemediationMinutes" class="form-control" />
</td>
</tr>
}
我发现这组输入中的数据可以通过简单地包含
来绑定为一个列表
List<Rating> Ratings
在提交表单时运行的任何方法的参数中。
您可以将您的模型 class 转换为字典;
var viewModel = new ViewModel()
{
RatingCategory01 = "a",
RatingCategory02 = "b",
RatingCategory03 = "c"
};
var dictionaryModel = viewModel.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.ToDictionary(prop => prop.Name, prop => prop.GetValue(viewModel, null));
然后您可以在视图中迭代字典。
这就是您想要的,而不是那 34 个属性及其隐含的 34 个 RemedialTime
兄弟姐妹:
public List<String> RatingCategory { get; set; } = new List<String>();
public List<String> RemedialTime { get; set; } = new List<String>();
如果您有 34 个东西,并且名称仅在索引号上有所不同,那就是一个集合,而不是 34 个具有顺序编号名称的不同属性。然后,您可以使用 foreach
循环枚举 34 个项目,或将它们分别索引为 RatingCategory[0]
到 RatingCategory[33]
。在 C# 中,集合索引从零开始,因此第一个是 0
,第三十四个是 33
。你会习惯的。
您还应该查看 String.Format() 的作用。 String.Format("Foo" + 1)
与 "Foo" + 1
完全相同。
我有一个包含 34 个编号属性的模型,如下所示
Public Class ViewModel
{
public string RatingCategory01 { get; set; }
public string RatingCategory02 { get; set; }
public string RatingCategory03 { get; set; }
//...and so on until category #34
}
我不想在 Razor Pages 中为每个类别编写输入代码,而是使用循环遍历所有类别并生成适当的控制组。我试过下面的代码:
<tbody>
@for (var i = 1; i < 35; i++)
{
string n;
@if (i > 0 && i < 10)
{
n = "RatingCategory0" + i.ToString();
}
else
{
n = "RatingCateogry" + i.ToString();
}
<tr>
<td>
<label asp-for="@string.Format("RatingCategory" + n)" class="control-label"></label>
</td>
<td>
<select asp-for="@string.Format("RatingCategory" + n)" asp-items="Model.CategoryRatingSelectList">
<option value="">Select</option>
</select>
</td>
<td>
<input asp-for="@string.Format("RemedialTime" + n)" class="form-control" />
</td>
</tr>
}
</tbody>
当我构建项目并导航到页面时,出现此错误:
InvalidOperationException: Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
我不确定我是否在正确的轨道上。我真的很想创建一个循环来生成这些输入,以便将来的维护和更改更容易。从我的 code/question 可以很明显地看出,我对此很陌生,因此非常感谢您的帮助。
编辑以添加解决方案:
我使用了 Ed Plunkett 提供的解决方案,我在下面进行了检查。我稍微修改了一下,最终创建了一个名为 'Rating' 的新 class,因为我发现在实践中我需要一个更复杂的对象。我现在的观点是
public List<Rating> Ratings = { get; set; }
在控制器中,我使用循环根据需要的数量向列表中添加尽可能多的空评级。
for (var i = 0; i < 34; i++)
{
vm.Ratings.Add(new Rating());
}
尽管随着应用程序的发展,这可能会更新为使用硬编码数字以外的其他内容。
最后,我在视图中使用了一个循环,为列表中的每个评级创建了一组控件。在这种情况下,它是一个 TableRow,在不同的列中包含不同的控件:
@for (var i = 0; i < Model.Ratings.Count; i++)
{
<tr>
<td>
@Html.DisplayFor(model => model.Ratings[i].Category)
</td>
<td>
<div class="form-group">
<select asp-for="Ratings[i].RatingValue" asp-items="Model.CategoryRatingSelectList">
<option value="">Select</option>
</select>
</div>
</td>
<td>
<input asp-for="Ratings[i].RemediationMinutes" class="form-control" />
</td>
</tr>
}
我发现这组输入中的数据可以通过简单地包含
来绑定为一个列表List<Rating> Ratings
在提交表单时运行的任何方法的参数中。
您可以将您的模型 class 转换为字典;
var viewModel = new ViewModel()
{
RatingCategory01 = "a",
RatingCategory02 = "b",
RatingCategory03 = "c"
};
var dictionaryModel = viewModel.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.ToDictionary(prop => prop.Name, prop => prop.GetValue(viewModel, null));
然后您可以在视图中迭代字典。
这就是您想要的,而不是那 34 个属性及其隐含的 34 个 RemedialTime
兄弟姐妹:
public List<String> RatingCategory { get; set; } = new List<String>();
public List<String> RemedialTime { get; set; } = new List<String>();
如果您有 34 个东西,并且名称仅在索引号上有所不同,那就是一个集合,而不是 34 个具有顺序编号名称的不同属性。然后,您可以使用 foreach
循环枚举 34 个项目,或将它们分别索引为 RatingCategory[0]
到 RatingCategory[33]
。在 C# 中,集合索引从零开始,因此第一个是 0
,第三十四个是 33
。你会习惯的。
您还应该查看 String.Format() 的作用。 String.Format("Foo" + 1)
与 "Foo" + 1
完全相同。