S R B 项目总结
1:Label的慎用:Label被打到前台的时候,显示的是span,随之而来也会带来问题。首先:代码的encode与decode。其次:如果Label放在表格的一个td里面,如果Label过长,导致被td覆盖,看不到后面的,也不能拖动使之显示。还有:如果Label用来展现从数据库中读出的数据时,如果数据库此字段前面有多个空格。因为Html不对空格进行解析,所以导致视觉上空格不能被展示出来。
解决方案:用TextBox代替Label用于数据展示。TextBox不需要考虑encode和decode问题。其他2个问题也可以被解决。TextBox可以用css样式使之看上去和Label具有相同的外观。
.txtLabelLike
{
border-top: 1px solid #FFFFFF;
border-left: 2px solid #FFFFFF;
border-right: 2px solid #FFFFFF;
border-bottom: 1px solid #FFFFFF;
}
2:多行文本框的问题
<asp:TextBox CssClass="txtEnabled" Rows="4" TextMode="MultiLine" Columns="92" MaxLength="255"></asp:TextBox>
一些备注一类的使用多行文本框。多行文本框的使用需要注意以下问题:
l 多行文本框的MaxLength虽然可以设置,但是却不起作用。
l 虽然多行文本框也可以设置height和width属性,但是推荐使用Cloumns和Rows属性代替之。需要注意的是Rows属性设置的行高是以阿拉伯数字和英文字母为参考,所以在上面的例子中如果填写4行汉字,最后一行文字的底部会有部分被覆盖住。
l 多行文本框每次回传提交的时候,前面和后面的回车换行符会被各“吃掉”一个。现在还没有找到什么好的解决方案,推荐的解决方案是;如果没有特殊的要求,可以trim掉多行文本框的空格和换行符。支持看上去不会那么“奇怪”。
3:服务器端和客户端
应该尽量避免对同一业务过程同时使用客户端控制和服务器端控制。这样的设计会比较容易出现错误。如果一定要使用客户端和服务器端的同时控制需要注意以下问题:
l 一些类似下拉列表框的控件,如果是必须是服务器端控件,则对其的onchange事件需要用脚本来控制以避免页面的刷新让客户无法接受。
l 如果对一个控件,同时进行用脚本来清空和服务器端的清空(修改),需要注意的是:用脚本虽然清空(修改)了,但是只是客户端的清空(修改),这时候,此控件的服务器端的数值并没有被清空(修改),一回传,客户端的值又会被服务器端的值覆盖。
二:编码方面
1:每一个文本框都应该设置width和maxLength,如果没有设置,重点确认一下。
2:对于用户输入的内容注意是否需要以下的处理:
l Trim 或者 TrimEnd
l 大写转换为小写
l 全角转换为半角
txtProjectNO.Text = Utility.ToHanKaku(txtProjectNO.Text).ToUpper
l 如果输入的是日期,请参考下面的函数处理之
’对日期的验证
Public Shared Function ValidateYMD(ByVal p_strValidatedYM As String) As Boolean
Try
’转为半角后TrimEnd
p_strValidatedYM = Utility.ToHanKaku(p_strValidatedYM).TrimEnd
’利用正则表达式验证日期格式
If Regex.IsMatch(p_strValidatedYM, "\d{4}\D\d{1,2}\D\d{1,2}") Then
’判断最大日期和最小日期范围
If Not Check.IsDate(p_strValidatedYM) OrElse _
CDate(p_strValidatedYM) > CDate(CommonConst.MAX_YMD) OrElse _
CDate(p_strValidatedYM) < CDate(CommonConst.MIN_YMD) _
Then
Return False
End If
ElseIf p_strValidatedYM <> String.Empty Then
Return False
End If
Return True
Catch ex As Exception
Return False
End Try
End Function
’转换为半角文字
Public Shared Function ToHanKaku(ByVal p_strText As String) As String
If p_strText Is Nothing Then
Return String.Empty
End If
Return StrConv(p_strText, VbStrConv.Narrow)
End Function
Public Shared Function IsDate(ByVal p_strText As String) As Boolean
Try
Date.Parse(p_strText)
Return True
Catch
Return False
End Try
End Function
l 如果要输入的是数量等数值,请参考下面的过程处理之
’对数量的验证(用户自定义控件)
Protected Sub ValidateAmountData(ByVal source As Object, ByVal args As System.Web.UI.WebControls.ServerValidateEventArgs)
Dim l_strNumber As String
Try
args.IsValid = False
’要去掉逗号,还要转为半角,不能让全角通过
l_strNumber = Utility.ToHanKaku(Utility.RemoveComma(args.Value))
If Not Check.StringInLength(CDec(strNumber)).ToString("##0"), 10) Then
Exit Sub
End If
If Not Check.IsNumeric(l_strNumber) Then
Exit Sub
End If
If CDec(l_strNumber) < 1 Then
Exit Sub
End If
args.IsValid = True
Catch ex As Exception
args.IsValid = False
End Try
End Sub
Public Shared Function RemoveComma(ByVal p_strText As String) As String
Return p_strText.Replace(",", String.Empty).Replace(",", String.Empty)
End Function
Public Shared Function IsNumeric(ByVal p_strText As String) As Boolean
Try
Double.Parse(p_strText)
Return True
Catch
Return False
End Try
’判断字符串长度是否合法的函数
Public Shared Function StringInLength(ByVal p_strText As String, ByVal p_intLength As Integer) As Boolean
If p_intLength < GetEncoding.GetByteCount(p_strText) Then
Return False
End If
Return True
End Function
Public Shared Function GetEncoding() As Encoding
Try
Return Encoding.GetEncoding("shift-jis")
Catch
Return Encoding.Default
End Try
End Function
l 如果输入的是金额等数值,请参考下面的过程处理之
’单价的验证处理过程例子(用户自定义控件)
Protected Sub ValidateUnitPriceData(ByVal source As Object, ByVal args As System.Web.UI.WebControls.ServerValidateEventArgs)
Dim l_strNumber As String
Try
args.IsValid = False
If args.Value = String.Empty Then
Exit Sub
End If
l_strNumber = Utility.ToHanKaku(Utility.RemoveComma(args.Value))
If Not Check.IsNumeric(l_strNumber) Then
Exit Sub
End If
If CDec(l_strNumber) < 0 Then
Exit Sub
End If
If CDec(l_strNumber) <> CDec(Utility.FormatMoney(l_strNumber)) Then
Exit Sub
End If
args.IsValid = True
Catch ex As Exception
args.IsValid = False
End Try
End Sub
Public Shared Function FormatMoney(ByVal p_strText As String) As String
If Check.IsNumeric(p_strText) Then
Return CDec(p_strText).ToString("###,##0")
End If
Return p_strText
End Function
3:对于从数据库中读取出来展现在页面上的内容注意是否需要以下的处理:
l 如果是用Label展现出来的一定要注意encode,防止形如<input>这样的数据。
l 如果数据库中的数据,前面包含很多的空格,如果用Label展现的话,空格不会被表现出来(虽然查看html的时候,空格是存在的。)
l 是否需要Trim或者TrimEnd
l 应该考虑数据库中此字段是否有可能为DBNull。如果可能要使用下面的方法处理之
'申請依頼元社員氏名
ucStaff.StaffName = Utility.GetFieldOfString(.Item(ConstData.ViewConst.V_STAFF_INFO.STAFF_NAME)).TrimEnd
Public Shared Function GetFieldOfString(ByVal p_objDBdata As Object) As String
Return GetFieldOfString(p_objDBdata, String.Empty)
End Function
Public Shared Function GetFieldOfString(ByVal p_objDBdata As Object, ByVal p_strDefaultValue As String) As String
If p_objDBdata Is DBNull.Value Then
Return p_strDefaultValue
Else
Return CStr(p_objDBdata)
End If
End Function
4:用户控件可以通过如下的方法找到包含此用户控件页面上的其他控件
’ViewState(ConstData.ViewState.SRBU9001_DEPTCODE_LABEL_ID)为一开始传进来的父页面上的某个Label的ID
DirectCast(Me.Parent.FindControl(ViewState(ConstData.ViewState.SRBU9001_DEPTCODE_LABEL_ID).ToString), Label).Text = “Txt”
5:文本框的onchange事件
文本框的onchange事件并不像看上去那么简单,这是个令人头痛的问题。因为文本框本身的onchange事件存在一些bug,有一定几率不触发。(例如在打开拼音输入法是,没有按回车确定输入法中显示的文字是直接离开文本框就有一定几率使得onchange事件不触发。)所以我们使用了onfocusin,记下当时数值,在onfocusout时对比与onfocusin时的数值模拟onchange事件。但是此种方法也会有问题。就是在用户用鼠标拖拽数据使内容发生变化时,onfocusin事件不会被触发。
最终的解决方案如下:
首先:在js脚本文件中添加下面语句,禁用此页面的拖拽功能
document.attachEvent("ondragstart",function(){return false;})
然后在共同的文件里面添加以下共同的过程
’ AddTextBoxValueChangeEvent通用部分
Public Shared Sub AddTextBoxValueChangeEvent(ByVal p_objTextBox As TextBox)
Dim l_objFocusout As New StringBuilder
l_objFocusout.Append("if (this.savevalue == this.value) return;")
l_objFocusout.AppendFormat("if (typeof({0}) == 'function') {0}();", p_objTextBox.ClientID & "_onvaluechange")
l_objFocusout.Append("this.savevalue = this.value;")
p_objTextBox.Attributes.Add("savevalue", "")
’获得焦点的时候用savavalue(自己定义的属性)记录当前值
p_objTextBox.Attributes.Add("onfocusin", "this.savevalue = this.value;")
’失去焦点时,触发在前台自己定义的onchange事件
p_objTextBox.Attributes.Add("onfocusout", l_objFocusout.ToString)
’拖拽进来时触发获得焦点事件
p_objTextBox.Attributes.Add("ondragenter", "this.focus();")
’禁止在文本框上进行拖拽
p_objTextBox.Attributes.Add("ondragstart", "return false;")
End Sub
然后在后台对需要添加onchange事件的文本框添加以下代码
’对txtProjectNO添加onchange事件
ClientAPI.AddTextBoxValueChangeEvent(txtProjectNO)
最后在前台或者后台添加相如function <%=txtProjectNo.ClientID%>_onvaluechange()的js脚本函数
在前台写法如下:
function <%=txtProjectNo.ClientID%>_onvaluechange()
{
document.all.<%=lblProjectName.ClientID%>.innerText="";
document.all.<%=txtProjectValidFlag.ClientID%>.value="0";
}
在后台写法如下:
Dim l_objScript As New System.Text.StringBuilder
With l_objScript
.AppendLine("function " & txtProjectNo.ClientID & "_onvaluechange()")
.AppendLine("{ ")
.AppendLine("document.getElementById(""" & lblProjectName.ClientID & """). innerText ="""";")
.AppendLine("document.getElementById(""" & txtProjectValidFlag.ClientID & """).value=""0"";")
.AppendLine("}")
End With
’注册脚本
Me.Page.ClientScript.RegisterClientScriptBlock(Me.Page.GetType(), Me.ID & "ProjectNoOnchange", l_objScript.ToString(), True)
6:多个控件执行同一个过程
’按钮
AddHandler btnRegisterCancel.Click, AddressOf RegisterCancel
’验证控件
AddHandler cuvHopeDeliverDateNoteIncludeHanaComma.ServerValidate, AddressOf ValidateIncludeHanaComma
7:取得系统日付的方法
'申請日=システム日付
lblApplyDate.Text = CStr(DateTime.Today())
8:如果同一个控件有多个验证控件对其进行验证,可以将多个验证控件的显示都设置为动态,这样就无须自己去考虑验证控件的星号显示时的间隔问题。文本框和多个验证控件,多个文本框之间的Html代码不能有空格和回车。
<asp:TextBox ID="txtApplicantNote" runat="server" ></asp:TextBox><asp:CustomValidator ID="cuvApplicantNoteIncludeComma" Enabled="false" runat="server" EnableClientScript="false" ControlToValidate="txtApplicantNote" Text="*" Display="Dynamic"></asp:CustomValidator><asp:CustomValidator ID="cuvApplicantNote" Enabled="false" runat="server" EnableClientScript="false" ControlToValidate="txtApplicantNote" Text="*" Display="Dynamic"></asp:CustomValidator>
9:多行文本框在预览的时候可能不能显示完整,可以在预览的时候利用下面的样式,使之出现竖向滚动条。
.txtPreview
{
overflow-y: auto;