视图显示不同的值,然后在其模型中
View displays different values, then it has in its model
简要概述
我有一个非常奇怪的错误,我完全不知道它来自哪里。我想创建一个网页,您可以在其中修改一个 table 并由此 table 您可以在数据库中生成一个 table。为此,我正在使用 ASP .NET MVC 4 并且我已经能够在数据库中修改和创建 table,但是我有一个小的“+”按钮,我想在其中插入单元格table(模型)。
问题
It already works, but it is inserting it always at the last index AND the name is also equal to the one, which was last before. (same for deleting with "-" button)
这里有两个截图:
点击前:
点击后:
代码
为了实现这一点,我创建了两个模型:
创建表格模型
我用一列初始化模型。 (我还有更多不相关的属性和功能)
public class CreateTableModels
{
public CreateTableModels()
{
Columns = new List<CreateTableColumnModels>() { new CreateTableColumnModels(){ PrimaryKey = true } };
}
[Required]
[UniqueNamesValidation(ErrorMessage="Alle Namen müssen unique sein")]
[Display(Name = "Columns")]
public List<CreateTableColumnModels> Columns { get; private set; }
//more properties...
此模型具有 CreateTableColumnModels 的列表:
public class CreateTableColumnModels
{
public CreateTableColumnModels()
{
Name = "name";
NotNull = false;
PrimaryKey = false;
Length = 1;
}
[Required]
[Display(Name = "Typ")]
public System.Data.SqlDbType Type { get; set; }
[Key]
[Required(ErrorMessage = "Darf nicht leer sein!")]
[RegularExpression(@"^[A-Za-z0-9]+$", ErrorMessage = "Nur Buchstaben und Zahlen sind erlaubt")]
[Display(Name = "Name")]
public string Name { get; set; }
//more properties...
控制器
我想在控制器中向模型插入一列(如果按下按钮,它会通过 addCell 发送索引)。该列的名称应为 "Added"。如果我添加一个新列,它工作正常。
public class CreateTableController : Controller
{
public ViewResult Index(CreateTableModels model, int count = 1, int? addCell = null, int? removeCell = null, bool createTable = false)
{
if (addCell != null)
{
model.Columns.Insert(addCell.Value, new CreateTableColumnModels() { Name = "ADDED", Type = System.Data.SqlDbType.Float });
}
查看
我几乎把整个视图都放在这里了,因为我完全不知道问题出在哪里。
<h2>CreateTable</h2>
@using (Html.BeginForm("Index", "CreateTable", FormMethod.Get))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
@Html.ValidationSummary(true)
</div>
<table id="table" class="table">
<thead>
<tr>
<th>@Html.LabelFor(model => model.Columns.FirstOrDefault().Type)</th>
<th>@Html.LabelFor(model => model.Columns.FirstOrDefault().Length)</th>
<th>@Html.LabelFor(model => model.Columns.FirstOrDefault().Precision)</th>
<th>@Html.LabelFor(model => model.Columns.FirstOrDefault().Name)</th>
<th>@Html.LabelFor(model => model.Columns.FirstOrDefault().NotNull)</th>
<th>@Html.LabelFor(model => model.Columns.FirstOrDefault().PrimaryKey)</th>
</tr>
</thead>
<tbody>
@for (int i = 0; i < @Model.Columns.Count; i++)
{
<tr>
<td>
<div id="TableSelection">
@Html.DropDownListFor(m => Model.Columns[i].Type, new SelectList(Model.Columns[i].Types), new { @ID = "typeSelection", @class = "form-control", @style = "width:150px;" })
</div>
</td>
<td>
<div id="Length">
@Html.TextBoxFor(m => Model.Columns[i].Length, new { @ID = "length", @class = "form-control", @type = "number", @style = "width:80px", @disabled = "disabled" })
@Html.ValidationMessageFor(m => Model.Columns[i].Length)
</div>
</td>
<td>
<div id="Precision">
@Html.TextBoxFor(m => Model.Columns[i].Precision, new { @ID = "precision", @class = "form-control", @type = "number", @style = "width:80px", @disabled = "disabled" })
@Html.ValidationMessageFor(m => Model.Columns[i].Precision)
</div>
</td>
<td>
<div id="Name">
@Html.TextBoxFor(model => Model.Columns[i].Name, new { @class = "form-control", @style = "width:150px" })
@Html.ValidationMessageFor(model => Model.Columns[i].Name)
</div>
</td>
<td>
<div id="NotNull">
@Html.CheckBoxFor(model => Model.Columns[i].NotNull, new { @ID = "notNull", @checked = Model.Columns[i].NotNull, @class = "checkbox" })
</div>
</td>
<td>
<div id="PrimaryKey">
@Html.CheckBoxFor(x => Model.Columns[i].PrimaryKey, new { @ID = "primaryKey", @checked = Model.Columns[i].PrimaryKey, @class = "checkbox" })
</div>
</td>
<td>
<div>
<button type="submit" class="btn btn-default" name="addCell" value="@i">+</button>
<button type="submit" class="btn btn-default" name="removeCell" value="@i">-</button>
</div>
</td>
</tr>
}
</tbody>
</table>
<div align="left" class=" form-group" style="display: flex; flex-direction: row; justify-content: flex-start; align-items: center;">
<div>
@Html.LabelFor(model => model.TableName, new { @class = "control-label col-md-2" })
</div>
<div class="text-center control-form">
@Html.EditorFor(model => model.TableName, new { @class = "text-center control-form" })
@Html.ValidationMessageFor(model => model.TableName)
</div>
<div>
<button type="submit" style="margin-left:10px; margin-right:10px;" name="createTable" value="true" class="btn btn-success">Create</button>
</div>
<div>
@if (Model.WorkDone != null && (bool)Model.WorkDone)
{
<label style="font-size:medium" class="label label-success">Alle Änderungen wurden gespeichert!</label>
}
else if (Model.WorkDone != null)
{
<label style="font-size:medium" class="label label-danger">Es ist etwas schief gelaufen!</label>
}
</div>
</div>
}
调试
此外,如果我调试它直到视图结束,它具有正确的值。
我唯一能想到的改变是 _Layout.cshtml
文件中的 @RenderBody()
。有没有人有类似的东西或可以帮助我?已经感谢阅读到最后:)
问题是当您提交 collection 时,发布的值会添加到 ModelState
。如果我们只查看 Name
属性,则会添加以下值
Columns[0].Name // value = "a"
Columns[1].Name // value = "b"
Columns[2].Name // value = "c"
现在插入一个新列(比如在第一项之前)。模型中的值现在是
Columns[0].Name // value = "ADDED"
Columns[1].Name // value = "a"
Columns[2].Name // value = "b"
Columns[3].Name // value = "c"
现在,当您 return 视图时,您(正确地)使用 HtmlHelper
方法生成视图,但是生成表单控件的所有 HtmlHelper
方法都呈现 value
属性通过检查以下(按顺序)
ModelState
中的值(如果有)
ViewDataDictionary
中的值(如果有)
- 来自模型的值
此行为的原因在 TextBoxFor displaying initial value, not the value updated from code 中解释。
在 for
循环的第一次迭代中,您的 @Html.TextBoxFor(m => m.Columns[i].Name)
在 ModelState
中看到 "a" 的值并在文本框中呈现 "a" (即使模型的值为 "ADDED").
在第 2 次迭代中,值再次取自 ModelState
,因此呈现 "b"。
在第 3 次迭代中,值再次取自 ModelState
,因此呈现 "c"。
并且在第 4 次也是最后一次迭代中,Columns[3].Name
在 ModelState
(或 ViewData
)中找不到值,因此它从模型中读取值,因此 "c" 被渲染。
作为旁注,如果您在 table 单元格中添加 @Model.Columns[i].Name
,您会看到根据 属性 值呈现的值,即第 1 行:"ADDED",第 2 行:"a",第 3 行:"b",第 4 行:"c".
要解决此问题,您可以在 return 视图之前添加 ModelState.Clear()
。但是,这样做的副作用是它还会清除所有验证错误,因此至少,如果 ModelState
无效
,您应该立即 return 视图
public ViewResult Index(CreateTableModels model, ...)
{
if (!ModelState.IsValid)
{
return View(model);
}
... // code to insert new row
ModelState.Clear();
return View(model);
}
但是,最好的方法是遵循 PRG 模式并重定向到生成新数据的方法。
简要概述
我有一个非常奇怪的错误,我完全不知道它来自哪里。我想创建一个网页,您可以在其中修改一个 table 并由此 table 您可以在数据库中生成一个 table。为此,我正在使用 ASP .NET MVC 4 并且我已经能够在数据库中修改和创建 table,但是我有一个小的“+”按钮,我想在其中插入单元格table(模型)。
问题
It already works, but it is inserting it always at the last index AND the name is also equal to the one, which was last before. (same for deleting with "-" button)
这里有两个截图:
点击前:
代码
为了实现这一点,我创建了两个模型:
创建表格模型
我用一列初始化模型。 (我还有更多不相关的属性和功能)
public class CreateTableModels
{
public CreateTableModels()
{
Columns = new List<CreateTableColumnModels>() { new CreateTableColumnModels(){ PrimaryKey = true } };
}
[Required]
[UniqueNamesValidation(ErrorMessage="Alle Namen müssen unique sein")]
[Display(Name = "Columns")]
public List<CreateTableColumnModels> Columns { get; private set; }
//more properties...
此模型具有 CreateTableColumnModels 的列表:
public class CreateTableColumnModels
{
public CreateTableColumnModels()
{
Name = "name";
NotNull = false;
PrimaryKey = false;
Length = 1;
}
[Required]
[Display(Name = "Typ")]
public System.Data.SqlDbType Type { get; set; }
[Key]
[Required(ErrorMessage = "Darf nicht leer sein!")]
[RegularExpression(@"^[A-Za-z0-9]+$", ErrorMessage = "Nur Buchstaben und Zahlen sind erlaubt")]
[Display(Name = "Name")]
public string Name { get; set; }
//more properties...
控制器
我想在控制器中向模型插入一列(如果按下按钮,它会通过 addCell 发送索引)。该列的名称应为 "Added"。如果我添加一个新列,它工作正常。
public class CreateTableController : Controller
{
public ViewResult Index(CreateTableModels model, int count = 1, int? addCell = null, int? removeCell = null, bool createTable = false)
{
if (addCell != null)
{
model.Columns.Insert(addCell.Value, new CreateTableColumnModels() { Name = "ADDED", Type = System.Data.SqlDbType.Float });
}
查看
我几乎把整个视图都放在这里了,因为我完全不知道问题出在哪里。
<h2>CreateTable</h2>
@using (Html.BeginForm("Index", "CreateTable", FormMethod.Get))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
@Html.ValidationSummary(true)
</div>
<table id="table" class="table">
<thead>
<tr>
<th>@Html.LabelFor(model => model.Columns.FirstOrDefault().Type)</th>
<th>@Html.LabelFor(model => model.Columns.FirstOrDefault().Length)</th>
<th>@Html.LabelFor(model => model.Columns.FirstOrDefault().Precision)</th>
<th>@Html.LabelFor(model => model.Columns.FirstOrDefault().Name)</th>
<th>@Html.LabelFor(model => model.Columns.FirstOrDefault().NotNull)</th>
<th>@Html.LabelFor(model => model.Columns.FirstOrDefault().PrimaryKey)</th>
</tr>
</thead>
<tbody>
@for (int i = 0; i < @Model.Columns.Count; i++)
{
<tr>
<td>
<div id="TableSelection">
@Html.DropDownListFor(m => Model.Columns[i].Type, new SelectList(Model.Columns[i].Types), new { @ID = "typeSelection", @class = "form-control", @style = "width:150px;" })
</div>
</td>
<td>
<div id="Length">
@Html.TextBoxFor(m => Model.Columns[i].Length, new { @ID = "length", @class = "form-control", @type = "number", @style = "width:80px", @disabled = "disabled" })
@Html.ValidationMessageFor(m => Model.Columns[i].Length)
</div>
</td>
<td>
<div id="Precision">
@Html.TextBoxFor(m => Model.Columns[i].Precision, new { @ID = "precision", @class = "form-control", @type = "number", @style = "width:80px", @disabled = "disabled" })
@Html.ValidationMessageFor(m => Model.Columns[i].Precision)
</div>
</td>
<td>
<div id="Name">
@Html.TextBoxFor(model => Model.Columns[i].Name, new { @class = "form-control", @style = "width:150px" })
@Html.ValidationMessageFor(model => Model.Columns[i].Name)
</div>
</td>
<td>
<div id="NotNull">
@Html.CheckBoxFor(model => Model.Columns[i].NotNull, new { @ID = "notNull", @checked = Model.Columns[i].NotNull, @class = "checkbox" })
</div>
</td>
<td>
<div id="PrimaryKey">
@Html.CheckBoxFor(x => Model.Columns[i].PrimaryKey, new { @ID = "primaryKey", @checked = Model.Columns[i].PrimaryKey, @class = "checkbox" })
</div>
</td>
<td>
<div>
<button type="submit" class="btn btn-default" name="addCell" value="@i">+</button>
<button type="submit" class="btn btn-default" name="removeCell" value="@i">-</button>
</div>
</td>
</tr>
}
</tbody>
</table>
<div align="left" class=" form-group" style="display: flex; flex-direction: row; justify-content: flex-start; align-items: center;">
<div>
@Html.LabelFor(model => model.TableName, new { @class = "control-label col-md-2" })
</div>
<div class="text-center control-form">
@Html.EditorFor(model => model.TableName, new { @class = "text-center control-form" })
@Html.ValidationMessageFor(model => model.TableName)
</div>
<div>
<button type="submit" style="margin-left:10px; margin-right:10px;" name="createTable" value="true" class="btn btn-success">Create</button>
</div>
<div>
@if (Model.WorkDone != null && (bool)Model.WorkDone)
{
<label style="font-size:medium" class="label label-success">Alle Änderungen wurden gespeichert!</label>
}
else if (Model.WorkDone != null)
{
<label style="font-size:medium" class="label label-danger">Es ist etwas schief gelaufen!</label>
}
</div>
</div>
}
调试
此外,如果我调试它直到视图结束,它具有正确的值。
我唯一能想到的改变是 _Layout.cshtml
文件中的 @RenderBody()
。有没有人有类似的东西或可以帮助我?已经感谢阅读到最后:)
问题是当您提交 collection 时,发布的值会添加到 ModelState
。如果我们只查看 Name
属性,则会添加以下值
Columns[0].Name // value = "a"
Columns[1].Name // value = "b"
Columns[2].Name // value = "c"
现在插入一个新列(比如在第一项之前)。模型中的值现在是
Columns[0].Name // value = "ADDED"
Columns[1].Name // value = "a"
Columns[2].Name // value = "b"
Columns[3].Name // value = "c"
现在,当您 return 视图时,您(正确地)使用 HtmlHelper
方法生成视图,但是生成表单控件的所有 HtmlHelper
方法都呈现 value
属性通过检查以下(按顺序)
ModelState
中的值(如果有)ViewDataDictionary
中的值(如果有)- 来自模型的值
此行为的原因在 TextBoxFor displaying initial value, not the value updated from code 中解释。
在 for
循环的第一次迭代中,您的 @Html.TextBoxFor(m => m.Columns[i].Name)
在 ModelState
中看到 "a" 的值并在文本框中呈现 "a" (即使模型的值为 "ADDED").
在第 2 次迭代中,值再次取自 ModelState
,因此呈现 "b"。
在第 3 次迭代中,值再次取自 ModelState
,因此呈现 "c"。
并且在第 4 次也是最后一次迭代中,Columns[3].Name
在 ModelState
(或 ViewData
)中找不到值,因此它从模型中读取值,因此 "c" 被渲染。
作为旁注,如果您在 table 单元格中添加 @Model.Columns[i].Name
,您会看到根据 属性 值呈现的值,即第 1 行:"ADDED",第 2 行:"a",第 3 行:"b",第 4 行:"c".
要解决此问题,您可以在 return 视图之前添加 ModelState.Clear()
。但是,这样做的副作用是它还会清除所有验证错误,因此至少,如果 ModelState
无效
public ViewResult Index(CreateTableModels model, ...)
{
if (!ModelState.IsValid)
{
return View(model);
}
... // code to insert new row
ModelState.Clear();
return View(model);
}
但是,最好的方法是遵循 PRG 模式并重定向到生成新数据的方法。