本篇是《ASP.NET编程技巧》()的姊妹篇,记录.Net学习笔记——细节问题!有的时候,细节决定成败!
(1)如何判断2个字符串对象是否指向同一个引用?
string s1 = "aa";
string s2 = "aa";MessageBox.Show(object.ReferenceEquals(s1,s2).ToString()); //true char[] ch = { 'a', 'a' };string s1 = new string(ch);string s2 = "aa";MessageBox.Show(object.ReferenceEquals(s1,s2).ToString()); //false(2)获取本机IP地址。 public static IPAddress[] GetLocalhostIPv4Addresses() { String LocalhostName = Dns.GetHostName(); IPHostEntry host = Dns.GetHostEntry(LocalhostName); List<IPAddress> addresses=new List<IPAddress>(); foreach (IPAddress ip in host.AddressList) { if (ip.AddressFamily == AddressFamily.InterNetwork) addresses.Add(ip); } return addresses.ToArray(); }(3)如何把窗体坐标转换成屏幕坐标?
private void Form4_MouseMove(object sender, MouseEventArgs e) { textBox1.Text = string.Format("x:{0},y:{1}", e.X,e.Y); Point p = new Point(e.X, e.Y); p=this.PointToScreen(p); //把窗体坐标转换成屏幕坐标 textBox2.Text = string.Format("x:{0},y:{1}", p.X,p.Y); p = this.PointToClient(p); textBox3.Text = string.Format("x:{0},y:{1}", p.X, p.Y); }(4) 窗体显示帮助按钮this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;this.HelpButton = true;this.MaximizeBox = false;this.MinimizeBox = false;点击帮助按钮,显示chm格式的帮助文件?处理窗体的HelpButtonClicked事件:
System.Diagnostics.Process.Start("ArticleCollectorAPI.chm");
(5)控件的Anchor、Dock属性区别
Anchor用于设置控件与窗体边缘的距离保持不变!Dock用于设置控件紧贴窗体的某个边缘或者填充整个窗体。(6)使用DataGridView显示、更新、删除数据
string connstr = @"server=.\sqlexpress;initial catalog=MySchool;uid=sa;pwd=sa2008";
DataSet ds = new DataSet();SqlDataAdapter da;//显示数据
private void LoadData()
{ string strwhere; if (comboBox1.Text == "男") strwhere="sex='男'"; else if (comboBox1.Text == "女") strwhere="sex='女'"; else strwhere="sex='男' or sex='女'"; string sql = "select StudentId,StudentNo,StudentName,Sex from Student where " + strwhere; da = new SqlDataAdapter(sql, connstr);ds.Tables.Clear();
da.Fill(ds); dataGridView1.DataSource = ds.Tables[0];}
//更新数据private void button2_Click(object sender, EventArgs e)
{//自动产生更新数据库的SQL语句,但其数据必须是来自同一个数据表。否则,更新失败!
SqlCommandBuilder cmdb = new SqlCommandBuilder(da);da.Update(ds);
LoadData(); }//删除数据
private void 删除ToolStripMenuItem_Click(object sender, EventArgs e)
{ if (dataGridView1.SelectedRows.Count== 0) //SelectionMode属性用FullRowSelect { MessageBox.Show("请选择!"); return; } if (MessageBox.Show("确认要删除吗?", "警告", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) { using (SqlConnection conn = new SqlConnection(connstr)) { string sql = "delete from Student where StudentId=" + (int)dataGridView1.SelectedRows[0].Cells[0].Value; SqlCommand cmd = new SqlCommand(sql, conn); conn.Open(); cmd.ExecuteNonQuery(); } LoadData(); } } (7)关闭主窗体,出现是否退出的对话框:private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{ if (MessageBox.Show("确定要退出吗", "系统消息", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel) {e.Cancel = true;
} }private void FormMain_FormClosed(object sender, FormClosedEventArgs e)
{Application.Exit();
}//“退出”菜单的事件代码
private void 退出ToolStripMenuItem_Click(object sender, EventArgs e)
{ this.Close(); }(8)JavaScript访问服务端控件:
服务端控件声明:
<asp:TextBox ID="txtName" οnblur="CheckName()" runat=server></asp:TextBox><span id="error" style="color:Red"></span><br />
对应的JavaScript代码:
function CheckName() { if(document.forms(0).txtName.value.length!=6) { document.getElementById("<%= txtError.ClientID%>").value="error"; } else document.getElementById('error').innerHTML=""; }(9)表单回发之后,保留密码框中的密码
一般来说,当表单回发之后,密码框将会被自动清空。但是有些时候,我们并不希望这样。这时,我们可以添加下面的代码来避免这个问题。
protectedvoidPage_Load(objectsender,EventArgse)
{
if(IsPostBack) //如果是页面回发
{
if(!(String.IsNullOrEmpty(txtPassword.Text.Trim())))
{
txtPassword.Attributes["value"]=txtPassword.Text;
}
}
}
(10)重写Equals 方法判断对象是否相等
默认情况下,Object类的Equals()方法用于判断2个对象是否相等,是比较2个对象是否引用同一个对象。如果要支持值相等,则需要重写Equals虚方法。
public override bool Equals(object obj)
{ //将要比较的对象转换为当前类型 Student target = obj as Student;//如果为空、类型不同
if( target == null) return false;if (target.name == this.name &&
target.gender == this.gender && target.age == this.age) { return true; } return false; }(11)FileDialog的FilterIndex属性
注意msdn中的描述:
The index value of the first filter entry is 1.不是0.
(12)FileDialog的RestoreDirectory属性
msdn中的描述:假设用户在搜索文件的过程中更改了目录,那么,如果对话框会将当前目录还原为初始值,则值为 true;反之,值为 false。 默认值为 false。看了这个描述,是不是还是糊里糊涂的 o(∩_∩)o
其实,这个属性其实是控制当前程序中的System.Environment.CurrentDirectory的,也就是,当属性设置为true时,System.Environment.CurrentDirectory永远是程序从中启动的文件夹目录;而设置为false是,则每次使用OpenFileDialog选择完文件后,System.Environment.CurrentDirectory会变成最后一次打开文件的目录。
(13)页面刷新后保持滚动条不动,还在原来的位置
ASP.NET 2.0里提供了这样的一个方案,可以通过设置
<%@ Page MaintainScrollPositionOnPostBack="true" %>
或在编码里设置
Page.MaintainScrollPositionOnPostBack= true;
或在web.config里设置
<pages maintainScrollPositionOnPostBack="true" />
来达成。
(14)操作SQL Server数据库的bit字段
在SQL Server数据库的bit字段的值为1,或者是0。因此,向数据库中新增或修改时,该字段的值要为1或者是0。
但从数据库中取出bit字段的值时,对应的值为true或者为false。
(15)使用GUID
GUID(全局统一标识符)是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成GUID的API。生成算法很有意思,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。GUID的唯一缺陷在于生成的结果串会比较大。
1. 一个GUID为一个128位的整数(16字节),在使用唯一标识符的情况下,你可以在所有计算机和网络之间使用这一整数。2. GUID 的格式为“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,其中每个 x 是 0-9 或 a-f 范围内的一个十六进制的数字。例如:337c7f2b-7a34-4f50-9141-bab9e6478cc8 即为有效的 GUID 值。
3. 世界上(Koffer注:应该是地球上)的任何两台计算机都不会生成重复的 GUID 值。GUID 主要用于在拥有多个节点、多台计算机的网络或系统中,分配必须具有唯一性的标识符。
.NET中使用GUID
GUID 在 .NET 中使用非常广泛,而且 .NET Framework 提供了专门 Guid 基础结构。
Guid 结构的常用法包括:1) System.Guid.NewGUID() 生成一个新的 GUID 唯一值2) System.Guid.NewGUID() ToString()将 GUID 值转换成字符串,便于处理1、Guid.NewGuid().ToString("N") 结果为:
38bddf48f43c48588e0d78761eaa1ce62、Guid.NewGuid().ToString("D") 结果为: 57d99d89-caab-482a-a0e9-a0a803eed3ba3、Guid.NewGuid().ToString("B") 结果为: {09f140d5-af72-44ba-a763-c861304b46f8}4、Guid.NewGuid().ToString("P") 结果为: (778406c2-efff-4262-ab03-70a77d09c2b5)可见默认的为第2种效果同样,SQL Server也很好地集成了GUID的用途。SQL Server数据类型uniqueidentifier能够存储一个GUID数值。你可以通过使用NEWID()函数在SQL Server中生成这一数值,或者可以在SQL Server之外生成GUID,然后再手动地插入这一数值。
(16)内容页访问母版页控件
在子页中可以通过事件来访问母版页的控件属性
方法一如下:
(1)说明: 通过Master对象查找控件的形式转换为对应的控件类型 示例:this.lblContent.Text = (Master.FindControl("lblTime") as Label).Text; this.lblContent.Text = (Master.FindControl("lblTime") as Label).Text;(2)必须在子页面一些指定的方法里面 protected void Page_LoadComplete(object sender, EventArgs e) { this.lblContent.Text = (Master.FindControl("lblTime") as Label).Text; } 其中,“Page_LoadComplete”是内容页面加载完成时触发的一个事件。(3)也可以在事件中操作母版页功能 protected void Button1_Click(object sender, EventArgs e) { (Master.FindControl("lblTime") as Label).Text = "HeLLO you"; }方法二 通过强引用
<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" Title="Untitled Page" %>
<%@ MasterType VirtualPath="~/MasterPage.master" %>然后可以在母版页中定义公共属性或方法
public string GetUserName(){ return Page.User.Identity.Name;}在内容页中调用 Label1.Text = "欢迎光临" + Master.GetUserName();(17)转到前一页
方法一:
在asp.net的aspx里面的源代码中<input type="button οnclick="javascript:window.history.go(-1);"value="返回上一页">浅析:这个是用了HTML控件,通过一个onclick的事件,调用了javascript中的一个方法就可以了。这个是最简单的了,也同样适用于静态页面,ASP页面等。方法二:利用Reponse.WriteResponse.Write("<script language=javascript>history.go(-2);</script>)<a href="#" οnclick="javascript:history.back();">返回前一页</a>因为在asp.net中的页面,当你按下一个button后,由于页面中会实现page.postback的缘故,实际上在这其中是刷新了两次页面,我们要的是第一次的,所以就......方法三利用Response.Redirect() 或 Server.Transfer()在page_load中加入:if(!IsPostBack) ViewState["retu"]=Request.UrlReferrer.ToString(); 而后在返回按钮事件中加入: Response.Redirect(ViewState["retu"].ToString()); 或Server.Transfer (ViewState["retu"].ToString()); Request.UrlReferrer可以获取客户端上次请求的url的有关信息,我们在使用这个的时候最好对其进行一个判断if(ViewState["UrlReferrer"]!=null) Response.Redirect(ViewState["UrlReferrer"].ToString();else Response.write("对不起,当前是最前页码“);在使用Request.UrlReferrer时还要注意: 1. 如果上一页面使用document.location方法导航到当前页面,Request.UrlReferrer返回空值2. 如果有A,B两个页面,在浏览器中直接请求A页面,在A页面的中Page_Load事件中导航到B 页面,则 Request.UrlReferrer返回空。因为在Page_load事件中页面还未初始化,所以无法记录当前页的信息,导航到b页面也就无法获得上一页面的信息 3. 点击刷新按钮不会改变Request.UrlReferrer 方法四:在button的onClick事件中输入this.RegisterClientScriptBlock("e", "<script language=javascript>history.go(-2);</script>");(18)Web.config中注册用户控件和自定义控件
在ASP.NET 的早先版本里,我们通过在页面的顶部添加 <%@ Register %> 指令来引入和使用自定义服务器控件和用户控件时,象这样:
<%@ Register TagPrefix="scott" TagName="header" Src="Controls/Header.ascx" %> <%@ Register TagPrefix="scott" TagName="footer" Src="Controls/Footer.ascx" %> <%@ Register TagPrefix="ControlVendor" Assembly="ControlVendor" %> <html> <body> <form id="form1" runat="server"> <scott:header ID="MyHeader" runat="server" /> </form> </body> </html> 注意到上面的前两个注册指令是用来注册用户控件的(是在.ascx文件里实现的),最后这个是用来注册编译进一个程序集 .dll 文件里的自定义控件的。注册完后,我们能够在页面的任何地方用设定好的 tagprefix (标识前缀)和标识符号名( tagname)来声明这些控件。这行之有效,但管理起来会很痛苦,当我们要在我们的网站的许多页面上使用控件的话,尤其是,假如你移动了.ascx 文件,需要更新所有的注册声明的话。 处理方案: ASP.NET 2.0 使得控件声明极其干净而且管理起来极其容易。不用在页面上重复这些声明,只需在应用的web.config 文件的新的 pages->controls 部分声明一次即可: <?xml version="1.0"?> <configuration> <system.web> <pages> <controls> <add tagPrefix="scottgu" src="~/Controls/Header.ascx" tagName="header"/> <add tagPrefix="scottgu" src="~/Controls/Footer.ascx" tagName="footer"/> <add tagPrefix="ControlVendor" assembly="ControlVendorAssembly"/> </controls> </pages> </system.web> </configuration> 能够用这种方式同时声明用户控件和编译好的自定义控件。当使用这个技巧时,Visual Studio是完全支持这两者的,而且 VS 2005 Web Site 项目 和 VS 2005 Web Application 项目也都支持这两者。Visual Studio会在设想器里以所见即所得(WYSIWYG)模式显示这些控件,也会在后台编码文件里提示控件字段的声明。 一旦你在web.config 文件中声明好这些控件后,就能够在你网站上的任何一个页面,母板页或者用户控件中使用它们了,象这样(不再需要注册指令): <html> <body> <form id="form1" runat="server"> <scottgu:header ID="MyHeader" runat="server" /> </form> </body> </html>但要注意:如果在Web.config中注册用户控件,ASCX控件文件跟ASPX页面文件不能放在同一个目录下,否则会报错。
(19)WinForm中将Form显示在Panel中(C#)
pnlOPContainer.Controls.Clear();//移除所有控件FrmAddUser frmAddUser = new FrmAddUser();frmAddUser.TopLevel = false;frmAddUser.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;pnlOPContainer.Controls.Add(frmAddUser);frmAddUser.Show();
(20)DBNULL和NULL
Null是.net中无效的对象引用。DBNull是一个类。DBNull.Value是它唯一的实例。它指数据库中数据为空时,在.net中的值。null表示一个对象的指向无效,即该对象为空对象。DBNull.Value表示一个对象在数据库中的值为空,或者说未初始化,DBNull.Value对象是指向有效的对象。DBNull在DotNet是单独的一个类型 System.DBNull 。它只有一个值 DBNull.Value 。DBNull 直接继承 Object。这里容易犯的一个错误是,把ExecuteScalar返回DBNull与null的情况混淆,例如:string sql = string.Format("SELECT SUM(Cost) FROM CardRecord WHERE CardNO ='{0}'",txtCardNO.Text);如果没有数据,这里就会出错。你可以用Convert.IsDBNull来判断一个值是否DBNull。if (Convert.IsDBNull(command.ExecuteScalar()) == true){ MessageBox.Show("no"); connection.Close(); return;}注意Convert.IsDBNull(null)是false,也就是说null跟DBNull.Value是不等的。
(21)装箱和拆箱
object o = 2.56;float f = (float)o;//运行时报异常。C#中有两种类型变量,一种是值类型变量, 例如:int, float,double等等; 另一种是引用类型变量例如:string,用class定义的类型等等; 那么这两种类型变量的区别是,前一个是分配在栈中,后一个是分配在堆中。 对于如下操作 object obj = 0.0; 在c#中称为装箱操作,即把本应该放在栈中的数据放在堆中。 那么如果要拆箱,即把object返还成float变量, 不能用 float f2 = (float)(obj); 去获得,而要用 float f2 = float.Parse(obj.ToString()); 为什么前者不行呢,因为如果float存在栈中,长度是固定的。但是通过object来存放在堆中,那么它的长度就不仅仅是float数据的长度,还要包括一些其他信息,那么按照第一种方法进行强转的时候,很可能按照object存放的起始位置,以及float的变量长度,是无法把相应字节转换成float变量,因此会产生异常。下面的代码是可以的:object o = 2.56f;float f = (float)o;