簡體   English   中英

如何在 asp net 5 中為“asp-for”傳遞字符串值

[英]How can I pass string value for "asp-for" in asp net 5

我想為一個有很多屬性要編輯的實體寫一個Edit.cshtml文件,所以不得不寫很多次如下代碼:

<div class="form-group">
    <label asp-for="Email" class="col-md-2 control-label"></label>
    <div class="col-md-10">
        <input asp-for="Email" class="form-control" />
        <span asp-validation-for="Email" class="text-danger"></span>
    </div>
</div>

實際上,有很多實體,因此我必須編寫許多 Edit.cshtml 文件。 我想做一些簡化

我想在控制器中選擇實體的一些屬性並使用循環在視圖中顯示這些屬性。 例如: 在控制器文件中:

public IActionResult Edit(string id)
{
    var model = GetModel(id);
    var propertyNames= new List<string>()
    {
        "Name",
        "Email"
        // add some other property names of the entity 
    };
    ViewData["PropertyList"] = propertyNames;
    return View(model);
}

在視圖文件中:

@{
    var propertyNames = (List<string>)ViewData["PropertyList"];
    foreach (string item in propertyNames)
    {
        <div class="form-group">
            <label asp-for="@(item)" class="col-md-2 control-label"></label>
            <div class="col-md-3">
                <input asp-for="@(item)" class="form-control" />
                <span asp-validation-for="@(item)" class="text-danger"></span>
            </div>          
        </div>
    }
}

但它無法工作,因為它會生成錯誤的代碼。 似乎我無法為“asp-for”標簽助手傳遞字符串值。

例如,如果我將 top 的代碼更改為:

@{
    string e = "Email";
    <div class="form-group">
        <label asp-for="@e" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input asp-for="@e" class="form-control" />
            <span asp-validation-for="@e" class="text-danger"></span>
        </div>
    </div>
}

上面的代碼將生成:

<div class="form-group">
    <label class="col-md-2 control-label" for="e">e</label>
    <div class="col-md-10">
        <input class="form-control" type="text" id="e" name="e" value="Email" />
        <span class="text-danger field-validation-valid" data-valmsg-for="e" data-valmsg-replace="true"></span>
    </div>
</div>

預期的代碼是:

<div class="form-group">
    <label class="col-md-2 control-label" for="Email">Email</label>
    <div class="col-md-10">
        <input class="form-control" type="email" data-val="true" data-val-email="Email &#x5B57;&#x6BB5;&#x4E0D;&#x662F;&#x6709;&#x6548;&#x7684;&#x7535;&#x5B50;&#x90AE;&#x4EF6;&#x5730;&#x5740;&#x3002;" data-val-required="Email &#x5B57;&#x6BB5;&#x662F;&#x5FC5;&#x9700;&#x7684;&#x3002;" id="Email" name="Email" value="" />
        <span class="text-danger field-validation-valid" data-valmsg-for="Email" data-valmsg-replace="true"></span>
    </div>
</div>

我應該怎么做?

剃須刀可以嗎?

好的,我設法讓這個工作。 免責聲明:這是超級hacky,我不知道我是否以最好的方式完成了它。 我所知道的是,它可以滿足您的需求,並且可能會為您指明正確的方向。

首先,我創建了一個模型:

using System.ComponentModel.DataAnnotations;

namespace WebApplication1.Models
{
    public class TestModel
    {
        [Required]
        public string Name { get; set; }

        [Required]
        [EmailAddress]
        [Display(Name = "Email Address")]
        public string Email { get; set; }
    }
}

然后,我制作了一個自定義標簽助手。 這是“魔法”發生的可怕之處。 特別是Process方法的第一部分......

using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.TagHelpers;
using System.Linq;

namespace WebApplication1.TagHelpers
{
    [HtmlTargetElement("edit")]
    public class EditTagHelper : TagHelper
    {
        [HtmlAttributeName("asp-for")]
        public ModelExpression aspFor { get; set; }

        [ViewContext]
        [HtmlAttributeNotBound]
        public ViewContext ViewContext { get; set; }

        protected IHtmlGenerator _generator { get; set; }

        public EditTagHelper(IHtmlGenerator generator)
        {
            _generator = generator;
        }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            var propName = aspFor.ModelExplorer.Model.ToString();
            var modelExProp = aspFor.ModelExplorer.Container.Properties.Single(x => x.Metadata.PropertyName.Equals(propName));
            var propValue = modelExProp.Model;
            var propEditFormatString = modelExProp.Metadata.EditFormatString;

            var label = _generator.GenerateLabel(ViewContext, aspFor.ModelExplorer,
                propName, propName, new { @class = "col-md-2 control-label", @type = "email" });

            var input = _generator.GenerateTextBox(ViewContext, aspFor.ModelExplorer,
                propName, propValue, propEditFormatString, new { @class = "form-control" });

            var validation = _generator.GenerateValidationMessage(ViewContext, aspFor.ModelExplorer, 
                propName, string.Empty, string.Empty, new { @class = "text-danger" });

            var inputParent = new TagBuilder("div");
            inputParent.AddCssClass("col-md-10");
            inputParent.InnerHtml.Append(input);
            inputParent.InnerHtml.Append(validation);

            var parent = new TagBuilder("div");
            parent.AddCssClass("form-group");
            parent.InnerHtml.Append(label);
            parent.InnerHtml.Append(inputParent);

            output.Content.SetContent(parent);
            base.Process(context, output);
        }
    }
}

注意:要使自定義 TagHelper 工作,您需要在_ViewImports.cshtml文件中添加一行,如下所示(將WebApplication1替換為您的命名空間):

@addTagHelper "*, WebApplication1"

我改變了我的行動,以匹配你的行動(也許你可以在這里使用反射來獲取你的模型屬性名稱?):

public IActionResult Index()
{
    var propertyNames = new List<string>()
    {
        "Name",
        "Email"
    };
    ViewData["PropertyList"] = propertyNames;

    var m = new TestModel()
    {
        Name = "huoshan12345",
        Email = "test@test.net"
    };
    return View(m);
}

最后,在視圖中,您可以執行以下操作:

<div class="row">
    @using (Html.BeginForm())
    {
        var propertyNames = (List<string>)ViewData["PropertyList"];
        foreach (string item in propertyNames)
        {
            <edit asp-for="@item"></edit>
        }
        <input type="submit" value="Submit" />
    }
</div>

你也可以試試這個:

 foreach (string item in propertyNames){
     @Html.TextBox(item, value: null, htmlAttributes: new { @class = "form-control" })      
}

是的,可以用剃刀寫它。 認為這會幫助你。 如果您不放置“type”屬性,它將使用type='text'生成它。 您也可以對 data-val 屬性進行硬編碼,但不建議僅將 '-' 替換為 '_' 例如: @data_val_email

<div class="form-group">
  @Html.LabelFor(x=>x.Email)
  <div class="col-md-10">
     @Html.TextBoxFor(x => x.Email, new { @class = "form-control", @type = "email" })
      @Html.ValidateFor(x=>x.Email)
  </div>
</div>

這是一個相關的技術。 我擴展了標簽助手以將所需的 HTML 注入頁面。 這有點像 ASP.NET MVC EditorTemplate。

這是注入特殊局部視圖的自定義標簽助手

public class MyFormGroupTagHelper : PartialTagHelper
{
    public MyFormGroupTagHelper(ICompositeViewEngine viewEngine, IViewBufferScope viewBufferScope) : base(viewEngine, viewBufferScope)
    { }

    public ModelExpression Property { get; set; }

    public string LabelText { get; set; } = null;

    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        this.For = Property;
        this.Name = "_FormGroup";
        // Have to use Viewdata to pass information to the partial view, because the model is the single property of the entity that will be posted back to the controller
        this.ViewData["TH_LabelText"] = LabelText;
        this.ViewData["TH_DataTypeName"] = Property.Metadata.DataTypeName;
        await base.ProcessAsync(context, output);
    }
}

這是部分視圖_FormGroup.cshtml。 這將為具有 Bootstrap 樣式的表單上的單個字段生成標記。 如果字段是日期,它還會將“datepicker”類附加到輸入標簽。 請注意 asp-for 是如何使用 @Model 填充的,因此可以將同一視圖綁定到任何實體模型上的任何屬性

@model object

@{
    string LabelText = (string)@ViewData["TH_LabelText"];
    string DataTypeName = (string) ViewData["TH_DataTypeName"];
    bool IsDate = (DataTypeName == "Date");
}

<div class="form-group row">
    @if (LabelText != null)
    {
    <label asp-for="@Model" class="control-label col-md-4">@LabelText</label>
    }
    <div class="col-md-8">
        <input asp-for="@Model" class="form-control @( IsDate ? "datepicker" : "")"  />
        <span asp-validation-for="@Model" class="text-danger"></span>
    </div>
</div>

現在在 Create 或 Edit 視圖中,模型是業務實體,您可以像這樣創建代碼來編輯實體上的單個屬性。

<my-form-group label-text="Result date" property="ResultDate" view-data="ViewData" ></my-form-group>

在這種情況下,模型是一個具有名為 ResultDate 的字段的類,定義如下:

    [DataType(DataType.Date)]
    public DateTime? ResultDate { get; set; }

請注意,您必須設置 view-data 屬性才能將 ViewData 對象傳遞給標簽助手。 它使用 ViewData 將信息傳遞給局部視圖。 這並不理想,但我想不出任何其他方式將信息傳遞到局部視圖。 我在鍵前加上“TH_”以防止標簽助手覆蓋 Viewdata 中的任何其他值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM