导读:
代码可以在https://files.cnblogs.com/bighuiwolf/Chinasoft.rar下载。
第一篇:http://www.cnblogs.com/bighuiwolf/archive/2010/07/10/1774871.html
第二篇:http://www.cnblogs.com/bighuiwolf/archive/2010/07/10/1774920.html
第三篇:http://www.cnblogs.com/bighuiwolf/archive/2010/07/10/1774955.html
本篇为第一篇
前几天发了一篇asp.net mvc下连动下拉框的文章,今天开始一步步分析其代码。
---------------------------
补 整体思路:
我有一个理念,就是程序员应该尽量用代码来说话,不要光用嘴说话,这样才能言之有物,很多时候,一行代码可以胜过千言万语。
本系列文的写作方式也是贴全部核心代码,再加解释说明。
本系列分三篇,本文是第一篇,介绍级连下拉框所需要的基础数据的定义。第二篇介绍Form需要的数据定义。第三篇介绍例子代码。
整体的介绍顺序是自底向上先局部后全局的,如果有人喜欢自顶向下的研究,可以从第三篇最后一行倒着向上看,完全没有问题。
---------------------------
1. Model:
现在流行模型驱动设计,所以我从这里开始。假设要做一个国家、城市、区(县)、街道,这样的四级下拉框。作为一个Demo,我用XML文件作为我的数据存储方式。Demo的目标是建立一个页面,上面有国家、城市、区(县)、街道四个下拉框和一个代表其它信息的Other Infomation。其中的级联下拉框有相当一部分是可重复使用的通用代码,读懂程序的人都应该可以明白哪些是需要在项目中根据需要重写的吧。
废话不多说了,下面是顶级下拉框的基类,可以把顶级下拉框的共有的部分放进去(本例中它是国家类的基类):
2 {
3 public SelectList GetSelectList()
4 {
5 return GetSelectList(null);
6 }
7
8 public SelectList GetSelectList(int? selectedValue)
9 {
10 return GetSelectList(selectedValue, true);
11 }
12
13 public SelectList GetSelectList(int? selectedValue, bool AddEmpty)
14 {
15 string file = HttpContext.Current.Server.MapPath(DataFile);
16 var values = from c in XElement.Load(file).Elements(RootElement)
17 select new KeyValuePair<string, string>(c.Attribute("id").Value, c.Attribute("name").Value);
18
19 var list = values.ToList();
20 if (AddEmpty)
21 {
22 RepositoryHelper.AddEmpty(list);
23 }
24 return RepositoryHelper.GetSelectList(list, selectedValue);
25 }
26
27 public abstract string DataFile { get; }
28 public abstract string RootElement { get; }
29 }
下面是国家类:
2 public class Countries : SelectListProviderBase
3 {
4 public override string DataFile
5 {
6 get
7 {
8 return "~/App_Data/countries.xml";
9 }
10 }
11
12 public override string RootElement
13 {
14 get
15 {
16 return "country";
17 }
18 }
19 }
我们经常会遇到根据父ID获取子下拉框数据的需求,下面是我定义的一个接口,它可以作为所有有父级的下拉框的数据源接口:
2 public interface IHasParent
3 {
4 SelectList GetSelectListByParentId(int parentId);
5 SelectList GetSelectListByParentId(int parentId, int? selectedValue);
6 SelectList GetSelectListByParentId(int parentId, int? selectedValue, bool AddEmpty);
7 }
城市、区(县)、街道都要实现这个接口。我只要设计一个基类,实现该接口,然后基类的各子类指出每个类所用的XML文件和根元素即可:
2 public abstract class HasParentBase : IHasParent
3 {
4 #region IHasParent Members
5
6 public virtual SelectList GetSelectListByParentId(int parentId)
7 {
8 return GetSelectListByParentId(parentId, null);
9 }
10
11 public virtual SelectList GetSelectListByParentId(int parentId, int? selectedValue)
12 {
13 return GetSelectListByParentId(parentId, selectedValue, true);
14 }
15
16 public virtual SelectList GetSelectListByParentId(int parentId, int? selectedValue, bool AddEmpty)
17 {
18 var values = GetData(parentId);
19 var list = values.ToList();
20 if (AddEmpty)
21 {
22 RepositoryHelper.AddEmpty(list);
23 }
24 return RepositoryHelper.GetSelectList(list, selectedValue);
25 }
26
27 #endregion
28
29 public abstract string DataFile { get; }
30 public abstract string RootElement { get; }
31
32 public IEnumerable<KeyValuePair<string, string>> GetData(int parentId)
33 {
34 string file = HttpContext.Current.Server.MapPath(DataFile);
35 var values =
36 from c in XElement.Load(file).Elements(RootElement)
37 where c.Attribute("parentId").Value == parentId.ToString()
38 select new KeyValuePair<string, string>(c.Attribute("id").Value, c.Attribute("name").Value);
39 return values;
40 }
41 }
拿Cities来说(Suburbs和Streets都一样,都继承HasParentBase):
2 public class Cities : HasParentBase
3 {
4 public override string DataFile
5 {
6 get
7 {
8 return "~/App_Data/cities.xml";
9 }
10 }
11
12 public override string RootElement
13 {
14 get
15 {
16 return "city";
17 }
18 }
19 }
至此,所有基础数据都定义完了,下一节介绍页面中用到的数据,即FormModel们。
大家有什么不满,尽可扔鸡蛋,砖头的不要。
PS:国家数据XML:
2 <countries>
3 <country id="0" name="USA"/>
4 <country id="1" name="Britain"/>
5 </countries>
城市的数据(Suburbs和Streets与Cities类似,就不重复了):
2 <cities>
3 <city parentId="0" id="0" name="New York"/>
4 <city parentId="0" id="1" name="Washington"/>
5 <city parentId="1" id="2" name="London"/>
6 </cities>