日期:2014-05-17  浏览次数:21416 次

火星人代码示例:系统设置(asp.net MVC3中View的复用示例)

功能简介

最终功能如图:


上面一行两张图,是火星人的用户故事树配置界面,在每个用户故事的后面都有一个按钮(悬停可见),点击后出现操作菜单,其中一部分是新建下级故事菜单。

若用户选择左侧,菜单上只包括一个项目“通用故事”;若选择右侧,则包括很多故事(受当前故事类型的约束,这个比较复杂以后再说)。

这段代码,等一下将会出现关键字“StoryTreeType”,左侧叫做“Simple”(简单树),右侧叫做“Leveled”(等级树)。

下面一行两张图,是火星人的状态链配置界面,在上面提到的操作菜单上,除了能新建故事之外,还能将当前故事转移到另外一个状态。

若用户选择左侧,菜单上只包括与开发相关的状态(新建-待开发-开发中-开发完毕-部署完毕);做选择右侧,则会出现所有状态(新建后有审批等环节,而部署过程也包括多个状态)。

这段代码,等一下将会出现关键字“StatusList”,左侧叫做“DevelopmentOnly”(仅包含研发状态),右侧叫做“All”(所有)。


很显然,不只是这两排界面很类似,这四个界面和背后的模型都非常相近,下面谈谈如何以最小代码实现这个配置功能。


开发过程

Controller部分的代码略过,重点看Model和View的封装。

第一步:开发出StoryTreeType部分的Model代码


    public partial class Product
    {
        public const string UserDefaultProductIDKey = "DefaultProductID";

        //StoryTree type (Simple, Leveled, etc.)
        public const string StoryTreeTypeKey = "StoryTreeType";
        public enum StoryTreeTypes
        {
            Simple = 0,
            Leveled = 1
        }

        public static readonly StoryTreeTypes[] StoryTreeTypeValues = { StoryTreeTypes.Simple, StoryTreeTypes.Leveled };
        public static readonly string[] StoryTreeTypeTexts = { "缺省(使用简单父子关系形成故事树)", "使用系统定义的故事等级形成故事树" };

        public StoryTreeTypes StoryTreeType
        {
            get { return (StoryTreeTypes)Config.ReadValueAsInt(StoryTreeTypeKey, "$" + ID); }
        }

        public string StoryTreeTypeText
        {
            get { return StoryTreeTypeTexts[Config.ReadValueAsInt(StoryTreeTypeKey)]; }
        }
    }
注意这段代码里边有一个叫做Config的类,它负责把不同的配置写到数据库中的一个公共表里边,因此为了完成这个功能,我们并不需要讨论数据存储问题。

这得益于火星人之前已经封装好的众多功能。

第二步:实现StoryTreeType的View

注意下面的代码,已经将StroyTreeType的两种类型进行了Foreach循环处理,而不是写死在里边。

有时候会觉得只有两种,还做什么循环,但如果不循环就需要两段很接近的代码,调试和维护都很费劲。而且一旦养成这种习惯,很容易把整个软件都写散了。


@foreach (var type in Product.StoryTreeTypeValues)
{
    <td style = "border: none; ">
        <div class = "help-sample">
            <table>
                <tr>
                    <td style = "border: none; width: 500px; ">
                        @MFCUI.Image("", "/Products/StoryTree/Index16.png") <b>@Product.StoryTreeTypeTexts[(int)type]     </b>
                        @if (Model.StoryTreeType == type)
                        {
                            <b>[当前设置]</b>
                        }
                        else
                        {
                            @MFCUI.Link("[启用]", "/MFC/Configs/AjaxSet?key=" + Product.StoryTreeTypeKey + "&value=" + (int)type + "&user=$" + Model.ID, returnTo: this)
                            @:        
                        }
                        <table>
                            <tr>
                                <td style = "border: none; width: 200px; ">
                                    @RenderPage("~/Areas/DLC/Views/Products/ManagementMethod/StoryTreeTypes/_" + Model.StoryTreeType + ".cshtml")
                                </td>
                                <td style = "border: none; ">
                                    @MFCUI.Image("", "/Products/Products/ManagementMethods/_" + type + "Example.png") <br/><br/>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
        </div>
    </td>
}
注意

1. 这段代码里边