ASP MVC 2用于实现CanExecute样式命令的模式

时间:2011-08-08 10:10:04

标签: asp.net-mvc-2

我来自WPF(MVVM)背景并试图转向MVC 2.在MVC2中是否有任何模式,您可以使用命令/命令按钮,如<input>,您可以使用它来提交表单,以便您您尝试渲染视图时可以隐藏/禁用。

在MVVM世界中,您的命令可以实现ICommand接口,并且它具有非常有用的CanExecute方法。我想知道ASP MVC 2中是否有类似内容?

我能想到的唯一方法是在View中执行此操作,以便我可以检查ViewModel(CanSave)上的标志,并根据该显示/隐藏<input>标记。

基本上我想要运行2个版本的网站,一个处于只读模式,另一个处于编辑模式。

如果您需要任何澄清,请与我们联系。

4 个答案:

答案 0 :(得分:2)

ASP.NET MVC没有“控件”的概念,如经典ASP.NET和WPF中所见。 ASP.NET MVC的基础块是HTML元素,如<input><button>等。当然,这些并不提供您正在寻找的功能(即ICommand接口的实现)。

您正在查看的场景(即表单的两种模式)可以(并且可以说应该)在View级别处理。您已经面向正确的方向:在您的模型上有一个'CanSave'属性,并在视图中使用它来确定生成的内容。

示例:

<% if (Model.CanSave)
    { %>
        <p>First Name: <%= Html.TextBox("firstname", Model.firstname) %> </p>
<%  }
    else
    { %>
        <p>First Name: <%=Model.firstname %></p>
<%  } %>

您可能希望查看 DisplayTemplates EditorTemplates ...对于此方案非常方便。布拉德威尔逊做得很好here

它将帮助您实现这一目标:

<%= (Model.CanSave) ? Html.EditorFor(x => x.firstname) : Html.DisplayFor(x => x.firstname) %>

...这使您的视图干净整洁。

答案 1 :(得分:1)

如果你不能让MVC这样做,那么手动编写类似这个vb风格伪代码的东西是相对值得的。这涉及......

对控件进行子类化。

不像听起来那么痛苦,但是,它是一个中等大小的。因此,它仅适用于中型到大型应用程序。但值得为他们服务。

Interface BaseUIControl
    Property Enabled as Boolean
    Property Visible as Boolean
    Property Name as String
    Property EntireStateAsXML as string ' You can use this to do EVERYTHING!        

Interface UserActionItem
    Event Clicked(sender as UserActionItem ... don't pass anything from UI namespaces!)

Class MyButton (or link, etc.) Implement BaseUIControl, UserActionItem Inherits UI.Button

这有什么用?你基本上已经取代了缺失的功能。您的Controller(甚至应用程序层)只能通过接口了解UI组件,因此他们不必查看UI类型。

更多...

您可以利用这一理念来控制所有内容。这为我节省了数千小时的猴子代码。

Interface TextControl
    Property Value as text

Interface CheckControl 
    Property Checked as boolean 

上面两个是非常基本的 - 你从UI版本继承了MyCheckBox和MyTextBox并实现了相应的。

当然,您可以设置公共代码来循环所有控件并自动验证(或循环并获取每个XML以自动查看整个表单)。

Interface ValidationBase
    Property Required as Boolean

如果您有一个文本或仅限数字的掩码或内置于2个子类的限制......

Interface ValidationNumeric           
    Property MinVal, MaxVal as double 

Interface ValidationText
    Property MinLen, MaxLen as double 

不,它不会为你找到数据库。但这在地毯下扫了一大堆。

您甚至可以在UI设计器中设置这些属性值 - 是的,将BL放在UI中,但是,如果您只有一个用于BL的UI,实际上效果非常好。

现在使用混合列表框/多选,双列表选择器控件,选中列表框,选项按钮组/复选框等组合图像...

Interface Selector
    property Items as list (of string) 
    property SelectedItems as list (of string)

使用适用于UI的功能 - 您的通用例程可以更少关注它们的样子!子类UI部件将实现它们以设置/获取正确的值。

另外......我们添加了'validationEquation',ActivatesEquation(gray / ungray),SetValueTriggerEquation(如果为true,则将值设置为SetValueEquation,否则,保持不变),这允许将控件设置为来自其他项的简单值(通过Pascal Gayane的Expression Evaluator(它读取.net类型!)

基本上从绑定对象中获取值,就像使用反射一样

你也可以对主窗体进行子类化,让它通过它的所有子控件进行递归,将整个屏幕的XML放在一起,并像这样序列化它。您可以让自己的类在非UI层中实现这些,并使用它来完全(de /)序列化UI状态,并使用它们来读取UI,如果它们与业务对象相关,则映射到它。

令人难以置信这简化了复杂的应用程序。我们有一个拥有1200多个数据输入面板(...页面...我们的是一个厚客户端应用程序),将在250K LOC填写250种不同的纸质表格。表单定义包含每个控件的“名称”,这是从屏幕生成的XML中提取的。我们可能节省了500K LOC,因为许多屏幕背后都没有代码或者只有简单的代码;所有数据绑定,验证等都由引用接口的常用例程处理。

就像我说的,这只适用于大型应用。至少花2-3周时间开发90%的功能;在整个2年中可能还需要一个月的时间。我猜你的应用程序很大,如果你关心ICommand及其便利。我会把回报放在15-20个中等复杂的页面上。

答案 2 :(得分:1)

如果我正确理解了这个问题,你可以编写一个ControllerCommand类来封装它。像这样:

public class ControllerCommand
{
    public string Action { get; set; }
    public string Controller { get; set; }
    public object RouteValues { get; set; }
    public bool IsEnabled { get; set; }
}

您的详细信息视图模型可能会像这样使用它:

public class DetailsModel
{
    public guid Id { get; set;}
    // some other viewmodel properties
    public ControllerCommand Edit { get; set; }
}

您可以在HtmlHelper上编写扩展方法来替换内置的方法:

public MvcHtmlString CommandLink(this HtmlHelper html, string linkText, ControllerCommand command, object htmlAttributes)
{
    if (command.IsEnabled)
    {
        return html.ActionLink(linkText, command.Action, command.Controller, command.RouteValues, htmlAttributes);
    }
    else
    {
        return MvcHtmlString.Create(linkText);
        // perhaps return <span class="disabled-command">linkText</span>
    }
}

答案 3 :(得分:0)

我找到的方法之一是使用可以放在Actions中的Filter属性,但只能在服务器端处理CanExecute。

对于GUI方面,找不到比使用If语句检查用户是否有权运行特定操作(即编辑/删除按钮)更好的方法