经验技巧

 

<html>
<body>
<a href='aa' stytle='cursor:hand'>ADFADF</a>
</body>
</html>


/// <summary>
  /// 替换字符串中所有的html标签
  /// </summary>
  /// <param name="str">原始字符串</param>
  /// <param name="l">长度</param>
  /// <returns></returns>
  public static string CutReplaceStr(string str,int l)
  {
   Regex re = new Regex(@"<[^>]+>", RegexOptions.IgnoreCase);
   str=re.Replace(str,"");
   if(str.Length>=l)
    str=str.Substring(0,l)+"...";
   return str;
  }

 


String.prototype.Trim = function()
        {
     return this.replace(/(^\s*)|(\s*$)/g, "");
        }


 var objButton=document.getElementById("<%=btnSubmit.ClientID%>");
   focus(objButton);
   objButton.click();
大问题

 


//ispostback

第一次打开页面:IsPostBack()的值为false;
回传到服务器则IsPostBack()变为true;
!是取反,一般
if(!IsPostBack)
{
//代表第一次读页面
}
else
{
//回传以后的代码
}

在不回发服务器端的话 IsPostBack()是fasle
比如刷新,浏览等

在有按钮 或者页面以 http 的 Post 命令方式请求
 IsPostBack()是fasle


打开你的asp.net页面的客户端源代码,你会看到一个
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" .... />
字段,这个就是 IsPostback 函数的来源。

当,并且参数中包含这个 __VIEWSTATE 的时候,页面的 IsPostback == true。

不论回发还是回调(asp.net2.0下的内置的Ajax处理)都是IsPostback == true。后者的情况下,回调和回发的区别,可以进一步通过页面的 IsCallback 函数来区分。

 

//WEB页面生成周期:

客户端向服务端请求一个新的aspx页面:
        1、 服务器端会创建一个控件树,再创建页面上的所有控件,把控件加到控件树中。
        2、 TrackViewState状态跟踪,检查控件的EnableViewState属性,对EnableViewState=ture的控件进行跟踪。
        3、 触发页面OnLoad。
        4、 预生成OnPreRender。
        5、 检查控件的EnableViewState属性,对需要保存状态的调用SaveViewState[状态1]。
        6、 Render生成。
        7、 … …

        从客户端回传一个aspx页面,页面被Post回服务端后。
        A、 和上述1一样。
        B、 和上述2一样。
        C、 LoadViewState,加载控件提交前的状态[就是加载状态1]。
        D、 LoadPostdata,从Post回来的表单中取出相应的数据,并把这些数据更新控件的状态[状态2]。
        E、 和上述3一样。
        F、 触发修改事件和回传事件。
        G、 和上述4一样。
        H、 保存状态SaveViewState[状态2]。
        I、 Render。
        J、 … …

HTML控件编辑为web控件必须包含在一个Form表单里,进行传送。


Request 提交服务器信息
Respinse 服务器返回信息

string username=Request["txtUserName"].ToString();
string password=Request["txtPwd"].ToString();
string username=Request.Form.Get("txtUserName").ToString();
string password=Request.Form.Get("txtPwd").ToString();
string username=Request.QueryString["txtUserName"].ToString();
string password=Request.QueryString["txtPwd"].ToString();
Response.Write("登陆的名字为"+username+"登陆的密码为"+password);

IsPostBack  第一次为 FALSE  第二次为 TRUE

ASPX FORM METHON为提交给自己
HTM 新建FORM METHON 要定义

再就是 POST 和 get方法的区别

_VIEWSTATE控件 是隐藏控件  在表单提交到服务器 此控件自动添加到表单中
保存表单信息

 

“需要被PostBack”的意思是,这个数据的生命周期需要跨越PostBack的。  
   
  上面说清楚了,页面每一次请求都重新实例化,所有参数的值都是默认值,这个和ASP无异。只不过在ASP.NET中,系统会自动分析这个请求,是不是PostBack请求。如果不是PostBack请求,那么就是你第一次请求页面所看到的“全新”页面;如果是PostBack,系统就会从Post的数据中自动进行自动分离处理,例如属于ViewState的就初始化并放到ViewState中,如果PostBack的数据表明这是一个“事件”,那么就触发该事件的逻辑。  
   
  简单点说:  
  1.页面确确实实每一次都重新实例化所有对象,所有值都是默认值,在这里ASP与ASP.NET一样。  
  2.系统会对Post的信息进行分析提取,并把它们放到适合的对象里,这是ASP.NET特有的。

//点击按钮事件

var objButton=document.getElementById('btnSubmit');
      focus(objButton);
      objButton.click();


style="CURSOR:HAND"

http://hi.baidu.com/cc_yu_xin/blog/item/8cc0da3fa4e1ebc07d1e71db.html


//DataGraid绑定时,想显示一列编号按照顺序为1,2,3,4,5....,


Container.ItemIndex就是行号索引值,自0开始,所以引用时一般如下:
<%#Container.ItemIndex+1 %>

或者

后台
dataSet.Tables[0].Columns.Add("col");
   for (int i=0;i<dataSet.Tables[0].Rows.Count;i++)
   {
    dataSet.Tables[0].Rows[i]["col"]=(i+1).ToString();
   
   }
前台

<asp:TemplateColumn HeaderText="序号">
<HeaderStyle Wrap="False" Width="5%"></HeaderStyle>
<ItemTemplate>
<%# DataBinder.Eval(Container, "DataItem.col") %>
</ItemTemplate>
</asp:TemplateColumn>


//C#的Datagrid中如何只允许输入数字

模板列这么写,加一个onblur事件。
<EditItemTemplate>
<asp:TextBox ID="TextBox2" name="TextBox2"runat="server" Text='<%# Bind("id") %>' οnblur="zzint(this);"></asp:TextBox>
</EditItemTemplate>
javascript事件。

<script type="text/javascript" >
function zzint(obj)
{
if(obj.value.search(/^[0-9]+$/)==-1)
{
alert("只能输入数字!\n");
obj.value="";
obj.focus();
obj.select();
}
}
</script>


HttpWorkerRequest

弹出alert框的网页成为空白,怎么解决?

Page.RegisterStartupScript("",   "<script   language=JavaScript>window.alert('登录成功');window.location='/website2007/service/index.aspx'</script>"); 

public void AlertMessage(string str)
  {
   string text = "<script language = 'javascript'>";
   text += "alert('";
   text += str + "')";
   text += "</script>";
   this.Page.RegisterStartupScript("alert", text);
  }
  public void  Alert(string   messageString)  
  {  
   this.RegisterStartupScript("Alert"+Guid.NewGuid().ToString(),"<SCRIPT   language=javascript>alert('"+@messageString.Replace("'","\\'").Replace("\r\n","\\n'+\r\n'")+"')</SCRIPT>");  
  }

//sql server 用sql语句获取当前月份天数,
select  DATEDIFF(dd,getdate(),dateadd(mm,1,getdate()))
dd 代表day;
getdate()当前时间;
dateadd(mm,1,getdate())在当前时间上加一个月

即 在当前时间上加一个月的天数 -当前月份天数 得到当月的总天数

解释    DATEDIFF ( datepart , startdate , enddate )
        DATEADD ( datepart , number, date )


datepart :是规定了应在日期的哪一部分计算差额的参数。下表列出了 Microsoft® SQL Server™ 识别
的日期部分和缩写。

日期部分 缩写
year yy, yyyy
quarter qq, q
Month mm, m
dayofyear dy, y
Day dd, d
Week wk, ww
Hour hh
minute mi, n
second ss, s
millisecond ms

 

C# 的属性 set 访问器是一个最佳执行业务逻辑判断的地方
// Model
public class UserEntity
{
// ...
public string UserName
{
get { return _UserName; }
set {
// 执行业务逻辑检查
if (value.Length > 20 || String.IsNullOrEmpty(value))
{
  throw new Exception("用户名不合法。");
}
_UserName = value;
}
// ...

}

 

<a href="AAA.aspx?wo_id=<%# DataBinder.Eval(Container, "DataItem.WO_PROJECTNAME") %>"></a>

 

//防止被过长的英文撑坏表格
在td上写
style="word-break: break-all;"

或者写个css
.break
{
word-break: break-all

}


//遍历文本框
TextBox txt = new TextBox();

 foreach (Control c in Page.Controls)
        {
            string t = null;
            for (int i = 0; i < c.Controls.Count; i++)
            {
               
                Control obj = c.Controls[i];
                if (obj.GetType().ToString() == "System.Web.UI.WebControls.TextBox")
                {
                    txt = (TextBox)obj;
                    txt.Attributes.Add("readonly","return false");
                }               
            }
        }


//js遍历文本框

function isHtml()
{

      var searchTextType = document.getElementsByTagName("input");
         var pattern  = /<+[^>]+/;
 
       for (var i=0; i<searchTextType.length; i++)
           {  
               if(searchTextType[i].type=="text")
              {
            if(pattern.exec(searchTextType[i].value))
              {
//         alert(searchTextType[i].id);
//         alert(searchTextType[i].value);
        
         var temp=document.getElementById(searchTextType[i].id);
        
         alert('有不合法字符,请重新输入');
         temp.value="";
         temp.focus();
        return false;
              }
             }
        }      
  
      return true;                 
}


//替换html

eg:
strContent=strContent.Replace("&","&amp");
strContent=strContent.Replace("'","''");
 
strContent=strContent.Replace("<","&lt");
strContent=strContent.Replace(">","&gt");
strContent=strContent.Replace("chr(60)","&lt");
strContent=strContent.Replace("chr(37)","&gt");
strContent=strContent.Replace("\"","&quot");
strContent=strContent.Replace(";",";");
strContent=strContent.Replace("\n","<br/>");
strContent=strContent.Replace(" ","&nbsp");
return strContent;


//asp.net 定时运行某程序

增加命名空间
using System.Timers;

protected void Application_Start(Object sender, EventArgs e)
  {
  System.Timers.Timer t=new System.Timers.Timer(1000);
  
   t.AutoReset=true;
   t.Enabled=true;
   t.Interval=1000;
//添加委托
   t.Elapsed +=new System.Timers.ElapsedEventHandler(fun);
  }


private void fun(object sender, System.Timers.ElapsedEventArgs e)
  {
   try
   {
    // 得到 hour minute second  如果等于某个值就开始执行某个程序。
    int intHour = e.SignalTime.Hour;
    int intMinute = e.SignalTime.Minute;
    int intSecond = e.SignalTime.Second;

  

    // 定制时间; 比如 在23:30 :00 的时候执行某个函数
    string  time=ConfigurationSettings.AppSettings["Time"];
    
    
    int iHour = int.Parse(time.Split(':')[0]);
    int iMinute =int.Parse( time.Split(':')[1]);
    int iSecond =int.Parse( time.Split(':')[2]);
    
    if (intHour==iHour && intMinute == iMinute && intSecond == iSecond)
    {
//运行你所需要的程序
     WebUI.Common.ProcessIsOverTime.Start();
    }
    
    
   

  
   }
   catch(Exception ex)
   {
    string s=ex.Message;
   }
  }

 

 

 

 

 

//判断起始时间和结束时间
 function TimeCompare(StartDateTime,EndDateTime)
 {
  var StartDateTime = StartDateTime.split("-")[0] +"-"+ (StartDateTime.split("-")[1].length == 1 ? "0"+ StartDateTime.split("-")[1] : StartDateTime.split("-")[1]) +"-"+ (StartDateTime.split("-")[2].length == 1 ? "0"+ StartDateTime.split("-")[2] : StartDateTime.split("-")[2]);
  var EndDateTime = EndDateTime.split("-")[0] +"-"+ (EndDateTime.split("-")[1].length == 1 ? "0"+ EndDateTime.split("-")[1] : EndDateTime.split("-")[1]) +"-"+ (EndDateTime.split("-")[2].length == 1 ? "0"+ EndDateTime.split("-")[2] : EndDateTime.split("-")[2]);
  if(StartDateTime>EndDateTime)
  {
   return false;
  }
  return true;
 }


//模板化的数据绑定控件为我们在页面上显示数据提供了根本的灵活性。你可能还记得ASP.NET v1.x中的几个模板化控件(例如DataList和Repeater控件)。ASP.NET 2.0仍然支持这些控件,但在模板中绑定数据的语法已经被简化和改善了。本文将讨论在数据绑定控件模板中绑定数据的多种方法。

  数据绑定表达式

  ASP.NET 2.0改善了模板中的数据绑定操作,把v1.x中的数据绑定语法DataBinder.Eval(Container.DataItem, fieldname)简化为Eval(fieldname)。Eval方法与DataBinder.Eval一样可以接受一个可选的格式化字符串参数。缩短的Eval语法与DataBinder.Eval的不同点在于,Eval会根据最近的容器对象(例如DataListItem)的DataItem属性来自动地解析字段,而DataBinder.Eval需要使用参数来指定容器。由于这个原因,Eval只能在数据绑定控件的模板中使用,而不能用于Page(页面)层。当然,ASP.NET 2.0页面中仍然支持DataBinder.Eval,你可以在不支持简化的Eval语法的环境中使用它。

  下面的例子演示了如何使用新的简化的Eval数据绑定语法绑定到DataList数据项模板(ItemTemplate)中的Image、Label和HyperLink控件。

<asp:DataList ID="DataList1" RepeatColumns="5" Width="600" runat="server" DataSourceID="ObjectDataSource1">
 <ItemTemplate>
  <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl=''<%# Eval("PhotoID", "PhotoFormViewPlain.aspx?ID={0}") %>''>
  <asp:Image ID="Image1" Runat="server" ImageUrl=''<%# Eval("FileName", "images/thumbs/{0}") %>'' /></asp:HyperLink>
  <asp:Label ID="CaptionLabel" runat="server" Text=''<%# Eval("Caption") %>'' />
 </ItemTemplate>
</asp:DataList><br />
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" TypeName="DataComponentTableAdapters.PhotosTableAdapter" SelectMethod="GetPhotosForAlbum">

 


一、DataBinder.Eval的基本格式
<%#   DataBinder.Eval(Container,   "DataItem.isgood").ToString()=="0"   ?   "是"   :"否"   %>
在绑定数据时经常会用到这个句程序:<%# DataBinder.Eval(Container.DataItem,"xxxx")%>或者<%# DataBinder.Eval(Container,"DataItem.xxxx")%>
今天又学到一种,而且微软也说这种方法的效率要比以上两种高。
<%# ((DataRowView)Container.DataItem)["xxxx"]%>
很有用的,这样可以在前台页面做好多事情了。
还要记住要这样用必须要在前台页面导入名称空间System.Data,否则会生成错误信息。
<%@ Import namespace="System.Data" %>
这种用法其实和<%# ((DictionaryEntry)Container.DataItem).Key%>是一个道理。
Text='<%# DataBinder.Eval(Container.DataItem, "字段") %>'
这样的方法是最快的
Text='<%# GetPrice() %>'
也可以绑定方法,但方法要是public的
Text='<%# "CarDetails.aspx?CarID=" + DataBinder.Eval(Container.DataItem, "CarID") %>'
还可以连接多个字段
关键是Container这个东西,它比较神秘。它的名称空间是System.ComponentModel。对于它我还需要进一步理解。
二、DataBinder.Eval实现判断选择
<asp:TemplateColumn HeaderText="性别">
<ItemTemplate>
<%# DGFormatSex(Convert.ToString(DataBinder.Eval(Container.DataItem,"xb"))) %>
</ItemTemplate>
</asp:TemplateColumn>
cs里定义DGFormatSex方法
protected string DGFormatSex(string xb)
{
if(xb == "1")
return "男";
else
return "女";
}

 

//DataBinder.Eval用法范例

//显示二位小数
//<%# DataBinder.Eval(Container.DataItem, "UnitPrice", "${0:F2}") %>
//{0:G}代表显示True或False
//<ItemTemplate>
// <asp:Image Width="12" Height="12" Border="0" runat="server"
// AlternateText='<%# DataBinder.Eval(Container.DataItem, "Discontinued", "{0:G}") %>'
// ImageUrl='<%# DataBinder.Eval(Container.DataItem, "Discontinued", "~/images/{0:G}.gif") %>' />
// </ItemTemplate>
//转换类型
((string)DataBinder.Eval(Container, "DataItem.P_SHIP_TIME_SBM8")).Substring(4,4)
{0:d} 日期只显示年月日
{0:yyyy-mm-dd} 按格式显示年月日
{0:c} 货币样式

 

//不用ajax.listbox的互相移动判断重复项
function SelectOneRight()

 


 {    
    var obj = window.document.getElementById("ctl00$main$LbxO2");
 var containerObj = window.document.getElementById("ctl00$main$LbxSel");
 if (obj.selectedIndex<0)
 {
  return false;
 }

 for (var i=0;i<containerObj.length;i++)
 {
  if (containerObj.options[i].value==obj.options[obj.selectedIndex].value)
  
   return false;
 }
 var i_op=document.createElement("OPTION");
 i_op.text=obj.options[obj.selectedIndex].text;
 i_op.value=obj.options[obj.selectedIndex].value;
 containerObj.add(i_op);    
     }    
       //删除选中项   
function DelOne()


    {
          
          var obj = window.document.getElementById("ctl00$main$LbxSel");
    var index = obj.selectedIndex;
    if (index<0)
    {
  return false;
   }
   else
   {
  obj.remove(index);
   }
               
     }

//iframe打开新页面;

<asp:LinkButton ID="LinkButton1" runat="server"  OnClientClick="top.location.href='../login.aspx' "  >重新登录</asp:LinkButton>


//将截断字符串或二进制数据。语句已终止的问题

1可能是数据库字段长度不对
2 在页面假如 ValidateRequest="false"

 

//点击按钮插入一条数据后,按f5刷新页面,又会插入一条数据.....
Response.Write("<script>location.reload();</script>");

//onmouseover滑过改变td颜色

function change(obj)
{

switch (obj)
 {
 case "bszn":
 bszn.bgColor="#17C3C3";
 bgxz.bgColor="#CCCCCC";
 ques.bgColor="#CCCCCC";
 
 break;
 case "bgxz":
 bszn.bgColor="#CCCCCC";
 bgxz.bgColor="#17C3C3";
 ques.bgColor="#CCCCCC";
 break;
 case "ques":
 bszn.bgColor="#CCCCCC";
 bgxz.bgColor="#CCCCCC";
 ques.bgColor="#17C3C3";
 break;
 }
 }

   <td id=bszn width="13%" height="25" bgcolor="#17C3C3" class="bk1"><div align="center" class="font_5"><a   href="detail1.aspx?id=<%=Request.QueryString["id"]%>"    οnmοuseοver=change("bszn"); target="frmContent">办事指南</a></div></td>
                <td id=bgxz width="14%" height="25" bgcolor="#CCCCCC" class="bk1" ><div align="center"><a href="detail2.aspx?id=<%=Request.QueryString["id"]%>" target="frmContent" οnmοuseοver=change("bgxz");>表格下载</a></div></td>
                <td id=ques width="22%" height="25" bgcolor="#CCCCCC" class="bk1"><div align="center"><a href="zxtsFrame.aspx?id=<%=Request.QueryString["id"]%>" target="frmContent" οnmοuseοver=change("ques")>常见问题与咨询</a></div></td>


//返回前一页并刷新前一页
οnclick="history.back(1);location.reload();"

application/octet-stream


//下载页面链接
<a href="downLoad.aspx?ID=<%# DataBinder.Eval(Container,"DataItem.ID")%>" ><img src="images/wsbs_download.gif" width="18" border="0" title="下载该文件"></a>


//附件下载保存downLoad.aspx文件

private void ProcessRequest()
  {
      
        EventAttchBo attchBO = Beyondbit.Web.Platform.NetEvent.Common.
    BOProxyFactory.CreateBoProxy<EventAttchBo>();  //声明BO
        int id = int.Parse(Request.QueryString["ID"]); //得到url传过来的id

        IList<EventATTACH> listAttchOnlyOne = attchBO.getAttchbyID(id); //根据id得到一条对应的数据集

        EventATTACH att = new EventATTACH();       //实体类对象
        att.CONTENT = listAttchOnlyOne[0].CONTENT;
        att.FILENAME = listAttchOnlyOne[0].FILENAME;

        //context.Response.Clear();


      Response.ContentType = "application/octet-stream"; //必须写说明内容的类型


       

      //  string fileName = Request.QueryString["FileName"];
       // fileName=  EventPublicMethod.getStr(fileName,12);

       // HttpUtility.UrlEncode(System.Text.Encoding.UTF8.GetBytes(fileName));


        //下载文件名限制32字符 16 汉字
      //  int maxlength = 15;
      //;
      //  if (fileName.Length > maxlength)
      //  {
      //      fileName = "-" + fileName.Substring(fileName.Length - maxlength, maxlength);

      //  }
    
      att.FILENAME = HttpUtility.UrlEncode(att.FILENAME, System.Text.Encoding.UTF8); //必须编码,不然文件名会出现乱码

 

      Response.AppendHeader("Content-Disposition", "attachment;filename=\"" + att.FILENAME + "\"");
     

    

 

        if (att.CONTENT != null && att.CONTENT.Length > 0)
         Response.BinaryWrite(att.CONTENT);

        Response.End();

    }

 

 

 

 

 


//HyperLink链接
<!--<asp:HyperLink id="HyperLink1" runat="server" Text='<%# EventPublicMethod.getleft(Eval("NAME").ToString(),15) %>' ></asp:HyperLink> -->

//关于ValidateRequest="false"的帖子
http://blog.csdn.net/DanceFire/archive/2007/04/11/1560171.aspx


//链接传中文例子

 <a href='list.aspx?depid=<%#Eval("code") %>&&type=<%# Server.UrlEncode(Eval("NAME").ToString())%>' target="_blank"><%# Eval("Name")%></a></td>


//datagrid 控制字符串长度

<!--<asp:HyperLink id="HyperLink1" runat="server" Text='<%#   EventPublicMethod.getleft(Eval("NAME").ToString(),5)   %>' > </asp:HyperLink>-->
<%#   EventPublicMethod.getleft(Eval("NAME").ToString(),15)   %>

 public static string getleft(string scatitle, int cid)     //从左截取串   scatitle   的   cid个字符  
        {
            string rtn = "";
            if (scatitle.Trim().Length > cid)
            {
                rtn = scatitle.Substring(0, cid) + "...";
            }
            else
            {
                rtn = scatitle;
            }
            return rtn;
        }  


//如何取得select下拉列表框控件的值
var ddl = document.getElementById("SelectID");
    var index = ddl.selectedIndex;
    var value = ddl.options[index].value;
    var text = ddl.options[index].text;

to:   jacky125()    
  那怎样把获取下拉框的值在前台放进文本框呢????  
  大家帮忙想一想  
  -----------------------------------------  
  var   province=document.getElementById("DropDownList1");  
  var   pindex   =   province.selectedIndex;  
  var   pValue   =   province.options[pindex].value;  
  var   pText     =   province.options[pindex].text;  
   
  document.getElementById("<%=TextBox1.ClientID%>").innerText=pValue+"|"+pText;  


//判断是否是框架或者是页面

  <script language="javascript"  type="text/javascript">  
//    var obj = document.getElementById("btnClose");
//    if (this.name == "FrameBodyRight")
//    {     
//          obj.onclick =historyBack;         
//     
//    } 
//
//    function historyBack()
//    {
//        window.history.back(-1);
//    }
     </script>


//隐藏层动态显示

<html>
<head>
 <script language=javascript>
  function Div1_Display(sign)
  {
   if (sign==1)
   {
    document.all("Div1").style.display="none";
    document.all("Div2").style.display="inline";
   }
   else
   {
    document.all("Div2").style.display="none";
    document.all("Div1").style.display="inline";
   }
  }
 </script>
</head>
<body>
 <table>
  <tr>
   <td>
    <input type=button value="Div1" οnclick="Div1_Display(1)" ID="Button1" NAME="Button1">
    <input type=button value="Div2" οnclick="Div1_Display(2)" ID="Button2" NAME="Button2">
   </td>
  </tr>
 </table>
 <div id=Div1>
  aaaaaaaaaaaaaaaaaaa
 </div>
 <div id="Div2" style="display:none">
  bbbbbbbbbbbbbbbbbbbbb
 </div>
</body>
</html>


//在服务器端得到客户端控件的值一定要设置name属性
   string temp = Request.Params["Text4"].ToString();
 


//ajax返回Dataset 绑定html 下拉列表控件
前台
<script language="javascript" for="window" event="onload">
<!--
document.all.ProceedingSearch1_rbDel.checked=true;
 click_rb_Dept();
-->
</script>

<script language="javascript" type="text/javascript">
 function click_rb_Dept(){ 
  ajaxMethod.SelectAllService(1,get_options_calllback);
  
 }
 
 function click_rb_proc(){
  ajaxMethod.SelectAllService(0,get_options_calllback);
 }
 
 
 
 function get_options_calllback(res){
  var result=res.value;
  
  if(result==null)
   return;
  var rows=result.Tables[0].Rows;
  var selectControl=document.getElementById("ProceedingSearch1_optionSelect");
  selectControl.length=0;
  selectControl.options[selectControl.options.length]=new Option("请选择分类",0);
  
  for(var i=0;i<rows.length;i++){
   var option=new Option(rows[i].NAME,rows[i].ID);
   selectControl.options[selectControl.options.length]=option;
  }
 }
 
 
</script>
ajax方法
 [AjaxPro.AjaxMethod()]
    public DataSet SelectAllService(int option)
    {
        if (option == 1)
            return procbo.GetDeptDs();
        else
            return procbo.GetworkDs();
    }

    后台页面
    ublic partial class userControl_ProceedingSearch : System.Web.UI.UserControl
{
 
   
    protected void Page_Load(object sender, EventArgs e)
    {
        AjaxPro.Utility.RegisterTypeForAjax(typeof(ajaxMethod));

    }
 }

 

//2003取ds某列
DataSet.Tables[0]["列名"]

 

//Page_Load事件中怎么调用页面上的JavaScript函数
this.RegisterStartupScript("h","<script language=javascript>writeHelloWorld();</script>");


//DataGrid 用超链接打开JS脚本

 <asp:TemplateField HeaderText="序号">
                         
                            <itemtemplate>
                             <a href="Javascript:Js_IFrame_OpenIframe('SortInfoModify.aspx?ID=<%#Eval("ID")%>',500,300,'修改分类',true)">
<asp:Label runat="server" Text='<%# Bind("ID") %>' id="Label1"></asp:Label></a>
</itemtemplate>
                        </asp:TemplateField>


     <asp:TemplateField HeaderText="事项名称">
                         
                            <itemtemplate>
                             <a href="Javascript:Js_IFrame_OpenIframe('ProceedingModify.aspx?ID=<%#Eval("ID")%>&WPSID=<%#Eval("wpsid") %>',800,500,'修改分类',true)">
<asp:Label runat="server" Text='<%# Bind("NAME") %>' id="Label1"></asp:Label></a>
</itemtemplate>
                        </asp:TemplateField>


/*  3个listbox之间的的 移动删除以及判断删除重复项
    添加事项时的判断输入数据的有效性
    得到listbox 选中的项 ,并用hidden客户端控件储存
*/

 //通过客户端Hidden文本控件得到选中的生命周期数据
        string temp = Request.Params["Text4"].ToString().Remove(0, 9);

  [AjaxPro.AjaxMethod()]
    public string text(string aaa)
    {
        return aaa.Remove(0, 9);
    }
  
    [AjaxPro.AjaxMethod()]
    public string checkListBox(string value)
    {
      
        string flag = "-1";
        string aa = value.Remove(0, 9);
        string[] vv = aa.Split(";".ToCharArray());
      
        for (int i = 0; i < vv.Length - 1; i++)
        {
            for (int j = i + 1; j < vv.Length; j++)
                if (vv[j].ToString() == vv[i].ToString())
                {                  
                    flag = "1";
                    break;

                }
        }
        return flag;
      
    }

<<按钮 把左边的listbox选中项添加到中间listbox
function SelectOneLeft()
        {     
            var lst1=window.document.getElementById("ctl00$main$LbxO1");
            var lstindex=lst1.selectedIndex;
            if(lstindex<0) return;
            var v = lst1.options[lstindex].value;            
            var t = lst1.options[lstindex].text;       
            
            var lst2=window.document.getElementById("ctl00$main$LbxSel");       
                    
            lst2.options[lst2.options.length] = new Option(t,v,true,true);
            var str;
            var strText=window.document.getElementById("Text3");
            for(var i=0; i<lst2.options.length; i++)
               {
              str += lst2.options[i].value+";";
               }
             strText.value = str;
             //var teva=ajaxMethod.text(strText.value)
             //alert(teva.value);
            var flag=ajaxMethod.checkListBox(strText.value);
             //alert(flag.value);   
               
            if(flag.value=="1"){
            var lstindex=lst2.selectedIndex;
            lst2.options[lstindex].parentNode.removeChild(lst2.options[lstindex]);
     alert("不能添加重复项");    
                         }      
               
        }
>>按钮 把右边的listbox选中项添加到中间listbox
 function SelectOneRight()
   {     
            var lst1=window.document.getElementById("ctl00$main$LbxO2"); //找到此listbox 即右边的listbox
            var lstindex=lst1.selectedIndex;                             //定义变量存放选择项的索引
           
            if(lstindex<0) return;
            var v = lst1.options[lstindex].value;                        //定义变量存放此选择项的value
            var t = lst1.options[lstindex].text;                         //定义变量存放此选择项的Text
            
            var lst2=window.document.getElementById("ctl00$main$LbxSel");  //找到中间的listbox     
                    
            lst2.options[lst2.options.length] = new Option(t,v,true,true); //应该是向此listbox添加value,text
            var str;
            var strText=window.document.getElementById("Text3");            //找到隐藏的文本框html控件
            for(var i=0; i<lst2.options.length; i++)
                   {
              str += lst2.options[i].value+";";                            
                   }
            strText.value = str;                                           //在此文本框中循环加入中间listbox的值并以”;“分割     
            //var teva=ajaxMethod.text(strText.value)
            //alert(teva.value);
            var flag=ajaxMethod.checkListBox(strText.value);                 //用ajax方法判断是否有重复项
            //alert(flag.value);   
                     
            if(flag.value=="1"){
            var lstindex=lst2.selectedIndex;                                  //有重复项删除并alert
            lst2.options[lstindex].parentNode.removeChild(lst2.options[lstindex]);          
      alert("不能添加重复项");  
                          }      
               
      }    
          
 //删除选中的listBox项       
function DelOne()
        {
            var lst2=window.document.getElementById("ctl00$main$LbxSel");
            var lstindex=lst2.selectedIndex;
            if(lstindex>=0)
            {
               var v = lst2.options[lstindex].value+";";
               
           
                lst2.options[lstindex].parentNode.removeChild(lst2.options[lstindex]);
            }
               
        }
       
        //取得前台LISTBOX经过筛选的的值放在隐藏HTML文本控件 让服务器调用
function getSelid()
        {  var str1
           var lst2=window.document.getElementById("ctl00$main$LbxSel");
           var strText1=window.document.getElementById("Text4");
              for(var i=0; i<lst2.options.length; i++)
                 {
              str1 += lst2.options[i].value+";";
                 }
              strText1.value = str1;
             //alert(str1); 
            // var checkVlue=window.document.getElementById("Text4");
         }
  
 
 //点击checkbox显示隐藏层  、
 
 js代码
 function show(obj)
{
if(obj.checked)
{

 //alert(obj.checked);
 var checkVlue=window.document.getElementById("checkValue")
 checkVlue.value=obj.checked;
 //alert(checkVlue.value);
 
document.getElementById('div1').style.visibility="visible";
}
else
{
 
 //alert(obj.checked);
 var checkVlue=window.document.getElementById("checkValue")
 checkVlue.value=obj.checked;
 // alert(checkVlue.value);
document.getElementById('div1').style.visibility="hidden";
}
}

html代码  
                            <input id="Checkbox2" type="checkbox" οnclick="show(this)" />提供在线办理
                            <div id=div1 style="visibility:hidden">                              
                            <asp:DropDownList ID="ddlTable" runat="server" Width="200px">
                            </asp:DropDownList>

 


    
//校验是否全由数字组成
function isDigit(s)
{
var patrn=/^[0-9]{1,20}$/;

if (!patrn.exec(s)) return false

return true
}

//检验添加事项的数据合法
function Addcheck()
{

var name =window.document.getElementById("ctl00$main$dbTxtEventName");         //事项名称
var SERIALNUM=window.document.getElementById("ctl00$main$dbTxtEventSERIALNUM");//事项编号
var Dept=window.document.getElementById("ctl00$main$DBDDLDept");               //受理窗口
var TIMELIMIT=window.document.getElementById("ctl00$main$dbTxtEventTIMELIMIT");//受理时限
var SEQUENCE=window.document.getElementById("ctl00$main$dbTxtEventSEQUENCE");  //排序
var hiddenText=window.document.getElementById("Text4");                
var workSel=window.document.getElementById("ctl00$main$LbxSel");//生命周期

//判断受理窗口被选中的索引值  //0项被选中即没选择

 

  if (name.value==""){
              alert("请填写事项名称");
              name.focus();
              return false;
                     }
  if (SERIALNUM.value==""){
              alert("请填写事项编号");
              SERIALNUM.focus();
              return false;
                     }   
  for(i = 0 ; i < Dept.children.length ; i ++)
  {
    if (Dept.children[i].selected && i==0)
    {
        alert("请选择事项受理窗口");
        return false;
    }   
   }                  
  if (TIMELIMIT.value==""||TIMELIMIT.value==0){
              alert("请填写受理时限,并且不能为0");
              TIMELIMIT.focus();
              return false;
                     }                                    

  if (workSel.children.length==0)
  {
   alert("请选择事项生命周期");
            return false;
  }
 
   
  
  if(TIMELIMIT.value!=""){
  if(!isDigit(TIMELIMIT.value)){
   alert("受理时限只能是数字");
   TIMELIMIT.focus();
   return false; 
              }
 debugger;          }   
  if(SEQUENCE.value!=""){
  if(!isDigit(SEQUENCE.value)){
   alert("排序值只能是数字,并且不能为0");
   SEQUENCE.focus();
   return false; 
              }
           }

    return true;
}


 // #region 下载保存按钮, 有附件显示无附件不显示
   
    protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
    {
        string path = Server.MapPath(DBLAttvh.Text);

        System.IO.FileInfo file = new System.IO.FileInfo(path);
        Response.Clear();
        Response.Charset = "GB2312";
        Response.ContentEncoding = System.Text.Encoding.UTF8;
        //   添加头信息,为"文件下载/另存为"对话框指定默认文件名  
        Response.AddHeader("Content-Disposition", "attachment;   filename=" + Server.UrlEncode(file.Name));
        //   添加头信息,指定文件大小,让浏览器能够显示下载进度  
        Response.AddHeader("Content-Length", file.Length.ToString());

        //   指定返回的是一个不能被客户端读取的流,必须被下载  
        Response.ContentType = "application/ms-excel";

        //   把文件流发送到客户端  
        Response.WriteFile(file.FullName);
        //   停止页面的执行  

        Response.End();
    }
#endregion


//数据库存为O1,O2,O3用switch判断RowDataBound里面写
 protected void DBgrdSubject_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            string type = e.Row.Cells[2].Text;

            switch (type)
            {
                case "o1":
                    e.Row.Cells[2].Text = "市民生命周期";
                    break;
                case "o2":
                    e.Row.Cells[2].Text = "企业生命周期";
                    break;
                case "o3":
                    e.Row.Cells[2].Text = "分类办事";
                    break;
                default:
                    e.Row.Cells[2].Text = "发生错误";
                    break;
            }
        }         
      

    }

//起始时间不能大于结束时间的判断
function checkFormTime(){
if(form1.startTime.value==""){startTimeNull();return true;}
if(form1.endTime.value==""){endTimeNull();return true;}
newTime = new Date();
str = form1.startTime.value.split('-');
st = new Date(str[0],--str[1],++str[2]-1);
str2 = form1.endTime.value.split('-');
et = new Date(str2[0],--str2[1],++str2[2]-1);
if(st > newTime){startTimeNull();}
if(et > newTime){endTimeNull();}
if(st > et){alert("起始时间不能大于结束时间");return true}
return true;
}
function startTimeNull(){alert("查询初始时间有误");}
function endTimeNull(){alert("查询结束时间有误");}

 


Asp.net中,上传文件的默认大小是4096 KB,也就是4M,不过你可以在Web.config中更改这个数据

<httpRuntime maxRequestLength="10240"

         useFullyQualifiedRedirectUrl="true"

         executionTimeout="100"/>


那么此时就是10M的文件,当然你也可以把它修改的更大,但是不管改成多大都会有个极限,如果用户上传的文件比这个值大,就会出现程序Catch不到的异常

ewebedit使用方法

<input type="hidden" name="content1" value="">
<iframe ID="eWebEditor1" src="/ewebeditor.asp?id=content1&style=standard" frameborder="0" scrolling="no" width="500" HEIGHT="350"></iframe> 或者

<textarea name="content1" style="display:none"></textarea>
<iframe ID="eWebEditor1" src="/ewebeditor.asp?id=content1&style=standard" frameborder="0" scrolling="no" width="500" HEIGHT="350"></iframe> 以上

src="/ewebeditor.asp?id=content1&中id=content1必须和文本域的名字相同

// 如何在xp 下装 sql2000

办法如下:

  一.在SQL服务器的安装盘中找到MSDE这个目录,并且点击setup.exe安装它,过程简单直接下一步就OK了。

  二. 重启系统WINDOWSXP,这下就可以看到SQL服务的图标出现了。

    三. 再拿出SQL服务器版的安装光盘,直接安装客户端工具(这个不要多说吧?最简单的方法就是直接点击光盘根目录下的autorun.exe)

根据提示安装,自检过程中知道系统不是SERVER版,会提示只安装客户端工具。(哈哈,服务端我已有了)

    四. 打开企业管理器,试用SA用户连一下看看,是不是发现SA用户登陆失败?因为你还没有与信任SQL SERVER连接相关联。还好这个只要

对系统注册表稍加修改就可以啦:

        在运行中输入regedit打开注册表编辑器,找到[HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\MSSQLSERVER\MSSQLSERVER],这个项里面

有一个键值LoginMode,默认下,值是1,现在将值改为2,重启电脑。

    五. 再打开企业管理,再连接试试,是不是OK了!

 

 

 

 


Web:Default.aspx
BLL:UserInfo.cs
DALFactoryFactory.cs
IDALIDALClass.cs
DALSQLServerAccessDB.cs、SQLHelper.cs
ModelUserEntity.cs

项目引用如下:
Web:BLL.dll、DALFactory、IDAL、SQLServer.dll
BLL:DALFactory、DALSQLServer、IDAL、Model
DALFactory:IDAL
IDAL:Model
DALSQLServer:IDAL、Model
Model:无

=============================================================================
///Web项目的代码

//Default.aspx.cs
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using BLL;
using Model;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Button2.Visible = false;
        if (!Page.IsPostBack)
        {
            //调用BLL
            UserInfo userInfo = new UserInfo();
            GridView1.DataSource = userInfo.GetALLUserInfo();
            GridView1.DataBind();
        }

    }
    protected void Button1_Click(object sender, EventArgs e)
    {
        UserEntity userEntity = new UserEntity();
        try
        {
            userEntity.UserName = txtUserName.Text.Trim();
            userEntity.Sex = ddlSex.SelectedValue.Trim();
            userEntity.Email = txtEmail.Text.Trim();
            userEntity.Phone = txtPhone.Text.Trim();
            userEntity.Address = txtAddress.Text.Trim();
        }
        catch (Exception ee)
        {
            Label1.Text = ee.Message;
            return;
        }

        try
        {
            //调用BLL层
            UserInfo userInfo = new UserInfo();
            userInfo.Insert(userEntity);
            Label1.Text = "向数据表写入成功";
            Button2.Visible = true;
        }
        catch(Exception ee)
        {
            Label1.Text = ee.Message;
        }

    }
    protected void Button2_Click(object sender, EventArgs e)
    {
        Response.Redirect("Default.aspx");
    }
}


//Web.config
<configuration>
  <appSettings>
    <add key="DALDB" value="DALSQLServer"/>
    <add key="ConnectionString" value="Server=.;DataBase=ThreeLayersSampleDB;Integrated Security = SSPI;"/>
    <add key="Select" value="Select * From UserInfo"/>
    <add key="Insert" value="InsertValues"/>
  </appSettings>
<connectionStrings/>

-------------------------------------------------------------
///BLL项目代码

//UserInfo.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Configuration;
using DALSQLServer;
using Model;
using IDAL;
using DALFactory;

namespace BLL
{
    public class UserInfo
    {
        private readonly IDAL.IDALInterface instance = DALFactory.Factory.CreateAccessDBInstance();

        public DataSet GetALLUserInfo()
        {
            return instance.GetAllUserInfo();
        }

        public void Insert(UserEntity userEntity)
        {
            try
            {
                instance.Insert(userEntity);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

    }
}

-------------------------------------------------------------------
///DALFactory项目代码

//Factory.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using System.Reflection;

namespace DALFactory
{
    public sealed class Factory
    {
        public static readonly string path = ConfigurationManager.AppSettings["DALDB"];

        public static IDAL.IDALInterface CreateAccessDBInstance()
        {
            IDAL.IDALInterface i = Assembly.Load(path).CreateInstance(path + ".AccessDB") as IDAL.IDALInterface;
            return i;
        }
    }
}

-------------------------------------------------------------------
///IDAL项目代码

//IDALInterface.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using Model;

namespace IDAL
{
    public interface IDALInterface
    {
        DataSet GetAllUserInfo();
        void Insert(UserEntity userEntity);
    }
}

///DALSQLServer项目代码

//AccessDB.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using Model;
using IDAL;

namespace DALSQLServer
{
    public class AccessDB : IDAL.IDALInterface
    {
        public DataSet GetAllUserInfo()
        {
            return SQLHelper.GetAllUserInfo();
        }

        public void Insert(UserEntity userEntity)
        {
            try
            {
                SQLHelper.Insert(userEntity);
            }
            catch (Exception e)
            {
                throw e;
            }
        }
    }
}


//SQLHelper.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using Model;
using System.Data;
using System.Configuration;

namespace DALSQLServer
{
    public abstract class SQLHelper
    {
        private static readonly string strConnection = ConfigurationManager.AppSettings["ConnectionString"];
        private static readonly string strSQLInsert = ConfigurationManager.AppSettings["Insert"];

        private static SqlConnection con = new SqlConnection(strConnection);

        public static DataSet GetAllUserInfo()
        {
            SqlDataAdapter da = new SqlDataAdapter(ConfigurationManager.AppSettings["Select"], con);
            DataSet ds = new DataSet();
            da.Fill(ds, "UserInfo");
            return ds;
        }

        public static void Insert(UserEntity userEntity)
        {
            SqlCommand com = new SqlCommand(strSQLInsert, con);
            com.CommandType = CommandType.StoredProcedure;
            com.Parameters.Add(new SqlParameter("@UserName", SqlDbType.NChar, 20));
            com.Parameters.Add(new SqlParameter("@Sex", SqlDbType.NChar, 2));
            com.Parameters.Add(new SqlParameter("@Email", SqlDbType.NChar, 50));
            com.Parameters.Add(new SqlParameter("@Phone", SqlDbType.NChar, 20));
            com.Parameters.Add(new SqlParameter("@Address", SqlDbType.NChar, 50));

            com.Parameters["@UserName"].Value = userEntity.UserName;
            com.Parameters["@Sex"].Value = userEntity.Sex;
            com.Parameters["@Email"].Value = userEntity.Email;
            com.Parameters["@Phone"].Value = userEntity.Phone;
            com.Parameters["@Address"].Value = userEntity.Address;

            try
            {
                con.Open();
                com.ExecuteNonQuery();
            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {
                con.Close();
            }
        }
    }
}

---------------------------------------------------------------
///Model项目代码

//UserEntity.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace Model
{
    public class UserEntity
    {
        private string _UserName;
        private string _Sex;
        private string _Email;
        private string _Phone;
        private string _Address;

        public UserEntity() { }

        public string UserName
        {
            set
            {
                if (value.Length > 20 || value.Length == 0)
                {
                    throw new Exception("用户名过长或为空");
                }
                _UserName = value.Replace('\'', '_');
            }
            get { return _UserName; }
        }
        public string Sex
        {
            set
            {
                if (value.Length == 0)
                {
                    throw new Exception("请选择性别");
                }
                _Sex = value.Replace('\'', '_');
            }
            get { return _Sex; }
        }
        public string Email
        {
            set
            {
                if (value.Length > 50)
                {
                    throw new Exception("Email地址过长");
                }
                _Email = value.Replace('\'', '_');
            }
            get { return _Email; }
        }
        public string Phone
        {
            set
            {
                if (value.Length > 20)
                {
                    throw new Exception("电话号码过长");
                }
                _Phone = value.Replace('\'', '_');
            }
            get { return _Phone; }
        }
        public string Address
        {
            set
            {
                if (value.Length > 50)
                {
                    throw new Exception("地址过长");
                }
                _Address = value.Replace('\'', '_');
            }
            get { return _Address; }
        }

    }
}

 

简单工厂模式,抽象工厂模式,反射工厂模式的代码总结
http://www.cnblogs.com/pumaboyd/archive/2006/10/27/541811.html

http://asp.shuangla.com/net-database-code/server-hosting-tutorial/access-upload19391.html


在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时由于需求的变化,往往存在着更多系列对象的创建工作。如何应对这种变化?如何绕过常规的对象的创建方法(new),提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合?这就是我们要说的抽象工厂模式。
 
  意图

  提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

  模型图

  逻辑模型:

 

  物理模型:

 

  生活中的例子

  抽象工厂的目的是要提供一个创建一系列相关或相互依赖对象的接口,而不需要指定它们具体的类。这种模式可以汽车制造厂所使用的金属冲压设备中找到。这种冲压设备可以制造汽车车身部件。同样的机械用于冲压不同的车型的右边车门、左边车门、右前挡泥板、左前挡泥板和引擎罩等等。通过使用转轮来改变冲压盘,这个机械产生的具体类可以在三分钟内改变。

 

  抽象工厂之新解

  虚拟案例

  中国企业需要一项简单的财务计算:每月月底,财务人员要计算员工的工资。

  员工的工资 = (基本工资 奖金 - 个人所得税)。这是一个放之四海皆准的运算法则。

  为了简化系统,我们假设员工基本工资总是4000美金。

  中国企业奖金和个人所得税的计算规则是:

  奖金 = 基本工资(4000) * 10%

  个人所得税 = (基本工资 奖金) * 40%

  我们现在要为此构建一个软件系统(代号叫Softo),满足中国企业的需求。

  案例分析

  奖金(Bonus)、个人所得税(Tax)的计算是Softo系统的业务规则(Service)。

  工资的计算(Calculator)则调用业务规则(Service)来计算员工的实际工资。

  工资的计算作为业务规则的前端(或者客户端Client)将提供给最终使用该系统的用户(财务人员)使用。

  针对中国企业为系统建模

  根据上面的分析,为Softo系统建模如下:

 

 

 

  则业务规则Service类的代码如下:

 

1using System;
2
3namespace ChineseSalary
4{
5 /** <summary>
6 /// 公用的常量
7 /// </summary>
8 public class Constant
9 {
10 public static double BASE_SALARY = 4000;
11 }
12}
1using System;
2
3namespace ChineseSalary
4{
5 /** <summary>
6 /// 计算中国个人奖金
7 /// </summary>
8 public class ChineseBonus
9 {
10 public double Calculate()
11 {
12 return Constant.BASE_SALARY * 0.1;
13 }
14 }
15}
16

 

  客户端的调用代码:

 

1using System;
2
3namespace ChineseSalary
4{
5 /** <summary>
6 /// 计算中国个人所得税
7 /// </summary>
8 public class ChineseTax
9 {
10 public double Calculate()
11 {
12 return (Constant.BASE_SALARY (Constant.BASE_SALARY * 0.1)) * 0.4;
13 }
14 }
15}
16

 

  运行程序,输入的结果如下:

  Chinese Salary is:2640

  针对美国企业为系统建模

  为了拓展国际市场,我们要把该系统移植给美国公司使用。 美国企业的工资计算同样是: 员工的工资 = 基本工资 奖金 - 个人所得税。

  但是他们的奖金和个人所得税的计算规则不同于中国企业:

  美国企业奖金和个人所得税的计算规则是:

  奖金 = 基本工资 * 15 %

  个人所得税 = (基本工资 * 5% 奖金 * 25%)

  根据前面为中国企业建模经验,我们仅仅将ChineseTax、ChineseBonus修改为AmericanTax、AmericanBonus。 修改后的模型如下:

 

 

 

  则业务规则Service类的代码如下:

 

1using System;
2
3namespace AmericanSalary
4{
5 /** <summary>
6 /// 公用的常量
7 /// </summary>
8 public class Constant
9 {
10 public static double BASE_SALARY = 4000;
11 }
12}
13


1using System;
2
3namespace AmericanSalary
4{
5 /** <summary>
6 /// 计算美国个人奖金
7 /// </summary>
8 public class AmericanBonus
9 {
10 public double Calculate()
11 {
12 return Constant.BASE_SALARY * 0.1;
13 }
14 }
15}
16

1using System;
2
3namespace AmericanSalary
4{
5 /** <summary>
6 /// 计算美国个人所得税
7 /// </summary>
8 public class AmericanTax
9 {
10 public double Calculate()
11 {
12 return (Constant.BASE_SALARY (Constant.BASE_SALARY * 0.1)) * 0.4;
13 }
14 }
15}
16

 

  客户端的调用代码:

 

1
2using System;
3
4namespace AmericanSalary
5{
6 /** <summary>
7 /// 客户端程序调用
8 /// </summary>
9 public class Calculator
10 {
11 public static void Main(string[] args)
12 {
13 AmericanBonus bonus = new AmericanBonus();
14 double bonusValue = bonus.Calculate();
15
16 AmericanTax tax = new AmericanTax();
17 double taxValue = tax.Calculate();
18
19 double salary = 4000 bonusValue - taxValue;
20
21 Console.WriteLine("American Salary is:" salary);
22 Console.ReadLine();
23 }
24 }
25}
26

 

  运行程序,输入的结果如下:

  American Salary is:2640

整合成通用系统

  让我们回顾一下该系统的发展历程:

  最初,我们只考虑将Softo系统运行于中国企业。但随着MaxDO公司业务向海外拓展, MaxDO需要将该系统移植给美国使用。

  移植时,MaxDO不得不抛弃中国企业的业务规则类ChineseTax和ChineseBonus, 然后为美国企业新建两个业务规则类: AmericanTax,AmericanBonus。最后修改了业务规则调用Calculator类。

  结果我们发现:每当Softo系统移植的时候,就抛弃原来的类。现在,如果中国联想集团要购买该系统,我们不得不再次抛弃AmericanTax,AmericanBonus,修改回原来的业务规则。

  一个可以立即想到的做法就是在系统中保留所有业务规则模型,即保留中国和美国企业工资运算规则。

 

  通过保留中国企业和美国企业的业务规则模型,如果该系统在美国企业和中国企业之间切换时,我们仅仅需要修改Caculator类即可。

  让移植工作更简单

  前面系统的整合问题在于:当系统在客户在美国和中国企业间切换时仍然需要修改Caculator代码。

  一个维护性良好的系统应该遵循“开闭原则”。即:封闭对原来代码的修改,开放对原来代码的扩展(如类的继承,接口的实现)

  我们发现不论是中国企业还是美国企业,他们的业务运规则都采用同样的计算接口。 于是很自然地想到建立两个业务接口类Tax,Bonus,然后让AmericanTax、AmericanBonus和ChineseTax、ChineseBonus分别实现这两个接口, 据此修正后的模型如下:

 

  此时客户端代码如下:

1
2using System;
3
4namespace InterfaceSalary
5{
6 /** <summary>
7 /// 客户端程序调用
8 /// </summary>
9 public class Calculator
10 {
11 public static void Main(string[] args)
12 {
13 Bonus bonus = new ChineseBonus();
14 double bonusValue = bonus.Calculate();
15
16 Tax tax = new ChineseTax();
17 double taxValue = tax.Calculate();
18
19 double salary = 4000 bonusValue - taxValue;
20
21 Console.WriteLine("Chinaese Salary is:" salary);
22 Console.ReadLine();
23 }
24 }
25}
26

  为业务规则增加工厂方法

  然而,上面增加的接口几乎没有解决任何问题,因为当系统的客户在美国和中国企业间切换时Caculator代码仍然需要修改。

  只不过修改少了两处,但是仍然需要修改ChineseBonus,ChineseTax部分。致命的问题是:我们需要将这个移植工作转包给一个叫Hippo的软件公司。 由于版权问题,我们并未提供Softo系统的源码给Hippo公司,因此Hippo公司根本无法修改Calculator,导致实际上移植工作无法进行。

  为此,我们考虑增加一个工具类(命名为Factory),代码如下:

1using System;
2
3namespace FactorySalary
4{
5 /** <summary>
6 /// Factory类
7 /// </summary>
8 public class Factory
9 {
10 public Tax CreateTax()
11 {
12 return new ChineseTax();
13 }
14
15 public Bonus CreateBonus()
16 {
17 return new ChineseBonus();
18 }
19 }
20}
21

  修改后的客户端代码:

1
2using System;
3
4namespace FactorySalary
5{
6 /** <summary>
7 /// 客户端程序调用
8 /// </summary>
9 public class Calculator
10 {
11 public static void Main(string[] args)
12 {
13 Bonus bonus = new Factory().CreateBonus();
14 double bonusValue = bonus.Calculate();
15
16 Tax tax = new Factory().CreateTax();
17 double taxValue = tax.Calculate();
18
19 double salary = 4000 bonusValue - taxValue;
20
21 Console.WriteLine("Chinaese Salary is:" salary);
22 Console.ReadLine();
23 }
24 }
25}
26

  不错,我们解决了一个大问题,设想一下:当该系统从中国企业移植到美国企业时,我们现在需要做什么?

  答案是: 对于Caculator类我们什么也不用做。我们需要做的是修改Factory类,修改结果如下:

1using System;
2
3namespace FactorySalary
4{
5 /** <summary>
6 /// Factory类
7 /// </summary>
8 public class Factory
9 {
10 public Tax CreateTax()
11 {
12 return new AmericanTax();
13 }
14
15 public Bonus CreateBonus()
16 {
17 return new AmericanBonus();
18 }
19 }
20}
21

系统增加抽象工厂方法

  很显然,前面的解决方案带来了一个副作用:就是系统不但增加了新的类Factory,而且当系统移植时,移植工作仅仅是转移到Factory类上,工作量并没有任何缩减,而且还是要修改系统的源码。 从Factory类在系统移植时修改的内容我们可以看出: 实际上它是专属于美国企业或者中国企业的。名称上应该叫AmericanFactory,ChineseFactory更合适.

  解决方案是增加一个抽象工厂类AbstractFactory,增加一个静态方法,该方法根据一个配置文件(App.config或者Web.config) 一个项(比如factoryName)动态地判断应该实例化哪个工厂类,这样,我们就把移植工作转移到了对配置文件的修改。修改后的模型和代码:

 

  抽象工厂类的代码如下:

1using System;
2using System.Reflection;
3
4namespace AbstractFactory
5{
6 /** <summary>
7 /// AbstractFactory类
8 /// </summary>
9 public abstract class AbstractFactory
10 {
11 public static AbstractFactory GetInstance()
12 {
13 string factoryName = Constant.STR_FACTORYNAME.ToString();
14
15 AbstractFactory instance;
16
17 if(factoryName == "ChineseFactory")
18 instance = new ChineseFactory();
19 else if(factoryName == "AmericanFactory")
20 instance = new AmericanFactory();
21 else
22 instance = null;
23
24 return instance;
25 }
26
27 public abstract Tax CreateTax();
28
29 public abstract Bonus CreateBonus();
30 }
31}

  配置文件:

1<?XML version="1.0" encoding="utf-8" ?>
2<configuration>
3 <appSettings>
4 <add key="factoryName" value="AmericanFactory"></add>
5 </appSettings>
6</configuration>
7

  采用上面的解决方案,当系统在美国企业和中国企业之间切换时,我们需要做什么移植工作?

  答案是: 我们仅仅需要修改配置文件,将factoryName的值改为American。

  修改配置文件的工作很简单,只要写一篇幅配置文档说明书提供给移植该系统的团队(比如Hippo公司) 就可以方便地切换使该系统运行在美国或中国企业。

  最后的修正(不是最终方案)

  前面的解决方案几乎很完美,但是还有一点瑕疵,瑕疵虽小,但可能是致命的。
  
  考虑一下,现在日本NEC公司决定购买该系统,NEC公司的工资的运算规则遵守的是日本的法律。如果采用上面的系统构架,这个移植我们要做哪些工作呢?

  1. 增加新的业务规则类JapaneseTax,JapaneseBonus分别实现Tax和Bonus接口。

  2. 修改AbstractFactory的getInstance方法,增加else if(factoryName.equals("Japanese")){....

  注意: 系统中增加业务规则类不是模式所能解决的,无论采用什么设计模式,JapaneseTax,JapaneseBonus总是少不了的。(即增加了新系列产品)

  我们真正不能接受的是:我们仍然修要修改系统中原来的类(AbstractFactory)。前面提到过该系统的移植工作,我们可能转包给一个叫Hippo的软件公司。 为了维护版权,未将该系统的源码提供给Hippo公司,那么Hippo公司根本无法修改AbstractFactory,所以系统移植其实无从谈起,或者说系统移植总要开发人员亲自参与。

  解决方案是将抽象工厂类中的条件判断语句,用.NET中发射机制代替,修改如下:

1using System;
2using System.Reflection;
3
4namespace AbstractFactory
5{
6 /** <summary>
7 /// AbstractFactory类
8 /// </summary>
9 public abstract class AbstractFactory
10 {
11 public static AbstractFactory GetInstance()
12 {
13 string factoryName = Constant.STR_FACTORYNAME.ToString();
14
15 AbstractFactory instance;
16
17 if(factoryName != "")
18 instance = (AbstractFactory)Assembly.Load(factoryName).CreateInstance(factoryName);
19 else
20 instance = null;
21
22 return instance;
23 }
24
25 public abstract Tax CreateTax();
26
27 public abstract Bonus CreateBonus();
28 }
29}
30

  这样,在我们编写的代码中就不会出现Chinese,American,Japanese等这样的字眼了。

  小结

  最后那幅图是最终版的系统模型图。我们发现作为客户端角色的Calculator仅仅依赖抽象类, 它不必去理解中国和美国企业具体的业务规则如何实现,Calculator面对的仅仅是业务规则接口Tax和Bonus。

  Softo系统的实际开发的分工可能是一个团队专门做业务规则,另一个团队专门做前端的业务规则组装。 抽象工厂模式有助于这样的团队的分工: 两个团队通讯的约定是业务接口,由抽象工厂作为纽带粘合业务规则和前段调用,大大降低了模块间的耦合性,提高了团队开发效率。

  完完全全地理解抽象工厂模式的意义非常重大,可以说对它的理解是你对OOP理解上升到一个新的里程碑的重要标志。 学会了用抽象工厂模式编写框架类,你将理解OOP的精华:面向接口编程。

  应对“新对象”

  抽象工厂模式主要在于应对“新系列”的需求变化。其缺点在于难于应付“新对象”的需求变动。如果在开发中出现了新对象,该如何去解决呢?这个问题并没有一个好的答案,下面我们看一下李建忠老师的回答:

  “GOF《设计模式》中提出过一种解决方法,即给创建对象的操作增加参数,但这种做法并不能令人满意。事实上,对于新系列加新对象,就我所知,目前还没有完美的做法,只有一些演化的思路,这种变化实在是太剧烈了,因为系统对于新的对象是完全陌生的。” 实现要点

  ·抽象工厂将产品对象的创建延迟到它的具体工厂的子类。

  ·如果没有应对“多系列对象创建”的需求变化,则没有必要使用抽象工厂模式,这时候使用简单的静态工厂完全可以。

  ·系列对象指的是这些对象之间有相互依赖、或作用的关系,例如游戏开发场景中的“道路”与“房屋”的依赖,“道路”与“地道”的依赖。

  ·抽象工厂模式经常和工厂方法模式共同组合来应对“对象创建”的需求变化。

  ·通常在运行时刻创建一个具体工厂类的实例,这一具体工厂的创建具有特定实现的产品对象,为创建不同的产品对象,客户应使用不同的具体工厂。 l 把工厂作为单件,一个应用中一般每个产品系列只需一个具体工厂的实例,因此,工厂通常最好实现为一个单件模式。

  ·创建产品,抽象工厂仅声明一个创建产品的接口,真正创建产品是由具体产品类创建的,最通常的一个办法是为每一个产品定义一个工厂方法,一个具体的工厂将为每个产品重定义该工厂方法以指定产品,虽然这样的实现很简单,但它确要求每个产品系列都要有一个新的具体工厂子类,即使这些产品系列的差别很小。 优点

  ·分离了具体的类。抽象工厂模式帮助你控制一个应用创建的对象的类,因为一个工厂封装创建产品对象的责任和过程。它将客户和类的实现分离,客户通过他们的抽象接口操纵实例,产品的类名也在具体工厂的实现中被分离,它们不出现在客户代码中。

  ·它使得易于交换产品系列。一个具体工厂类在一个应用中仅出现一次--即在它初始化的时候。这使得改变一个应用的具体工厂变得很容易。它只需改变具体的工厂即可使用不同的产品配置,这是因为一个抽象工厂创建了一个完整的产品系列,所以整个产品系列会立刻改变。

  ·它有利于产品的一致性。当一个系列的产品对象被设计成一起工作时,一个应用一次只能使用同一个系列中的对象,这一点很重要,而抽象工厂很容易实现这一点。

  缺点

  ·难以支持新种类的产品。难以扩展抽象工厂以生产新种类的产品。这是因为抽象工厂几口确定了可以被创建的产品集合,支持新种类的产品就需要扩展该工厂接口,这将涉及抽象工厂类及其所有子类的改变。

  适用性

  在以下情况下应当考虑使用抽象工厂模式:

  ·一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。

  ·这个系统有多于一个的产品族,而系统只消费其中某一产品族。

  ·同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。

  ·系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。

  应用场景

  ·支持多种观感标准的用户界面工具箱(Kit)。

  ·游戏开发中的多风格系列场景,比如道路,房屋,管道等。

  ·……

  总结

  总之,抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,运用抽象工厂模式的关键点在于应对“多系列对象创建”的需求变化。一句话,学会了抽象工厂模式,你将理解OOP的精华:面向接口编程。

转载于:https://www.cnblogs.com/yeqi770/archive/2008/07/02/1233723.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值