MVC 中的 Widget






4.88/5 (20投票s)
使用 Razor View 在 MVC 中轻松构建 Widget
引言
本文将帮助您使用 Razor 视图和 MVC4 构建一个可管理的 widget。 这不是一篇完全技术性的文章,它将为您提供在为我们的产品构建自定义组件或功能时,关于架构设计重要性的清晰概念。 在这里,我将向您展示嵌套部分视图的使用,该视图依赖于抽象,并且还具有可扩展性功能。
使用代码
Widgets 对我们来说非常熟悉。 大多数网站都具有此功能。 对于用户来说,在一个视图中获取信息非常重要,这样他/她就可以在登录网站时非常轻松地计划他们的工作。 因此,widgets 可以包含来自多个来源的信息。 假设您的公司让您负责设计一个可以轻松插入模型并且也是动态的 widget 模块。 在这里,我将讨论关于此类需求的设计概念。 假设我们正在构建一个公告板 widget。 在这里,我正在使用接口来构建该 widget。 我在此设计中有两个主要接口
- IWidget.cs
- ISubWidget.cs
您可能会问为什么需要两个接口,IWidget
不够吗?
答案:这是因为我们需要一个动态 widget。
在这里查看详细信息
public interface ISubWidget
{
string Topic { get; set; }
string Description { get; set; }
}
public interface IWidget
{
int SortOrder { get; set; }
string ClassName { get; set; }
string FooterText { get; set; }
string HeaderText { get; set; }
ISubWidget SubWidget { get; set; }
}
所以这里 IWidget
有一个属性 SubWidget
,它的返回类型是 ISubwidget
。 现在我们的 IWidget
就像一个包一样为我们工作。 那么我们的任务是构建一个公告板 Widget,对吧?
public class NoticeBoard : IWidget
{
public int SortOrder { get; set; }
public string ClassName { get; set; }
public string FooterText { get; set; }
public string HeaderText { get; set; }
public ISubWidget SubWidget { get; set; }
}
public class SubWidget : ISubWidget
{
public string Topic { get; set; }
public string Description { get; set; }
}
我们在类中构建了 widget,现在我们需要将其附加到 MVC 应用程序。 在展示模型填充之前,我想向您展示视图的设计概念。 我们将在这里使用部分视图。 由于接口,我们有相同的部分视图
- _Widget.cshtml
- _SubWiget.cshtml
_Widget.cshtml 的 Razor 视图将填充 IWidget
模型,并将 ISubwidget
加载到其主体部分。 对于它们两个,路径都是 View/Shared/Widget/。
@model MvcWidgetBuilder.Models.IWidget
<div class="widget">
<div class="@Model.ClassName">
<div class="header">
@Model.HeaderText
</div>
<div class="body">
@Html.Partial(string.Concat(new[] { "Widget",
"/", "_SubWidget" }), @Model.SubWidget)
</div>
<div class="footer">
@Model.FooterText
</div>
</div>
</div>
_SubWidget.cshtml 的 Razor 视图将填充 ISubWidget
模型
@model MvcWidgetBuilder.Models.ISubWidget
<div class="body">
<div>
<div style="float: left">
@Html.LabelFor(p => p.Topic, @Model.Topic)
</div>
</div>
<div style="clear: both">
@Model.Description
</div>
</div>
所以我们构建了我们的部分视图。 谁将调用它们来将它们加载到浏览器中? 我们还有另一个视图来完成这项工作
- _WidgetContainer.cshtml
我将只把模型 IWidget
传递给部分视图 _Widget.cshtml。 此视图的路径与之前相同:View/Shared/Widget/。
@model MvcWidgetBuilder.Models.IWidget
@foreach (MvcWidgetBuilder.Models.IWidget wm in ViewBag.Widgets)
{
@Html.Partial(string.Concat(new[] { "Widget", "/", "_Widget" }), wm)
}
所以我们有三个部分视图。 现在我们将引入一个公告板的视图。
- NoticeBoard.cshtml(路径:View/NoticeBoard/)
- 它调用了 widgetcontainer
@{
ViewBag.Title = "Widget";
}
@Styles.Render("~/Style/Widget.css")
<h2>Widget</h2>
<p>
@{
@Html.Partial("Widget/_WidgetContainer");
}
</p>
并且 NoticeBoard
的控制器是 NoticeBoardController
。 控制器的代码是
public class NoticeBoardController : Controller
{
//
// GET: /Widget/
public ActionResult Index()
{
return View();
}
public ActionResult MyNoticeBoard()
{
ViewBag.Widgets = GetWidgetData();
return View();
}
当我调用 /NoticeBoard/MyNoticeBoard 时,它只通过调用以下函数来填充 ViewBag.Widgets
public List<IWidget> GetWidgetData()
{
var noticeboardWidget = new List<IWidget>
{
new NoticeBoard()
{
SortOrder = 1, ClassName = "high",
HeaderText = "Notice Board", FooterText = "" ,
SubWidget = new SubWidget { Topic = "Office Time",
Description = "Office time will be change next month" },
},
new NoticeBoard()
{
SortOrder = 4, ClassName = "medium",
HeaderText = "Notice Board", FooterText = "" ,
SubWidget = new SubWidget { Topic = "Salary",
Description = "Salary is dusburst plese check your account" },
},
new NoticeBoard()
{
SortOrder = 8, ClassName = "low",
HeaderText = "Notice Board", FooterText = "" ,
SubWidget = new SubWidget { Topic = "About Lunch",
Description = "We need the feed back from you about the luch" },
},
new NoticeBoard()
{
SortOrder = 2, ClassName = "high",
HeaderText = "Notice Board", FooterText = "" ,
SubWidget = new SubWidget { Topic = "Emergency Meeting",
Description = "All the managers please come to our meeting room by 11.30" },
},
new NoticeBoard()
{
SortOrder = 5, ClassName = "medium",
HeaderText = "Notice Board", FooterText = "" ,
SubWidget = new SubWidget { Topic = "Office Meetting",
Description = "Todays meeting is cancel" },
},
new NoticeBoard()
{
SortOrder = 7, ClassName = "low", HeaderText = "Notice Board", FooterText = "" ,
SubWidget = new SubWidget { Topic = "HoliDay Notice",
Description = "We shifted our holiday leave for 1 day" },
},
new NoticeBoard()
{
SortOrder = 3, ClassName = "high", HeaderText = "Notice Board", FooterText = "" ,
SubWidget = new SubWidget { Topic = "Vacancy",
Description = "We need a sound asp.net developer with C#" },
},
new NoticeBoard()
{
SortOrder = 6, ClassName = "medium", HeaderText = "Notice Board", FooterText = "" ,
SubWidget = new SubWidget { Topic = "HR Notice",
Description = "Visiting cards proof send to you mail please check" },
},
};
return noticeboardWidget;
}
在浏览器中,您将看到以下屏幕
但是,如果您只是更改排序顺序的返回,它就会重新排列。
return noticeboardWidget.OrderBy(p=>p.SortOrder).ToList()
关注点
在这里,我的关注点不是向您展示 CSS 或带有部分视图的 MVC Razor。 我只是尝试关注动态 Widgets 设计。 由于我们也可以传递类名,我们可以通过模型控制 CSS 或视图。 我们的 widget 视图(部分视图)不依赖于模型(公告板),而是依赖于抽象 (IWidget
)。 因此,如果我们的公司想要对模型进行分类,例如 HRNotice、SalesNotice、EmployeeNotice,我们可以通过实现 IWidget
轻松地做到这一点。 那些初学者可以很容易地感受到接口的重要性,因为我很多次看到人们甚至无法回答一个简单的问题“为什么我们需要接口?” 我希望他们从这篇文章中找到基本的答案。
另一点可能出现在您的脑海中:如果我想构建一个与 _Widget
和 _SubWidget
不同的 widget 怎么办? 我们的 IWidget
支持吗?
答案:不支持,但是如果我们要使其更具动态性,我们可以通过传递视图名称来轻松实现。
public interface ISubWidget
{
string Topic { get; set; }
string Description { get; set; }
string WidgetName { get; set; } <---------------
}
public interface IWidget
{
int SortOrder { get; set; }
string ClassName { get; set; }
string FooterText { get; set; }
string HeaderText { get; set; }
string WidgetName { get; set; } <-------
ISubWidget SubWidget { get; set; }
}
更改我们的视图以及在 _WidgetContainer
上加载动态视图。
@model MvcWidgetBuilder.Models.IWidget
@foreach (MvcWidgetBuilder.Models.IWidget wm in ViewBag.Widgets)
{
@Html.Partial(string.Concat(new[] { "Widget", "/", wm.WidgetName }), wm)
}
以下代码用于我们的动态 widget:
@model MvcWidgetBuilder.Models.IWidget
<div class="widget">
<div class="@Model.ClassName">
<div class="header">
@Model.HeaderText
</div>
<div class="body">
@Html.Partial(string.Concat(new[] { "Widget", "/",
@Model.SubWidget.WidgetName }), @Model.SubWidget)
</div>
<div class="footer">
@Model.FooterText
</div>
</div>
</div>
您是否注意到我们设计结构的简单变化使我们的模型更具动态性。 这只有在我的模块依赖于抽象而不是具体类型时才有可能。