.Net学习笔记——细节问题

本篇是《ASP.NET编程技巧》(http://blog.csdn.net/zhouwen/archive/2010/09/16/5889330.aspx)的姊妹篇,记录.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" onblur="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") 结果为:
    38bddf48f43c48588e0d78761eaa1ce6
2、Guid.NewGuid().ToString("D") 结果为:
    57d99d89-caab-482a-a0e9-a0a803eed3ba
3、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 onclick="javascript:window.history.go(-1);"value="返回上一页">
浅析:这个是用了HTML控件,通过一个onclick的事件,调用了javascript中的一个方法就可以了。这个是最简单的了,也同样适用于静态页面,ASP页面等。
方法二:
利用Reponse.Write
Response.Write("<script language=javascript>history.go(-2);</script>)
<a   href="#"   onclick="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;

 

posted @ 2011-02-17 20:22  zhouhb  阅读(1294)  评论(0编辑  收藏  举报