[英]Bind values of a property of my model from a generic EditorFor template
我試圖編寫一個通用框架來協助開發向導樣式的表單。
我有一個模型,該模型的屬性表示向導中的每個步驟,例如
public class ExampleWizardTransaction : WizardTransaction
{
public override TransactionType TransactionType { get; set; } = TransactionType.ExampleWizard;
public override string ControllerName { get; set; } = "WizardExample";
[DisplayName("Client Details")]
public ClientDetails ClientDetails { get; set; } = new ClientDetails();
[DisplayName("Client Questions")]
public ClientQuestions ClientQuestions { get; set; } = new ClientQuestions();
[DisplayName("Client Preferences")]
public ClientPreferences ClientPreferences { get; set; } = new ClientPreferences();
}
[Step(1)]
public class ClientDetails : IStep
{
[Display(Description = "Please enter your first name")]
public string FirstName { get; set; }
[Display(Description = "Please enter your last name")]
public string LastName { get; set; }
}
[Step(2)]
public class ClientQuestions : IStep
{
[DisplayName("What is your favourite car?")]
public string FavouriteCar { get; set; }
[DisplayName("What is your favourite holiday destination?")]
public string FavouriteDestination { get; set; }
}
[Step(3)]
public class ClientPreferences : IStep
{
[DisplayName("Red or Blue?")]
public Colours Colour { get; set; }
[DisplayName("Do you like Indian food")]
public bool LikeFood { get; set; }
}
最初,我對每個向導步驟都有部分視圖,如下所示:
@model Web.Models.ExampleWizard.Create
<div class="row">
<div class="col-md-6">
@Html.EditorFor(x => x.ExampleWizardTransaction.ClientDetails)
</div>
</div>
使用此方法,表單的值可以正確綁定,因為在我發布表單時,MVC知道綁定上下文。
在我的表單上,我通過傳遞步驟號來呈現局部視圖,例如
Html.RenderPartial($"_CreateWizard_{Model.ExampleWizardTransaction.CurrentStep}", Model);
我試圖對代碼進行一般化,因此不需要在向導的每個步驟中都包含部分視圖。
為此,我呈現了一個操作,該操作確定與向導步驟關聯的類型,然后返回部分視圖:
Html.RenderAction("GetStep", "ExampleWizard", Model.ExampleWizardTransaction);
我的局部視圖指定了每個向導步驟都實現的接口:
_WizardStep.cshtml
@model Services.ViewModels.Wizard.IStep
<div class="row">
<div class="col-md-6">
@Html.EditorFor(x => x)
</div>
</div>
當我使用上面的方法時,表單可以正確呈現,但是值不再在POST上綁定,我認為這是因為它沒有屬性的綁定上下文(例如,輸入類型的ID和名稱為'完全合格)。
我在向導步驟中有一個用於字符串屬性的EditorFor模板,用於呈現文本框:
@model string
<div class="col-md-12">
<div class="form-group">
<label class="m-b-none" for="@ViewData.Model">
@ViewData.ModelMetadata.DisplayName
</label>
<span class="help-block m-b-none small m-t-none">@ViewData.ModelMetadata.Description</span>
<div class="input-group">
@Html.TextBox("", Model, new {@class = "form-control"})
<div class="input-group-addon">
<i class="fa validation"></i>
</div>
</div>
</div>
</div>
是否可以使用我的通用“ _WizardStep.cshtml”局部視圖,並且仍將當前步驟的屬性綁定到我的模型?
我的控制器如下所示:
[HttpPost]
public virtual ActionResult CreateWizard(Create model, string action)
{
var createModel = CreateModel<Create>();
switch (createModel.Save(action))
{
case WizardState.Finished:
return RedirectToActionWithMessage("List", "Transaction", "Completed", ToastNotificationStatus.Success);
case WizardState.Ongoing:
return RedirectToAction(MVC.ExampleWizard.CreateWizard(
model.ExampleWizardTransaction.Id,
model.ExampleWizardTransaction.GetNextStep(action)));
default:
model.MapExistingTransactions<ExampleWizardTransaction>();
return View(model);
}
}
我的“創建”模型包含我的“ ExampleWizardTransaction”屬性,該屬性包含實現IStep接口的每個向導步驟。
從@StephenMuecke的答案中獲得啟發,我采取了以下方法。
在我的“ CreateWizard.cshtml”視圖上,用以下行呈現此步驟:
@Html.WizardPartialFor(x => x.ExampleWizardTransaction.GetStepObject<IStep>(), "_WizardStep", Model.ExampleWizardTransaction)
這將調用“ WizardPartialFor”擴展方法:
public static MvcHtmlString WizardPartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper,
Expression<Func<TModel, TProperty>> expression, string partialViewName, IWizardTransaction wizardTransaction)
{
var compiled = expression.Compile();
var result = compiled.Invoke(helper.ViewData.Model);
PropertyInfo currentStep = wizardTransaction.GetCurrentStepPropertyInfo();
string currentStepName = currentStep.PropertyType.Name;
var name = $"{currentStep.DeclaringType.Name}.{currentStepName}";
var viewData = new ViewDataDictionary(helper.ViewData)
{
TemplateInfo = new TemplateInfo { HtmlFieldPrefix = name }
};
return helper.Partial(partialViewName, result, viewData);
}
public static PropertyInfo GetCurrentStepPropertyInfo(this IWizardTransaction wizardTransaction)
{
var properties = wizardTransaction.GetType().GetProperties()
.Where(x => x.PropertyType.GetCustomAttributes(typeof(StepAttribute), true).Any());
return properties.FirstOrDefault(x => ((StepAttribute)Attribute
.GetCustomAttribute(x.PropertyType, typeof(StepAttribute))).Step == wizardTransaction.CurrentStep);
}
在此擴展方法中,我們調用一個擴展方法,該方法獲取向導步驟對象:
public static TProperty GetStepObject<TProperty>(this IWizardTransaction wizardTransaction)
where TProperty : class
{
var properties = wizardTransaction.GetType().GetProperties()
.Where(x => x.PropertyType.GetCustomAttributes(typeof(StepAttribute), true).Any());
var @object = properties.FirstOrDefault(x => ((StepAttribute)Attribute
.GetCustomAttribute(x.PropertyType, typeof(StepAttribute))).Step == wizardTransaction.CurrentStep);
return @object.GetValue(wizardTransaction) as TProperty;
}
這樣可以成功呈現我的通用_WizardStep部分視圖,並且還可以成功綁定POST上的數據。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.