随笔-24  评论-69  文章-1  trackbacks-2
  2008年10月10日

ASP.NET学习笔记系列:

ASP.NET 2.0 提供了非常强大的绑定能力,而 ASP.NET 2.0 新增的 GridView 控件更是充分体现和发挥了数据绑定强大的功能。GridView 的数据绑定和页面显示可以通过简单的代码实现,大大提高了开发效率。

不过有个地方让人不爽,就是在使用分页时,如果绑定的数据不满一页,那么 GridView 仅显示绑定的数据。例如,将 GridView 的 PageSize 设置为 10,每页显示 10 条数据,如果当前查询仅返回了 6 条数据,那么 GridView 就显示这 6 条数据,如果当前查询返回了多于 10 条数据,那么 GridView 则显示 10 条数据,这样当执行不同的查询时,GridView 时而显示 10 条数据,时而显示 1、2、3、……,9 条数据,GridView 的显示区域随着绑定的数据条数的变化而变化,给人很糟糕的交互体验。

怎么办?如果能够不管绑定的数据条数是多是少,都能始终显示相同的行数就好了,也就是说,当 GridView 绑定的数据条数不满一页时,通过某种方法在 GridView 中添加空行,使 GridView 能够始终显示 PageSize 设置的行数。

 那么怎样添加空白行呢?还是利用 GridView 的 DataBound 事件,在绑定结束后,通过判断 GridView 的 Rows 属性将行数补充到和 PageSize 设置的大小一样,具体代码和效果如下:

    public void gridView_DataBound(object sender, EventArgs e)
    {
        
if (gridView.Rows.Count != 0 && gridView.Rows.Count != gridView.PageSize)
        {
            Control table 
= gridView.Controls[0];
            
if (table != null)
            {
                
for (int i = 0; i < gridView.PageSize - gridView.Rows.Count; i++)
                {
                    
int rowIndex = gridView.Rows.Count + i + 1;
                    GridViewRow row 
= new GridViewRow(rowIndex, -1, DataControlRowType.Separator, DataControlRowState.Normal);
                    row.CssClass 
= (rowIndex % 2 == 0? "alternate" : "item";
                    
for (int j = 0; j < gridView.Columns.Count; j++)
                    {
                        TableCell cell 
= new TableCell();
                        cell.Text 
= "&nbsp;";
 
                       row.Controls.Add(cell);
                    }
                    table.Controls.AddAt(rowIndex, row);
                }
            }
        }
    }

 

需要注意到是:

1. 添加的 GridViewRow 的 RowType 需要设置成 Seperator;

2. 设置空白行内地 TableCell 属性时,应注意 GridView 对应列的 Visible 属性是否设置为 false,和 GridView 的 AutoGenerateCollomn 是否设置为 true,如果是,那么应该对应的做一些处理。

最后的填充了空白行的 GridView 效果如图:

 

posted @ 2008-10-10 14:23 zsi 阅读(159) | 评论 (0)编辑
  2008年10月9日

最近一直在使用 ASP.NET,由于之前大部分工作都是使用 WinForm,对 ASP.NET 的理解还只是停留在表面,所以借着这次机会,深入的研究一下 ASP.NET。原则是尽量使用 ASP.NET 的编程模型和 Web 控件实现业务交互。

GridView 是 ASP.NET 2.0 新增加的 Web 控件,拥有比 DataGrid 更多的扩展和改进。使用 GridView 可以很容易的实现数据分页,但是遗憾的是,在缺省情况下,当仅有一页数据时, GridView 不显示 Pager 分页行,这非常让人郁闷。

在网上搜索了一下解决此问题的有关方法,基本的思路都是使用自定义 Pager,自己实现分页显示。这个思路很好,可是我的应用并不复杂,对分页也没有特殊的要求,只是能显示就好,为了这么点要求重写写那么多代码,太不划算。有没有好的解决方法呢?

还真不是没办法,我发现 GridView 的 Controls 集合中包括了 Header、DataRow、Footer、Pager等等所有可以显示的行,而且不管有没有显示,这些行都包含在 Controls 集合中,只不过仅有一页数据时,Pager 行的 Visible 属性被设置为了 false。既然如此,只要在数据绑定结束后把 Pager 行的 Visible 重新设置为 true 不就解决问题了吗?下面是解决方法:

 

    public static void gridView_DataBound(object sender, EventArgs e)
    {
        
if (gridView.Rows.Count != 0)
        {
            Control table 
= gridView.Controls[0];
            
int count = table.Controls.Count;
            table.Controls[count 
- 1].Visible = true;
        }
    }

 

 

 

posted @ 2008-10-09 10:25 zsi 阅读(123) | 评论 (1)编辑
  2008年9月3日

9月2日Google正式发布了其开源浏览器Chrome的Beta版下载。下载地址

作为开发人员,除了享受Google浏览器带给我们的新鲜感觉和全新体验外,不自觉的会思考其与其他浏览器到兼容性问题,毕竟因为这一点我们已经被IE6、IE7、FireFox搞得焦头烂额了。这还不算刚刚发布Beta2的IE8,现在又来了Chrome,我们不禁要问:Chrome,你行吗?

Google Chrome浏览器借鉴了一些源自Apple WebKit和 Mozilla Firefox的技术,从这一点上来说,Chrome浏览器与FF更接近。经过简单的试用,我们发现Chrome的兼容性很好,无论是Google百度新浪,还是豆瓣鲜果都能够正常显示。而且特别值得一提的是,Chrome的页面加载速度很快,不知道是不是采用独立进程的设计结构有关。

尽管如此,Chrome对一些页面元素的呈现还是显示了独到之处。例如,ASP.NET的Menu对象,无论IE,还是FireFox都是以<table>的方式呈现,如:

Code

 

但是Chrome则不同,Chrome使用了另外一种呈现方式,这应该是Chrome做得特殊处理,如下:

 

Code

 

可以发现Chrome用<div>替换了外层的<table>,使用<span>替换了嵌套的<table>,经过处理后,呈现的代码被大大精简,而且更符合当前div+css的Web设计潮流。

无论如何,Google Chrome更我们带来了完全不同于以往的全新体验,而且目前仅是Beta版本,相信随着Google团队的不断改进,Google Chrome浏览器能够带给我们更多的惊喜。

 

Update:

看到朋友们的回复中提到了Apple的Safari,急忙从Apple网站上下载了最新的Windows版,测试相同的代码,发现Safari的呈现代码和Chrome一样,是不是因为Chrome使用了Apple WebKit的原因?

 

另在ASP.NET论坛有人回复说:

Safari and IE5.0 are considered downlevel browsers by ASP.NET.  By default you won't get rich renderings for either of those. 

ASP.NET将Safari和IE5.0看作低级浏览器,默认情况下使用这两种浏览器不能得到内容丰富的呈现。

 

如果这和Chrome使用了Apple WebKit有关,就好解释了。Chrome浏览器不同于IE、FF的呈现与ASP.NET有关,ASP.NET将Chrome认为是低级浏览器,返回了简单代码,并非浏览器自身做了特殊处理。

 

Update2:

何为downlevel browsers?下层浏览器 
 具有基本特性和功能的早期浏览器。不支持脚本编辑、动态 HTML (DHTML)、DHTML 行为或可扩展标记语言 (XML) 的浏览器通常被视为下层浏览器。

posted @ 2008-09-03 12:08 zsi 阅读(1984) | 评论 (26)编辑
  2008年1月26日
  最近使用UnRARNet 处理 RAR格式的压缩文件。UnRARNet 是由 RARLab 随 unrar.dll 控件一起提供的.net 平台的封装。UnRARNet 使用VB.net语言,应该说对unrar.dll 进行了近乎完美的封装,几乎所有压缩和解压缩工作都完成的很漂亮。

  不过,最近在测试解压缩文件时,遇到一个 System.Runtime.InteropServices.SEHException 异常,异常信息是“外部组件发生异常”。具体位置是在 Decompressor 类的 LoadFileList() 方法中,其中有一句

mRARHandle = RAROpenArchiveEx(uRAREx)

是调用 unrar.dll 外部组件的RAROpenArchiveEx() 方法,异常就发生在这里。

  微软关于SEHExcption的描述中说:

SEHException 类处理从非托管代码引发的、但尚未映射到另一个 .NET Framework 异常的 SEH 错误。SEHException 类还响应 HRESULT E_FAIL(它具有值 0x80004005)。

.NET Framework 经常会遇到非托管 SEH 异常,这些异常自动映射到托管等效项。例如,STATUS_NO_MEMORY SEH 异常自动映射到 OutOfMemoryException 类,而 STATUS_ACCESS_VIOLATION SEH 异常自动映射到 NullReferenceException 类。但是默认情况下,任何未自动映射到特定异常的 SEH 异常将映射到 SEHException 类。



  我用Google搜索网页和Google Groups,都没有发现解决这类问题的方法,看来我足够幸运:),让我先碰到了。

  经过仔细分析,发现问题出在压缩文件的注释上,当注释长度超过一个临界值时,就会发生 SEHException 外部组件异常。RAR 命令指南中提到RAR 压缩包的最大注释长度是 62000 字节,而测试的压缩文件注释只有19000多个字节,完全没有超出最大注释长度。因为注释长度而发生异常似乎没有道理。难道是UnRARNet有问题?

  再回过头看 Decompressor 类,发现在 Init() 方法中有这么一段代码:

        uRAREx.CmtBuf = Space(16384)
        uRAREx.CmtBufSize 
= 16384
        uRAREx.ArcName 
= mRARFile

        uHeaderEx.CmtBuf 
= Space(16384)

  原来,UnRARNet 将默认的注释长度设置成了 16384,难怪解压缩时发生异常了。将注释长度设置成RAR 压缩包的最大注释长度62000,测试通过:)
posted @ 2008-01-26 11:48 zsi 阅读(290) | 评论 (0)编辑
  2007年6月14日
服务器出了些小毛病,总是报告“无法打开到 SQL Server 的连接”,如下

在建立与服务器的连接时出错。在连接到 SQL Server 2005 时,在默认的设置下 SQL Server 不允许进行远程连接可能会导致此失败。 (provider: 命名管道提供程序, error: 40 - 无法打开到 SQL Server 的连接) 

找了一些资料,说什么的都有,有说是因为装了SQL Server 2005的原因,有的说是.NET 2.0的名为LocalSqlServer的内置字符串的原因……但是我的数据库使用的是SQL Server 2000,操作系统是Windows 2003。没有使用到SQL Server 2005,也没有安装过SQL Server 2005,因此,可以排除这些因素。

连接字符串配置都是正确的,之前测试也没有任何问题。server使用的是IP地址,能够Ping通,也不会是计算机名称无法解析的原因。

但是,使用telnet [IP地址] 1433检查时发现,无法连接。根据一些资料的说法,可能和没有安装SQL Server 2000的补丁程序有关。如果版本号低于2039,就有可能会产生上述问题。使用 select @@version 命令查看SQL Server版本发现版本号是194,的确没有安装SP4。

死马且当活马医,抓住一根救命稻草,即使不是这个原因,也要试一试。装上SP4后一试,果然可以正常连接了。不过为什么呢?谁知道?

posted @ 2007-06-14 15:30 zsi 阅读(911) | 评论 (0)编辑
  2005年5月10日

  这两天在写一个小程序,帮助自己做一些碎且杂的工作。程序也没什么复杂的处理,应该很简单就完成了,谁知道却牵出一档子事儿来。到底怎么回事?请听我一一道来。
   写过IO处理程序的人都知道,在VB.NET中,如果只指定了文件名,而没有指定目录,那么当读写文件时,程序从启动目录读取文件。也就是说:.NET默认以程序的启动目录为缺省目录。例如,我的程序放在C:\Test\bin\目录下,程序中有下面一段写文件的代码,方式I:

Dim sw As New StreamWriter(“abc.txt”)
sw.
WriteLine(“ABCDEFG”)
sw.Close()


   在程序运行中,StreamWriter将在C:\Test\bin\目录下创建一个名为abc.txt的文本文件。上面的代码与下面的代码是一样的,方式II:

' 用Application.StartupPath指定目录
Dim sw As New StreamWriter(Application.StartupPath & “\abc.txt”)

   正因为如此,所以在我的小程序里,就是使用方式I。但是问题恰恰出在这里。后来,程序增加了一段代码,其中使用到了OpenFileDialog。就在增加这段代码以后,发现方式I中写abc.txt的代码失效了。每次我使用OpenFileDialog以后,再调用方式I的方法时,总是不能把内容写入C:\Test\bin\目录下的abc.txt文件中。
  经过好多次测试,这个问题依然没有解决,我甚至怀疑这是否是.NET的Bug。前面的测试我都把重点放在了:.NET以程序的启动目录为默认目录。那段代码中。最后一次测试,我转移了目标,我想会不会是写文件的代码有问题呢?带着这个疑问,我把写文件的代码由方式I变成了方式II。测试,通过!
   回过头来再看写文件的这段代码,方式II和方式I的差别在于是否明确指定了目录。如前面所言,.NET默认以程序的启动目录为缺省目录。但是在使用OpenFileDialog的情况下,缺省目录随OpenFileDialog打开的文件目录而变化。缺省目录变成了OpenFileDialog打开的文件所在的目录。如果打开了D:\My Documents\里面的文件,那么缺省目录就成了D:\My Documents\。当调用方式I的代码时,实际是在D:\My Documents\下创建并改写abc.txt文件,C:\Test\bin\abc.txt当然不会有变化。

   总结:在程序中读写文件时应明确指定文件目录,尽量不使用.NET的缺省目录。这在大型系统中尤为重要,因为大系统中往往用到OpenFileDialog。
   另外,还应该注意SaveFileDialog和FolderBrowserDialog。

posted @ 2005-05-10 14:13 zsi 阅读(2264) | 评论 (9)编辑
  2005年4月26日
在Visual Studio .net中创建ASP.NET程序,默认位置为http://localhost/[WebApplicationName],新建立的ASP.NET程序在C盘的C:\Inetpub\wwwroot\建立与程序名称相同的文件夹。新文件的增加和修改也是在这个文件夹中完成的。但是,我不想让ASP.NET程序保存在C盘,原因有二:一,一般C盘是系统盘,我想尽量保持系统盘的干净,不在系统盘创建和删除文件,以免产生系统碎片;二,我的其他程序,例如WinForm程序,都存储在D盘或E盘的某个位置统一管理,我不想让ASP.NET程序例外。怎么办?答案当然是把ASP.NET程序剪切到其他位置保存。

  1. 把ASP.NET程序剪切到新的位置
  2. 打开IIS,新建一个虚拟目录,并将路径指定到ASP.NET程序的新位置。
  3. 打开ASP.NET程序所在的目录,并打开[WebApplicationName].[vbproj].webinfo或[WebApplicationName].[csproj].webinfo文件文件,修改Web节点的URLPath属性为http://localhost/[虚拟目录名称]/ [WebApplicationName].vbproj或http://localhost/[虚拟目录名称]/ [WebApplicationName].csproj。

  OK!大功告成。打开VS.NET试试一切正常。
posted @ 2005-04-26 09:47 zsi 阅读(832) | 评论 (3)编辑
  2005年4月20日
.NET的对象序列化真是好东西,以后要多多利用。

  在使用.NET的序列化时,碰到过一些问题,还好,有丰富的MSDN可查,没有什么过不去的槛。在这里,把使用.NET序列化的经验小结一下。
  1. 基本确认XmlSerializer使用UTF8对序列化的XML文档编码。
  2. XmlSerializer只序列化声明为public的字段,属性,或带返回值的方法。
  3. 如果要序列化属性,那么该属性必须是可读写的,即必须包含get和set,而不能是readonly或writeonly。
  4. XmlAttribute,XmlAnyAttribute不能与XmlElement,XmlText,XmlAnyElement,XmlArray,XmlArrayItem一起使用。
  5. XmlRoot只能用于一个类,XmlType可用于所有类。
  6. 不同的类的XmlType不能相同,除非使用NameSpaces区分。

相关链接:
  ● 在.NET中实现对象序列化
  ● 对象序列化:使用System.Xml.Serialization命名空间
  ● 对象序列化:使用XmlSerializer走完最后一步
posted @ 2005-04-20 15:19 zsi 阅读(973) | 评论 (0)编辑
  2005年4月12日
前面我们已经讲到如何使用System.Xml.Serialization命名空间中的各种特性对要序列化的类进行标记,这里再说一说如何利用XmlSerializer进行对象的序列化。如果对对象序列化缺少了解,可以通过下面两个链接了解:
  ● 在.NET中实现对象序列化
  ● 对象序列化:使用System.Xml.Serialization命名空间

  XmlSerializer的Serialize提供了6个重载方法,实际上属于3种类型。它允许将序列化的结果保存到TextWriter、Stream、XmlWriter对象中。
  正如在对象序列化:使用System.Xml.Serialization命名空间中讲到的,使用XmlTextWriter的好处在于,可以在序列化的XML文件声明中显式的指定encoding,而如果使用的是TextWriter或Stream,那么将按.NET的默认的编码方式序列化(前文已经讲到,可以使用的是UTF8,不过这只是我的猜测)。

  如果要把序列化后的XML文档保存为本地文件,那么使用XmlTextWriter是最好的一种选择。但是,如果要直接传输序列化后的XML文档,那么使用Stream最好。.NET提供了多种Stream的继承类用于在不同场合的Stream处理。要直接传输序列化后的XML文档,MemoryStream是不错的选择。
        Dim mem As New System.IO.MemoryStream
        
Dim serializer As New XmlSerializer(GetType(Order))
        serializer.Serialize(mem, o, ns)

  如果同时希望在序列化的XML文件声明中显式的指定encoding,那么还是可以使用XmlTextWriter的,MemoryStream也不可少。
        Dim mem As New System.IO.MemoryStream
        
Dim writer As New XmlTextWriter(mem, Encoding.UTF8)
        
Dim serializer As New XmlSerializer(GetType(Order))
        serializer.Serialize(writer, o, ns)

  这样,既可以直接使用MemoryStream的ToArray方法以Byte数组进行传输,也可以使用Encoding.UTF8. GetString(mem. ToArray)将Byte数组转换成String类型进行传输。

  一切看起来都很顺利,但是我在使用XmlDocument验证序列化的XML文档时,碰到一个问题。还是使用前文的例子,当我使用下面的代码时,总是产生XmlException异常“根级别上的数据无效”:
        Dim doc As New XmlDocument
        doc.LoadXml(Encoding.UTF8.GetString(mem.ToArray))

  使用Console.WriteLine打印出的结果是下面的样子,很完整的XML文档,只不过前面多了一个“?”:
?<?xml version="1.0" encoding="utf-8"?>
<order id=”123456”> 
    
<orderDate>2005-04-05</orderDate> 
    
<items> 
        
<item> 
            
<name>对象序列化</name> 
        
</item> 
    
</items> 
</order>

  本来以为这个?是包含在序列化的XML文档中的,但是使用String的StartWith方法却找不到这个?。看来它不属于XML文档的一部分。当使用Trim时,一切OK,?没有了,异常没有了:)
        Dim doc As New XmlDocument
        doc.LoadXml(Encoding.UTF8.GetString(mem.ToArray).
Trim())
posted @ 2005-04-12 10:59 zsi 阅读(1894) | 评论 (0)编辑
  2005年4月11日
   要使用.NET进行对象的序列化,必须在解决方案中添加System.Xml的引用,并且在类文件中引入System.Xml.Serialization命名空间。这样就可以在文件中使用序列化所需要的各种特性了。
Imports System.Xml.Serialization

  如果对XML Serialization缺少了解,请首先参考拙文:在.NET中实现对象序列化
<?xml version="1.0" encoding="utf-8"?>
<order id=”123456”> 
    
<orderDate>2005-04-05</orderDate> 
    
<items> 
        
<item> 
            
<name>对象序列化</name> 
        
</item> 
    
</items> 
</order>

   上面的例子包含了典型的XML中常见的各种元素:XML声明、XML根节点、XML节点、XML属性、XML集合。除XML声明外,在.NET中都有对应的特性用于定义这些元素。这些特性包括:XmlRootAttribute、XmlTypeAttribute、XmlElementAttribute、XmlAttributeAttribute、XmlArrayAttribute和XmlArrayItemAttribute。另外,还有两个常用的特性,XmlIgnoreAttribute用于标记在对象序列化时需要被忽略的部分,XmlIncludeAttribute用于标记在生成XML Schema时需要包括的类型。

   如果没有显式地标记任何特性,那么默认类的特性为XmlTypeAttribute、类成员的特性为XmlElementAttribute,且名称为类或类成员的名称。例如:
Public Class Order
        
Public ID As String
        
Public OrderDate As String
   
End Class

  如果不做任何特性标记,使用下面的代码序列化时:
        Dim o As New Order
        
With o
            .ID 
= 123456
            .OrderDate 
= Date.Now.ToShortDateString
        
End With

        
Dim writer As New XmlTextWriter("abc.xml", Encoding.UTF8)
        
Dim serializer As New XmlSerializer(GetType(Order))

        writer.Formatting 
= Formatting.Indented
        serializer.Serialize(writer, o)

  序列化后的XML为:
<?xml version="1.0" encoding="utf-8"?>
<Order xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  
<ID>123456</ID>
  
<OrderDate>2005-4-11</OrderDate>
</Order>

  可以看到,<Order>对应Order类,而<ID>和<OrderDate>分别对应Order类中的字段ID和OrderDate。另外,多了一个XML声明和两个XML命名空间。
  XML声明是.NET自动添加的,但是encoding是在XmlTextWriter中指定的,如果不指定encoding,那么XML声明只有<?xml version="1.0"?>。我使用的是.NET 1.1,这个版本中只支持XML 1.0版本。另外,如果不指定encoding,那么默认的编码可能也是UTF8(没找到相关的资料)。
  .NET默认为Order类添加了XMLSchema和XMLSchema-instance两个W3C的命名空间。该命名空间也可以自己指定,方法是使用XmlSerializer的另一个Serialize方法。
            Dim ns As New XmlSerializerNamespaces
            ns.Add(
"""")

            writer.Formatting 
= Formatting.Indented
            serializer.Serialize(writer, o, ns)

  要将类序列化为XML节点:
    <XmlType("order")> _
    
Public Class Order
        ‘ any code here.
    
End Class

  要将类序列化为XML根节点:
    <XmlRoot("order")> _
    
Public Class Order
        ‘ any code here.
    
End Class

  当在类中同时使用XmlRootAttribute、XmlTypeAttribute时,序列化文档中的类型以XmlRootAttribute为准:
    <XmlRoot("order"), XmlType("anotherOrderName")> _
    
Public Class Order
        ‘ any code here.
    
End Class

  要将类成员序列化为XML节点:
        <XmlAttributeAttribute("id")> _
        
Public ID As String

  要将类成员序列化为XML属性:
        <XmlAttributeAttribute("id")> _
        
Public ID As String

  要将类成员序列化为XML集合:
    <XmlRoot("order"), XmlType("anotherOrderName")> _
    
Public Class Order
        
<XmlAttributeAttribute("id")> _
        
Public ID As String
        
Public orderDate As String
        
<XmlArray("items"), XmlArrayItem("item", Type:=GetType(OrderItem))> _
        
Public Items As New ArrayList
    
End Class


    
<XmlType("orderItem")> _
    
Public Class OrderItem
        
Public Name As String
    
End Class

  使用特性的一个好处是:可以在代码和序列化的文档中使用不同的编码规范

posted @ 2005-04-11 17:30 zsi 阅读(2469) | 评论 (1)编辑