根据来自控制器的逻辑在 MVC 中设置视图样式
Styling a view in MVC based on logic from the controller
我正在创建一个应用程序,用户必须按顺序完成一系列步骤。在控制器中,我检查每个步骤是否完成或正在进行,然后根据此信息,我将样式属性添加到 ViewModel,然后将其传递给视图。
以下是包含步骤的视图:
所以在控制器中,我有以下代码当前正在填充视图:
switch (WhatStep)
{
case 1:
ViewModel.WhatStep = 1;
ViewModel.StepOneComplete = false;
ViewModel.StepOnePanelColour = "info";
ViewModel.StepOneStatusText = "<span class=\"text-info pull-right\"><strong>Next Step</strong></span>";
ViewModel.StepOneCollapsedText = "open";
ViewModel.StepTwoComplete = false;
ViewModel.StepTwoPanelColour = "default";
ViewModel.StepTwoStatusText = "<span class=\"text-default pull-right\"><strong>Upcoming</strong></span>";
ViewModel.StepTwoCollapsedText = "collapsed";
ViewModel.StepThreeComplete = false;
ViewModel.StepThreePanelColour = "default";
ViewModel.StepThreeStatusText = "<span class=\"text-default pull-right\"><strong>Upcoming</strong></span>";
ViewModel.StepThreeCollapsedText = "collapsed";
ViewModel.StepFourComplete = false;
ViewModel.StepFourPanelColour = "default";
ViewModel.StepFourStatusText = "<span class=\"text-default pull-right\"><strong>Upcoming</strong></span>";
ViewModel.StepFourCollapsedText = "open";
ViewModel.StepFiveComplete = false;
ViewModel.StepFivePanelColour = "default";
ViewModel.StepFiveStatusText = "<span class=\"text-default pull-right\"><strong>Upcoming</strong></span>";
ViewModel.StepFiveCollapsedText = "collapsed";
ViewModel.StepSixComplete = false;
ViewModel.StepSixPanelColour = "default";
ViewModel.StepSixStatusText = "<span class=\"text-default pull-right\"><strong>Upcoming</strong></span>";
ViewModel.StepSixCollapsedText = "collapsed";
break;
case 2:
ViewModel.WhatStep = 2;
ViewModel.StepOneComplete = true;
ViewModel.StepOnePanelColour = "success";
ViewModel.StepOneStatusText = "<span class=\"text-success pull-right\"><strong>✔ Complete</strong></span>";
ViewModel.StepOneCollapsedText = "collapsed";
ViewModel.StepTwoComplete = false;
ViewModel.StepTwoPanelColour = "info";
ViewModel.StepTwoStatusText = "<span class=\"text-info pull-right\"><strong>Next Step</strong></span>";
ViewModel.StepTwoCollapsedText = "open";
随着为每个步骤填充 viewModel,控制器不断运行。
每个面板的 html 视图如下所示:
<div class="panel panel-@Model.StepOnePanelColour">
<div class="panel-heading">
<h4 class="panel-title">
<strong>Step One:</strong>
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne" class="@Model.StepOneCollapsedText"></a>
@Html.Raw(Model.StepOneStatusText)
</h4>
</div>
<div id="collapseOne" class="panel-collapse collapse" style="height: 0px;">
<div class="panel-body">
<p>Instructions here<p>
</div>
</div>
</div>
虽然这种方法工作正常,但控制器包含 500 多行代码,只是为了根据用户所处的步骤填充 viewModel。
有更好的方法吗?
我建议通过 javascript 或 jQuery 和 CSS 进行样式设置。通过评估您的 ViewModel。让浏览器处理专门为此设计的 UI 样式。
您不仅可以将控制器代码减少到几行,还可以显着减少视图代码。
与其为每个步骤使用具有多个属性的视图模型,不如使用集合来表示步骤
public enum StepStatus
{
Upcoming,
Current,
Complete
}
public class Step
{
public int Number { get; set; }
public StepStatus Status { get; set; }
}
然后在生成视图的方法中
public ActionResult Index(int currentStep)
{
List<Step> model = new List<Step>();
for (int i = 0; i < 10; i++) // generates 10 steps
{
model.Add(new Step() { Number = i + 1 });
}
// Set the status of the steps based on the current step
for (int i = 0; i < currentStep; i++)
{
model[i].Status = StepStatus.Complete;
}
model[currentStep - 1].Status = StepStatus.InProgress;
return View(model);
}
而视图只是使用一个循环来生成每个步骤
@model List<Step>
....
<div id="accordion">
@for (int i = 0; i < Model.Count; i++)
{
<div class="panel @Model[i].Status.ToString().ToLower()"> // adds class name based on the status
<div class=" panel-heading">
<h4 class="panel-title">
<strong>Step @Model[i].Number</strong>
@{ string className = Model[i].Status == StepStatus.Current ? "open" : "collapsed"; }
<a data-toggle="collapse" data-parent="#accordion" href="#step@(Model[i].Number)" class="@className"></a>
<span class="text-default pull-right">
@if (Model[i].Status == StepStatus.Complete)
{
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> // adds the tick mark
}
<strong>@Model[i].Status</strong>
</span>
</h4>
</div>
<div id="step@(Model[i].Number)" class="panel-collapse collapse">
<div class="panel-body">
<p>Instructions here<p>
</div>
</div>
</div>
}
</div>
并添加一些 css 来模仿 panel-succcess
、panel-infoand panel-default
bootstap 类
.complete {
border-color: #d6e9c6;
}
.complete > .panel-heading {
color: #3c763d;
background-color: #dff0d8;
border-color: #d6e9c6;
}
.current {
border-color: #bce8f1;
}
.current > .panel-heading {
color: #31708f;
background-color: #d9edf7;
border-color: #bce8f1;
}
.upcoming {
border-color: #ddd;
}
.upcoming > .panel-heading {
color: #333;
background-color: #f5f5f5;
border-color: #ddd;
}
您没有说明如何在 <div class="panel-body">
元素中呈现内容,但是如果您想包含所有步骤的内容,可以使用 @Html.Action()
或使用 ajax 根据需要加载内容。使用一些约定,控制器方法可以简单地是
public PartialViewResult Step(int number, StepStatus status)
{
var model = .... // get the model based on the step number
string viewName = string.Format("_Step{0}{1}", number, status)
return PartialView(viewName, model);
}
你的部分内容被命名为 _Step1Complete.cshtml
、_Step1Current.cshtml
等(我假设你根据状态有不同的内容),以及在视图中生成内容的
<div class="panel-body">
@{ Html.RenderAction("Step", new { number = Model[i].Number, status = Model[i].Status }) // assumes the Step() method is in the same controller
</div>
我正在创建一个应用程序,用户必须按顺序完成一系列步骤。在控制器中,我检查每个步骤是否完成或正在进行,然后根据此信息,我将样式属性添加到 ViewModel,然后将其传递给视图。
以下是包含步骤的视图:
所以在控制器中,我有以下代码当前正在填充视图:
switch (WhatStep)
{
case 1:
ViewModel.WhatStep = 1;
ViewModel.StepOneComplete = false;
ViewModel.StepOnePanelColour = "info";
ViewModel.StepOneStatusText = "<span class=\"text-info pull-right\"><strong>Next Step</strong></span>";
ViewModel.StepOneCollapsedText = "open";
ViewModel.StepTwoComplete = false;
ViewModel.StepTwoPanelColour = "default";
ViewModel.StepTwoStatusText = "<span class=\"text-default pull-right\"><strong>Upcoming</strong></span>";
ViewModel.StepTwoCollapsedText = "collapsed";
ViewModel.StepThreeComplete = false;
ViewModel.StepThreePanelColour = "default";
ViewModel.StepThreeStatusText = "<span class=\"text-default pull-right\"><strong>Upcoming</strong></span>";
ViewModel.StepThreeCollapsedText = "collapsed";
ViewModel.StepFourComplete = false;
ViewModel.StepFourPanelColour = "default";
ViewModel.StepFourStatusText = "<span class=\"text-default pull-right\"><strong>Upcoming</strong></span>";
ViewModel.StepFourCollapsedText = "open";
ViewModel.StepFiveComplete = false;
ViewModel.StepFivePanelColour = "default";
ViewModel.StepFiveStatusText = "<span class=\"text-default pull-right\"><strong>Upcoming</strong></span>";
ViewModel.StepFiveCollapsedText = "collapsed";
ViewModel.StepSixComplete = false;
ViewModel.StepSixPanelColour = "default";
ViewModel.StepSixStatusText = "<span class=\"text-default pull-right\"><strong>Upcoming</strong></span>";
ViewModel.StepSixCollapsedText = "collapsed";
break;
case 2:
ViewModel.WhatStep = 2;
ViewModel.StepOneComplete = true;
ViewModel.StepOnePanelColour = "success";
ViewModel.StepOneStatusText = "<span class=\"text-success pull-right\"><strong>✔ Complete</strong></span>";
ViewModel.StepOneCollapsedText = "collapsed";
ViewModel.StepTwoComplete = false;
ViewModel.StepTwoPanelColour = "info";
ViewModel.StepTwoStatusText = "<span class=\"text-info pull-right\"><strong>Next Step</strong></span>";
ViewModel.StepTwoCollapsedText = "open";
随着为每个步骤填充 viewModel,控制器不断运行。
每个面板的 html 视图如下所示:
<div class="panel panel-@Model.StepOnePanelColour">
<div class="panel-heading">
<h4 class="panel-title">
<strong>Step One:</strong>
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne" class="@Model.StepOneCollapsedText"></a>
@Html.Raw(Model.StepOneStatusText)
</h4>
</div>
<div id="collapseOne" class="panel-collapse collapse" style="height: 0px;">
<div class="panel-body">
<p>Instructions here<p>
</div>
</div>
</div>
虽然这种方法工作正常,但控制器包含 500 多行代码,只是为了根据用户所处的步骤填充 viewModel。
有更好的方法吗?
我建议通过 javascript 或 jQuery 和 CSS 进行样式设置。通过评估您的 ViewModel。让浏览器处理专门为此设计的 UI 样式。
您不仅可以将控制器代码减少到几行,还可以显着减少视图代码。
与其为每个步骤使用具有多个属性的视图模型,不如使用集合来表示步骤
public enum StepStatus
{
Upcoming,
Current,
Complete
}
public class Step
{
public int Number { get; set; }
public StepStatus Status { get; set; }
}
然后在生成视图的方法中
public ActionResult Index(int currentStep)
{
List<Step> model = new List<Step>();
for (int i = 0; i < 10; i++) // generates 10 steps
{
model.Add(new Step() { Number = i + 1 });
}
// Set the status of the steps based on the current step
for (int i = 0; i < currentStep; i++)
{
model[i].Status = StepStatus.Complete;
}
model[currentStep - 1].Status = StepStatus.InProgress;
return View(model);
}
而视图只是使用一个循环来生成每个步骤
@model List<Step>
....
<div id="accordion">
@for (int i = 0; i < Model.Count; i++)
{
<div class="panel @Model[i].Status.ToString().ToLower()"> // adds class name based on the status
<div class=" panel-heading">
<h4 class="panel-title">
<strong>Step @Model[i].Number</strong>
@{ string className = Model[i].Status == StepStatus.Current ? "open" : "collapsed"; }
<a data-toggle="collapse" data-parent="#accordion" href="#step@(Model[i].Number)" class="@className"></a>
<span class="text-default pull-right">
@if (Model[i].Status == StepStatus.Complete)
{
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> // adds the tick mark
}
<strong>@Model[i].Status</strong>
</span>
</h4>
</div>
<div id="step@(Model[i].Number)" class="panel-collapse collapse">
<div class="panel-body">
<p>Instructions here<p>
</div>
</div>
</div>
}
</div>
并添加一些 css 来模仿 panel-succcess
、panel-infoand panel-default
bootstap 类
.complete {
border-color: #d6e9c6;
}
.complete > .panel-heading {
color: #3c763d;
background-color: #dff0d8;
border-color: #d6e9c6;
}
.current {
border-color: #bce8f1;
}
.current > .panel-heading {
color: #31708f;
background-color: #d9edf7;
border-color: #bce8f1;
}
.upcoming {
border-color: #ddd;
}
.upcoming > .panel-heading {
color: #333;
background-color: #f5f5f5;
border-color: #ddd;
}
您没有说明如何在 <div class="panel-body">
元素中呈现内容,但是如果您想包含所有步骤的内容,可以使用 @Html.Action()
或使用 ajax 根据需要加载内容。使用一些约定,控制器方法可以简单地是
public PartialViewResult Step(int number, StepStatus status)
{
var model = .... // get the model based on the step number
string viewName = string.Format("_Step{0}{1}", number, status)
return PartialView(viewName, model);
}
你的部分内容被命名为 _Step1Complete.cshtml
、_Step1Current.cshtml
等(我假设你根据状态有不同的内容),以及在视图中生成内容的
<div class="panel-body">
@{ Html.RenderAction("Step", new { number = Model[i].Number, status = Model[i].Status }) // assumes the Step() method is in the same controller
</div>