随笔 - 26  文章 - 2  评论 - 23 
  2008年8月11日

用PHP控制缓冲区

PHP4.0 提供了一个输出缓冲函数集合。输出缓冲支持允许你写包裹函数功能压缩缓冲区。在 PHP4 的输出缓冲支持允许 HTML 头信息存 放, 无论 HTML 的正文是否输出。但在 PHP 中,头信息( (header(), content type, and cookies )不 采用缓冲。

在使用 PHP 的过程中不免要使用到 header 和 setcookie 两个函数,这两个函数会发送一段文件头信息给浏览器,但是如果在使用 这两个函数之前已经有了任何输出(包括空输出,比如空格,回车和换行)就会提示出错,提示信息如 下:“Header had all ready send by”!。在 PHP 4.0 里面加入了缓冲区控制的几个函数,使用这些函数可以帮我们解 决很多问题。

函数名称 函数格式 功能 说明

Flush flush()

输出缓冲区内的内容并且删除缓冲区。 这个函数经常使用,效率很高。

ob_start void ob_start(void)

打开输出缓冲区。 当缓冲区激活时,所有来自PHP程序的非文件头信息均不会发送,而是保存在内部缓冲区。为了输出缓冲区的内容,可以使用ob_end_flush()或者使用ob_end_clean()来输出缓冲区的内容。

ob_get_contents string ob_get_contents(void)

返回内部缓冲区的内容。 这个函数会返回当前缓冲区中的内容,如果输出缓冲区没有激活,则返回 FALSE 。

ob_get_length int ob_get_length(void)

返回内部缓冲区的长度。 这个函数会返回当前缓冲区中的长度;和ob_get_contents一样,如果输出缓冲区没有激活。则返回 FALSE。

ob_end_flush void ob_end_flush(void)

发送内部缓冲区的内容到浏览器,并且关闭输出缓冲区。 这个函数发送输出缓冲区的内容(如果有的话)。

ob_end_clean void ob_end_clean(void)

删除内部缓冲区的内容,并且关闭内部缓冲区。 这个函数不会输出内部缓冲区的内容!
用PHP控制缓冲区
用PHP控制缓冲区

ob_implicit_flush void ob_implicit_flush ([int flag])

打开或关闭绝对刷新 使用过Perl的人都知道$|=x的意义,这个字符串可以打开/关闭缓冲区,而ob_implicit_flush函数也和那个一样,默认为关闭缓冲区,打开绝对输出。

二、实例分析:

1、用缓冲区控制的函数防止文件头发送信息出错。

<? //PHP提示符
ob_start(); //打开缓冲区
echo ”Welcome /n”; //输出
header(”location:next.php”); //把浏览器重定向到next.php
?>

如果去掉 ob_start,PHP 就会提示在文件的第4行出错,出错信息为“Header had all ready send by”,但是 加上 ob_start,就不会提示出错,原因是当打开了缓冲区,echo 后面的字符不会输出到浏览器,而是保留在服务器的缓冲区中,直到你使 用 flush 或者 ob_end_flush 才会输出,所以并不会出现文件头已输出的错误!

2、保存输出(这是一个很经典的用途)。

假如你想知道客户端的屏幕输出信息像函数的输出结果等,而且这个输出信息会因客户端的不同而不同。我们可以用函 数 <? phpinfo(); ?> 得到服务器的设置信息,但是如果想要保存 phpinfo() 函数的输出怎么办呢?在没有缓冲区控 制之前,可以说一点办法也没有,但是有了缓冲区的控制,我们可以轻松的解决。

<?
ob_start(); //打开缓冲区
phpinfo(); //使用phpinfo函数
$info=ob_get_contents(); //得到缓冲区的内容并且赋值给$info
$file=fopen(’phpinfo.txt’,'w’); //打开文件phpinfo.txt
fwrite($file,$info); //写入信息到phpinfo.txt
fclose($file); //关闭文件phpinfo.txt
?>

用以上的方法,就可以把不同用户的 phpinfo 信息保存下来,这在以前恐怕没有办法办到!同样,用缓冲区的方法可以保存一般方法难以完成的任务,这其实上就是将一些“过程”转化为“函数”的方法。

posted @ 2008-08-11 22:19 xin478 阅读(50) | 评论 (0)编辑
  2008年7月8日
     摘要: using System;using System.IO;using System.Text;using System.Net;using System.Diagnostics;using System.Net.Sockets;using System.Collections.Generic;using System.Runtime.InteropServices;namespace Socket... 阅读全文
posted @ 2008-07-08 22:08 xin478 阅读(108) | 评论 (0)编辑
  2008年7月4日


得益于mod_aspdotnet.so,这个支持apache2.2的不好找,附上http://www.cnblogs.com/Files/xin478/mod_aspdotnet-2.2.0.2006-setup-r2.rar
有个支持apache2.0的,到处上,可以上网找。
安装后,打开httpd.conf,尾部添加
LoadModule aspdotnet_module "modules/mod_aspdotnet.so"

AddHandler asp.net asax ascx ashx asmx aspx axd config cs csproj licx rem resources resx soap vb vbproj vsdisco webinfo

<IfModule mod_aspdotnet.cpp>
    # Mount the ASP.NET example application
    AspNetMount /wwwroot "f:/wwwroot"
    # Map all requests for /active to the application files
    Alias /wwwroot "f:/wwwroot"
    # Allow asp.net scripts to be executed in the active example
    <Directory "f:/wwwroot">
        Options FollowSymlinks ExecCGI
        Order allow,deny
        Allow from all
        DirectoryIndex index.aspx
    </Directory>
    # For all virtual ASP.NET webs, we need the aspnet_client files
    # to serve the client-side helper scripts.
    AliasMatch /aspnet_client/system_web/(\d+)_(\d+)_(\d+)_(\d+)/(.*) \"C:/Windows/Microsoft.NET/Framework/v$1.$2.$3/ASP.NETClientFiles/$4"
    <Directory "C:/Windows/Microsoft.NET/Framework/v*/ASP.NETClientFiles">
        Options FollowSymlinks
        Order allow,deny
        Allow from all
    </Directory>
</IfModule>

其中,f:/wwwroot 是你机子上网站的根目录,/wwwroot是通过Apache来访问的路径。
运行下测试,
在IIS5.1下,
2000万次整数运算性能      62.5 毫秒
2000万次浮点运算性能      140.625 毫秒

apache2.2下
2000万次整数运算性能      62.5 毫秒
2000万次浮点运算性能      140.625 毫秒

时间一样,据解释是由于IIS和Apache下的ASP.NET都是运行在Common Language Runtime(CLR)的基础上,因此Apache环境下的ASP.NET程序的运行速度不会比在IIS下慢。



posted @ 2008-07-04 15:04 xin478 阅读(1340) | 评论 (14)编辑
  2008年6月28日
试用了一下firefox3.0,感觉相当好,可一时之间还有点不习惯firefox的下载方式,迅雷目前不支持firefox3,只支持firefox2,现在在网上找到一个简单的方法,如下:
1. 打开 about:config
2. 右键点击页面,新建(New)->布尔(Boolean),名称为 extensions.checkCompatibility 值为 false
3. 右键点击页面,新建(New)->布尔(Boolean),名称为 extensions.checkUpdateSecurity 值为 false
然后在迅雷里设置对firefox3.0的支持。
posted @ 2008-06-28 17:11 xin478 阅读(255) | 评论 (2)编辑
  2008年3月11日
==================================================================================
安装MySQL需要下面两个文件:
MySQL-server-4.0.16-0.i386.rpm   
MySQL-client-4.0.16-0.i386.rpm
下载地址为:http://www.mysql.com/downloads/mysql-4.0.html, 打开此网页,下拉网页找到“Linux x86 RPM downloads”项,找到“Server”和“Client programs”项,下载需要的上述两个rpm文件。
rpm文件是Red Hat公司开发的软件安装包,rpm可让Linux在安装软件包时免除许多复杂的手续。该命令在安装时常用的参数是 –ivh ,其中i表示将安装指定的rmp软件包,V表示安装时的详细信息,h表示在安装期间出现“#”符号来显示目前的安装过程。这个符号将持续到安装完成后才停 止。
1)安装服务器端
在有两个rmp文件的目录下运行如下命令:
[root@test1 local]# rpm -ivh MySQL-server-4.0.16-0.i386.rpm
显示如下信息。
warning: MySQL-server-4.0.16-0.i386.rpm: V3 DSA signature: NOKEY, key ID 5072e1f5
Preparing...       ########################################### [100%]
1:MySQL-server     ########################################### [100%]
。。。。。。(省略显示)
/usr/bin/mysqladmin -u root password 'new-password'
/usr/bin/mysqladmin -u root -h test1 password 'new-password'
。。。。。。(省略显示)
Starting mysqld daemon with databases from /var/lib/mysql
如出现如上信息,服务端安装完毕。测试是否成功可运行netstat看Mysql端口是否打开,如打开表示服务已经启动,安装成功。Mysql默认的端口是3306。
[root@test1 local]# netstat -nat
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address      Foreign Address     State   
tcp  0  0 0.0.0.0:3306     0.0.0.0:*      LISTEN   
上面显示可以看出MySQL服务已经启动。
2)安装客户端
运行如下命令:
[root@test1 local]# rpm -ivh MySQL-client-4.0.16-0.i386.rpm
warning: MySQL-client-4.0.16-0.i386.rpm: V3 DSA signature: NOKEY, key ID 5072e1f5
Preparing...    ########################################### [100%]
1:MySQL-client  ########################################### [100%]
显示安装完毕。
用下面的命令连接mysql,测试是否成功。

登录MySQL的命令是mysql, mysql 的使用语法如下:
mysql [-u username] [-h host] [-p[password]] [dbname]
username 与 password 分别是 MySQL 的用户名与密码,mysql的初始管理帐号是root,没有密码,注意:这个root用户不是Linux的系统用户。MySQL默认用户是root,由于 初始没有密码,第一次进时只需键入mysql即可。
[root@test1 local]# mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1 to server version: 4.0.16-standard
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql>
出现了“mysql>”提示符,恭喜你,安装成功!
增加了密码后的登录格式如下:
mysql -u root -p
Enter password: (输入密码)
其中-u后跟的是用户名,-p要求输入密码,回车后在输入密码处输入密码。

注意:这个mysql文件在/usr/bin目录下,与后面讲的启动文件/etc/init.d/mysql不是一个文件。
===========================================================================================

1.apache

  在如下页面下载apache的for Linux 的源码包

  http://www.apache.org/dist/httpd/;

  存至/home/xx目录,xx是自建文件夹,我建了一个wj的文件夹。

  命令列表:

  cd /home/wj

  tar -zxvf httpd-2.0.54.tar.gz

  mv httpd-2.0.54 apache

  cd apache

  ./configure --prefix=/usr/local/apache2 --enable-module=so

  make

  make install

  安装apache至/usr/local/apache 并配置apache支持dso方式

  2.php

  在如下页面下载php的for Linux 的源码包

  http://www.php.net/downloads.php ;

  存至/home/wj目录

  命令列表:

  cd /home/wj

  tar -zxvf php-5.0.4.tar.gz

  mv php-5.0.4 php

  cd php

  ./configure --prefix=/usr/local/php5 --with-apxs2=/usr/local/apache2/bin/apxs --with-config-file-path=/usr/local/lib --enable-track-vars --with-xml --with-MySQL

  make

  make install

  其中apache和mysql是根据你安装的目录名变,我的是 =/usr/local/apache2/bin/apxs 和MySQL

  cp php.ini-dist /usr/local/lib/php.ini

  以dso方式安装php至/usr/local/php 设置配置文件目录为/usr/local/lib 开启mysql,xml支持

  3.配置

  vi /usr/local/apache/conf/httpd.conf

  对apache做如下配置

  #将ServerAdmin mailto:linux@linuxidc.com一行改为您的邮箱地址

  #DocumentRoot "/home/httpd/html/" 此处为html文件主目录

  # 同上

  #Options FollowSymLinks MultiViews 为安全起见,去掉"Indexes"

  #

  # DirectoryIndex default.php default.phtml default.php3 default.html default.htm

  #

  #设置apache的默认文件名次序

  #AddType application/x-httpd-php .php .phtml .php3 .inc

  #AddType application/x-httpd-php-source .phps

  #设置php文件后缀

  存盘退出

  vi /usr/local/lib/php.ini

  #register-golbals = On

  存盘退出

  4.启动服务

  /usr/local/apache/bin/apachectl start

  5.测试

  然后写个php测试页info.php:内容如下

  〈?php

  phpinfo();

  ?>

  正常的话,应该能看到php的信息了,恭喜你的Apche+Mysql+PHP安装成功。

  6、apache自动启动- -

  下面用自启动apache为例;

  自启动脚本:

  /usr/local/apache/bin/apachectl start

  文件位于/etc/rc.d/init.d下,名为apached,注意要可执行.

  #chmod +x /etc/rc.d/init.d/apached //设置文件的属性为可执行

  #ln -s /etc/rc.d/init.d/apached /etc/rc3.d/S90apache //建立软连接,快捷方式

  #ln -s /etc/rc.d/init.d/apached /etc/rc0.d/K20apache

======================================================================================


apache2.2配置好httpd.conf后,无论访问什么路径都出现 403 forbidden的提示,一般有两种可能性。

一种可能性是DocumentRoot选项的设置,如果在安装好apache2后修改了该选项,并且忘记了配置该新目录的访问权限就会出现这样的情况。比如apache2安装好后默认的参数如下
DocumentRoot /usr/local/www/data

<directory "/usr/local/www/data">
    Options Indexes FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
</directory>

我们常常会重新指定web文件存放的目录,比如设定
DocumentRoot /var/www
这时往往会忽略了对后面的Directory 项的修改,必须将里面的路径同时修改为 /var/www才行,否则将会访问所有目录都出现 403 forbidden错误。

另外一种可能性出现在我们配置了不同的VirtualHost,并且有某个VirtualHost的DocumentRoot不在全局的 DocumentRoot目录下,这时必须在全局种单独增加对该目录的Directory 项进行设置,否则该VirtualHost下的所有访问均会出现403 forbidden错误。

这个问题是因为Apache2对于权限和安全的更高要求,对分布在不同磁盘上的目录文件进行严格管理,我们进行web规划的时候必须注意这一点。
posted @ 2008-03-11 15:54 xin478 阅读(147) | 评论 (0)编辑
  2008年2月20日

对于数据绑定控件的开发,其主要的要点如下:

1、  定义控件实现INamingContainer接口;

 

2、  对于基于模板的数据绑定控件还需要实现模板属性;

 

3、  实现有关数据绑定的内容,包括建立DataSource和DataBind方法等;

 

4、  使用数据源或者ViewState数据创建子控件层次结构。

 

以上四点是开发基于模板的数据绑定控件的基本要点,在VS.NET中提供的比较典型的模板数据绑定控件就是DATAGRID了,下面我们来实际做一个例子实现类似与DATAGRID的模板化绑定的效果。

 

例子共包括两个主要文件:实现模板容器的Item.cs文件和实现控件主体的DataBindTmp.cs文件,两个文件的代码如下:

Item.cs
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;

namespace Hdkj.Ying
{
 /// <summary>
 /// Item 的摘要说明。
 /// </summary>
 public class ItemTmp : System.Web.UI.WebControls.TableCell,INamingContainer
 {
  private object _dataItem;

  public ItemTmp(object dataItem)
  {
   _dataItem = dataItem;
  }

  public override ControlCollection Controls
  {
   get
   {
    EnsureChildControls();
    return base.Controls;
   }
  }

  public object DataItem
  {
   get{return _dataItem;}
   set{_dataItem = value;}
  }
 }
}

DataBindTmp.cs
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Collections;

namespace Hdkj.Ying
{
 [
 DefaultProperty("DataSource"),
 ParseChildren(true)
 ]
 public class DataBindTmp : System.Web.UI.WebControls.WebControl,INamingContainer
 {
  #region 定义变量
  private object _dataSource;
  private ITemplate _itemTemplate;
  private ITemplate _headerTemplate;
  
  #endregion

  #region 定义属性
  #region 属性ItemTemplate
  [
  Browsable(true),
  DefaultValue(null),
  PersistenceMode(PersistenceMode.InnerProperty),
  TemplateContainer(typeof(ItemTmp))
  ]
  public virtual ITemplate ItemTemplate
  {
   get
   {
    return _itemTemplate;
   }
   set
   {
    _itemTemplate = value;
   }
  }
  #endregion

  #region 属性HeaderTemplate
  [
  Browsable(true),
  DefaultValue(null),
  PersistenceMode(PersistenceMode.InnerProperty),
  TemplateContainer(typeof(ItemTmp))
  ]
  public virtual ITemplate HeaderTemplate
  {
   get
   {
    return _headerTemplate;
   }
   set
   {
    _headerTemplate = value;
   }
  }
  #endregion

  #region 属性DataSource
  [
  Bindable(true),
  Description("获取或者设置数据源"),
  Category("Data"),
  DefaultValue(null),
  DesignerSerializationVisibility(DesignerSerializationVisibility.Content)
  ]
  public virtual object DataSource
  {
   get
   {
    return _dataSource;
   }
   set
   {
    if(value == null || value is IEnumerable || value is IListSource)
    {
     _dataSource = value;
    }
    else
    {
     throw new ArgumentException();
    }
   }
  }
  #endregion

  #region 属性DataMember
  [
  Category("Data"),
  DefaultValue(""),
  Description("获取或者设置绑定的数据成员.")
  ]
  public virtual string DataMember
  {
   get
   {
    string s = (string)ViewState["DataMember"];
    return (s == null) ? string.Empty:s;
   }
   set
   {
    ViewState["DataMember"] = value;
   }
  } 
  #endregion
  #endregion

  #region 实现控件呈现
  //重写CreateChildControls
  protected override void CreateChildControls()
  {  
   Controls.Clear();
   if ((ViewState["ItemCount"]) != null)
   {
    CreateControlHierarchy(false);
   }
  }

  //使用数据源或者ViewState创建控件层次结构
  protected virtual void CreateControlHierarchy(bool useDataSource)
  {
   IEnumerable dataSource = null;
   int itemCount = 0;  

   if (useDataSource)
   {
    dataSource = GetDataSource();
   }
   else
   {
    dataSource = new object[(int)ViewState["ItemCount"]];
   }

   if (dataSource != null)
   {
    Table table = new Table();
    table.Attributes.Add("cellpadding","0");
    table.Attributes.Add("cellspacing","0");   
    Controls.Add(table);

    ItemTmp headerItem = new ItemTmp(null);
    if(_headerTemplate != null)
    {
     TableRow headerRow = new TableRow();
     table.Rows.Add(headerRow);
    
     ITemplate template = _headerTemplate;
     if(template != null)
     {
      template.InstantiateIn(headerItem);
     }
     headerRow.Cells.Add(headerItem);
    }
   
    IEnumerator dataItems = dataSource.GetEnumerator();
   
    while(dataItems.MoveNext())
    {
     TableRow itemRow = new TableRow();
     table.Rows.Add(itemRow);

     ItemTmp item = new ItemTmp(dataItems.Current);    
     
     ITemplate template = _itemTemplate;
     if(template != null)
     {      
      _itemTemplate.InstantiateIn(item);
     }     
     itemRow.Cells.Add(item);
     if(useDataSource)
     {
      item.DataBind();
     }
     itemCount++;
    }
   }

   if (useDataSource)
   {
    ViewState["itemCount"] = itemCount;   
   }
  }
  #endregion

  #region 实现数据绑定及相关
  public override void DataBind()
  {
   base.OnDataBinding(EventArgs.Empty);
   Controls.Clear();
   ClearChildViewState();
   TrackViewState();
   CreateControlHierarchy(true);
   ChildControlsCreated = true;
  }
 
  //获取数据源,将数据源中的数据都转换为IEnumerable类型
  protected virtual IEnumerable GetDataSource()
  {
   if (_dataSource == null)
   {
    return null;
   }           
   IEnumerable resolvedDataSource = _dataSource as IEnumerable;
   if (resolvedDataSource != null)
   {
    return resolvedDataSource;
   }
   IListSource listSource = _dataSource as IListSource;
   if (listSource != null)
   {
    IList memberList = listSource.GetList();

    if (listSource.ContainsListCollection == false)
    {
     return (IEnumerable)memberList;
    }
    ITypedList typedMemberList = memberList as ITypedList;
    if (typedMemberList != null)
    {
     PropertyDescriptorCollection propDescs = typedMemberList.GetItemProperties(new PropertyDescriptor[0]);
     PropertyDescriptor memberProperty = null;
                   
     if ((propDescs != null) && (propDescs.Count != 0))
     {
      string dataMember = DataMember;

      if (dataMember.Length == 0)
      {
       memberProperty = propDescs[0];
      }
      else
      {
       memberProperty = propDescs.Find(dataMember, true);
      }

      if (memberProperty != null)
      {
       object listRow = memberList[0];
       object list = memberProperty.GetValue(listRow);

       if (list is IEnumerable)
       {
        return (IEnumerable)list;
       }
      }
      throw new Exception("未能找到有效的DataMember.");
     }

     throw new Exception("数据源中不包含任何数据对象.");
    }
   }
   return null;
  }       
 
  private PropertyDescriptor[] GetColumnPropertyDescriptors(object dataItem)
  {
   ArrayList props = new ArrayList();
   PropertyDescriptorCollection propDescs = TypeDescriptor.GetProperties(dataItem);
   foreach (PropertyDescriptor pd in propDescs)
   {
    Type propType = pd.PropertyType;
    TypeConverter converter = TypeDescriptor.GetConverter(propType);
    if ((converter != null) && converter.CanConvertTo(typeof(string)))
    {
     props.Add(pd);
    }
   }
   props.Sort(new PropertyDescriptorComparer());
   PropertyDescriptor[] columns = new PropertyDescriptor[props.Count];
   props.CopyTo(columns, 0);
   return columns;
  }
       
  private sealed class PropertyDescriptorComparer : IComparer
  {
   public int Compare(object x, object y)
   {
    PropertyDescriptor p1 = (PropertyDescriptor)x;
    PropertyDescriptor p2 = (PropertyDescriptor)y;
    return String.Compare(p1.Name, p2.Name);
   }
  }
  #endregion
 }
}

典型应用代码如下:
private void Page_Load(object sender, System.EventArgs e)
  {
   // 在此处放置用户代码以初始化页面
   OleDbConnection oleConn = new OleDbConnection(Application["Data"].ToString());
   OleDbDataAdapter oleApt = new OleDbDataAdapter("select *from htgk",oleConn);
   DataSet dsTmp = new DataSet();
   oleApt.Fill(dsTmp,"htgk");
   DataView dvTmp = dsTmp.Tables[0].DefaultView;

   DataBindTmp2.DataSource = dvTmp;
   DataBindTmp2.DataBind();
  }

 

通过上述即实现了一个比较简单的模板化数据绑定控件,一个比较有实用价值的应用是展示图书信息的应用。具体的代码编制还需要根据实际应用的需要进行调整。

posted @ 2008-02-20 22:09 xin478 阅读(53) | 评论 (0)编辑

在dotNET中,DataGrid, Repeater等控件的数据源只需要是一个从IEnumerable接口派上的对象就可以进行绑定了,所以可以将DataTable, DataView等作为数据源。

在面向对象开发的中,一般我们会返回一个对象集合而不是一个DataTable, 而dotNet中的集合对象(如Array, ArrayList等)都实现了IEnumerable接口,故而也可以直接将对象集合赋值给数据控件的数据源。

在本文中重点要讨论是如何定制绑定的属性,如标题等。

当不需要在同一页面修改数据时(我称之为原地编辑),我一般选择Repeater来显示数据,如果要原地编辑数据,则使用DataList,因为它们给予了页面和代码最大程度上的分离,这对于美工来说是非常重要的。下面先给出示例代码(部分)

//*** Product.aspx ***

<table>
<asp:Repeater id="rptProduct" runat="server">
   <headertemplate>
      <tr>
         <td><asp:Label id="ProductId" runat="server"/></td>
         <td><asp:Label id="Name" runat="server"/></td>
         <td><asp:Label id="UnitPrice" runat="server"/></td>
      </tr>
   </headertemplate>
   <itemtemplate>
      <tr>
         <td><asp:Label id="ProductId" runat="server"/></td>
         <td><asp:Label id="Name" runat="server"/></td>
         <td><asp:Label id="UnitPrice" runat="server"/></td>
      </tr>
   </itemtemplate>
</asp:Repeater>
</table>
这里定义了标题模板和项目模板, Label控件的值在后台代码中进行设置, 注意,控件的名称应取对象的属性名。

//*** Product.cs ***

public class Product {
   public Product() { }

   [Caption("产品Id")]
   public int ProductId
   {
      get { return productId; }
      set { productId = value; }
   }
   private int productId;

   [Caption("名称")]
   public string Name
   {
      get { return name; }
      set { name = value; }
   }
   private string name;

   [Caption("单价")]
   public decimal UnitPrice
   {
      get { return unitPrice; }
      set { unitPrice = value; }
   }
   private decimal unitPrice;

} //class Product 产品业务对象

//*** CaptionAttribute.cs ****

public class CaptionAttribute : Attribute {
   public CaptionAttribute( string text ) {
      this.text = text;
   }

   public string Text
   {
      get { return text; }
   }
   private string text;

} //class CaptionAttribute 标题特性对象
在这里简单的传入一个标题文本,如果需要多语言支持,应该传入一个资源Id,然后读取对应的资源字符串。

//*** Product.aspx.cs ***

void Page_Load( object sender, EventArgs e ) {
   if ( !IsPostBack ) {
      rptProduct.DataSource = GetProducts(); // GetProducts返回Product对象的集合,这里省略.
      rptProduct.DataBind();
   }
}

void rptProduct_ItemDataBound( object sender, RepeaterItemEventArgs e ) {
   if ( ListItemType.Header == e.Item.ItemType )
      ValueHelper.SetCaption( e.Item, typeof(Product) );
   else if ( ListItemType.Item == e.Item.ItemType ||
         ListItemType.AlternatingItem == e.Item.ItemType )
   {
      Product p = (Product)e.Item.DataItem;
      ValueHelper.SetData( e.Item, p );
   }
}


//*** ValueHelper.cs ***

public class ValueHelper {

   public static void SetCaption( Control container, Type type ) {
      foreach ( Control c in container.Controls ) {
         if ( c is Label ) {
            Label label = (Label)c;
            if ( !IsEmpty(label.Text) ) {
               PropertyInfo pi = type.GetProperty( label.ID );
               label.Text = label.Id // 默认的标题
               if ( pi != null ) {
                  object[] attributes = pi.GetCustomAttributes( typeof(CaptionAttribute), true );
                  if ( attributes.Length > 0 )
                      label.Text = ((CaptionAttribute)attributes[0]).Text;
               }
            } //end if ( IsEmpty )
         }
         else if ( c.HasControls() ) {
            SetCaption( c, type );
         }
      } //end foreach ( container.Controls )
   }
   // 遍历所有的Label控件,然后根据其ID值在类类型中查找属性,再在属性上取得定制的Caption特性。

   public static void SetData( Control container, Object obj ) {
      foreach ( Control c in container.Controls ) {
         if ( c is Label || c is TextBox )
            SetControlData( c, obj, c.ID );
         else if ( c.HasControls() )
            SetData( c, obj );
      }
   }
   // 遍历所有的Label和TextBox控件,然后设置其值。

   private static void SetControlData( Control c, Object obj, string propertyName ) {
      if ( c == null || obj == null ) return;
      PropertyInfo pi = obj.GetType().GetProperty( propertyName );
      if ( pi != null ) {
         object value = pi.GetValue( obj, null );
         if ( value != null ) {
            if ( c is Label )
               ((Label)c).Text = value.ToString();
            else if ( c is TextBox )
               ((TextBox)c).Text = value.ToString();
         }
      }
   }
   // 通过反射取得对象属性的值,然后赋与控件。这里还可以根据值的类型就值进行格式化,这个留给大家自由发挥了。

} //class ValueHelper

通过定制特性我们不难扩展出像FormattedAttribute, VisiableAttribute, WidthAttribute等特性来。

另一种可行的方案是定义一个对象表示->业务对象的映射文件,就像业务对象->数据库映射那样,这样的话应该能更好的分离表示层和业务层,有兴趣的朋友不妨试一下。

posted @ 2008-02-20 22:08 xin478 阅读(41) | 评论 (0)编辑
  2008年2月18日

任何控件都可以包含子控件。一个控件支持模板,其实就是在往它里面加子控件。模板是用什么形式在控件内公开的呢?想一想,我们用一个一般的控件都可以直接用标记来指定属性,而模板也是使用标记来操作。使用模板的时候,就是用标记的方法给模板赋值,根据“任何控件都可以包含子控件”,所以模板里也可以再包含控件。因此,模板在控件定义中就表现为属性。我们的标记都是用xml形式呈现的,因此,使用模板实际上就是给控件的某个属性赋于xml标记这样的值。
上面的话是否可以看懂呢?看下面的这段标记。
<cc1:TemplateControl id=”tem” runat=”server”>
<ITEMTEMPLATE>
<asp:Button id=”Button1″ Text=”<%# Container.Text%>” Runat=”server”>
</asp:Button>
<asp:Label ID=”Label1″ Text=”<%# Container.Text%>” Runat=”server”></asp:Label><br>
<div>hello world !</div>
</ITEMTEMPLATE>
</cc1:TemplateControl>
这是一个支持模板及数据绑定的自定义控件。它是这样完成的。
ITEMTEMPLATE是一个ITemplate类型的属性,只要对外公开了此属性,就可以使控件支持模板。
//模板
private ITemplate itemTemplate;

public ITemplate ItemTemplate
{
get{ return this.itemTemplate; }
set{ this.itemTemplate=value; }
}

设置好属性后,还需要给控件加一个类级别的[ParseChildren(true)]特性,用来指明将控件内的XML标记元素视为属性处理,这样就可以在<ITEMTEMPLATE>标签内定义自己的模板。
作完这些后,下一步需要做的就是要将模板做为子控件加入到控件中。
protected override void CreateChildControls()
{
if(this.itemTemplate!=null)
{
//当由类实现时,定义子控件和模板所属的 Control 对象。然后在内联模板中定义这些子控件。
//这里把容器控件指定为代表控件本身的this
this.itemTemplate.InstantiateIn(this);
}
else
this.Controls.Add(new LiteralControl(”no itemtemplate!”));
base.CreateChildControls();
}
通过重写CreateChildControls方法来完成。
只有调用DataBind,才可能将数据绑定到子控件。因此我们还需要重写OnDataBinding
protected override void OnDataBinding(EventArgs e)
{
//确定服务器控件是否包含子控件。如果不包含,则创建子控件。
this.EnsureChildControls();
base.OnDataBinding (e);
}

到这里,一个简单的支持模板的控件就算完成了,可以自己把上面的东西组合起来看看效果。
我们需要模板一般都是要进行数据绑定的,接下来看看怎么实现。
<%# Container.Text%>
上面是一般的绑定表达式,可以看到,其实就是调用了一个对象的属性,其中Container用来表示乘放模板的容器,而Text正是该容器的属性。
一般用TemplateContainer特性来指定容器的类型,像这样:
[TemplateContainer(typeof(ContainerControl)),Browsable(false)]
public ITemplate ItemTemplate
{ //… }
ContainerControl就是一个容器控件,其定义如下
public class ContainerControl : Control,INamingContainer
{
private string text;

public string Text
{
get{ return this.text; }
}

public ContainerControl(string text)
{
this.text=text;
}
}

注意,这是一个控件,只是没有向页面呈现而已。实际上,它的作用就是用来乘放模板。这样,我们创建模板时就改成了这样子
ContainerControl cc=new ContainerControl(text);
this.itemTemplate.InstantiateIn(cc);
this.Controls.Add(cc);

下面是这个控件的完整的代码 :)
using System;
using System.Web.UI;
using System.ComponentModel;

namespace CC
{
/// <summary>
/// 模板练习
/// </summary>

//分析控件内的xml元素标记
[ParseChildren(true)]
public class SimpleTemplate : Control,INamingContainer
{
//模板
private ITemplate itemTemplate;

//指定存放模板的容器控件
[TemplateContainer(typeof(ContainerControl)),Browsable(false)]
public ITemplate ItemTemplate
{
get{ return this.itemTemplate; }
set{ this.itemTemplate=value; }
}

//辅助进行绑定的属性
private string text;

public string Text
{
get{ return this.text; }
set{ this.text=value; }
}


/// <summary>
/// 创建子控件
/// </summary>
protected override void CreateChildControls()
{
if(this.itemTemplate!=null)
{
//使用得到的属性来创建容器控件
ContainerControl cc=new ContainerControl(this.text);
//将模板添加到专门的容器中
this.itemTemplate.InstantiateIn(cc);
//将容器加到父控件中
this.Controls.Add(cc);
}
else
this.Controls.Add(new LiteralControl(”no itemtemplate!”));
base.CreateChildControls();
}

/// <summary>
/// 在这里进行检查并创建模板
/// </summary>
/// <param name=”e”></param>
protected override void OnDataBinding(EventArgs e)
{
//确定服务器控件是否包含子控件。如果不包含,则创建子控件。
this.EnsureChildControls();
base.OnDataBinding (e);
}

}

}

具体使用的页面,.aspx页上的标记就像我们一开始那样,.cs里的代码为
if(!this.IsPostBack)
{
this.tem.Text=”hello world !”;
this.tem.DataBind();
}
在这里,就算postback了,显示的页面还是没有改变,这主要是因为模板内的控件各自维持自己的状态,了解这一点很重要,因为接下来支持数据绑定时需要使用这一点。
还有一点,如果把DataBind注释掉了,那Text就不会绑定到模板上。你可以实验一下把EnsureChildControls放到其他方法中(比如Render什么的),结果都是如此。

posted @ 2008-02-18 21:17 xin478 阅读(73) | 评论 (0)编辑
  2008年1月31日


JavaScript提供了一个RegExp对象来完成有关正则表达式的操作和功能,每一条正则表达式模式对应一个RegExp实例。有两种方式可以创建RegExp对象的实例。

      使用RegExp的显式构造函数,语法为:new RegExp("pattern"[,"flags"])。

      使用RegExp的隐式构造函数,采用纯文本格式:/pattern/[flags]。

pattern部分为要使用的正则表达式模式文本,是必须的。在第一种方式中,pattern部分以JavaScript字符串的形式存在,需要使用双引号或单引号括起来;在第二种方式中,pattern部分嵌套在两个“/”之间,不能使用引号。

flags部分设置正则表达式的标志信息,是可选项。如果设置flags部分,在第一种方式中,以字符串的形式存在;在第二种方式中,以文本的形式紧接在最后一个“/”字符之后。flags可以是以下标志字符的组合。

      g是全局标志。如果设置了这个标志,对某个文本执行搜索和替换操作时,将对文本中所有匹配的部分起作用。如果不设置这个标志,则仅搜索和替换最早匹配的内容。

      i是忽略大小写标志。如果设置了这个标志,进行匹配比较时,将忽略大小写。

      m是多行标志。如果不设置这个标志,那么元字符“^”只与整个被搜索字符串的开始位置相匹配,而元字符“$”只与被搜索字符串的结束位置相匹配。如果设置了这个标志,“^”还可以与被搜索字符串中的“\n”或“\r”之后的位置(即下一行的行首)相匹配,而“$”还可以与被搜索字符串中的“\n”或“\r”之后的位置(即下一行的行尾)相匹配。

代码8.1是一个创建正则表达式的例子。

代码8.1   创建正则表达式:8.1.htm

<html>

<head>

<title>创建正则表达式 </title>

<script language = "JavaScript">

       var myString="这是第一个正则表达式的例子";

       var myregex = new RegExp("一个");   // 创建正则表达式

       if (myregex.test(myString)){

            document.write("找到了指定的模式!");

       }

       else{

            document.write("未找到指定的模式。");

       }

</script>

</head><body></body>

</html>

上面代码的运行结果如图8.1所示。

由于JavaScript字符串中的“\”是一个转义字符,因此,使用显式构造函数创建RegExp实例对象时,应将原始正则表达式中的“\”用“\\”替换。例如,在代码8.2中的两条语句是等价的。

代码8.2   转义字符中的“\”:8.2.htm

<script language="javascript">

       var re1 = new RegExp("\\d{5}");

       var re2 = /\d{5}/;

       alert("re1="+re1+"\nre2="+re2);

</script>

程序显示结果如图8.2所示。可以看出,两者结果相同。

       

由于正则表达式模式文本中的转义字符也是“\”,如果正则表达式中要匹配原义字符“\”,在正则表达式模式文本中要以“\\”来表示,当使用显式构造函数的方式创建RegExp实例对象的时候,就需要使用“\\\\”来表示原义字符“\”。

var re = new RegExp(\\\\)。

8.4   RegExp对象的属性
RegExp对象的属性分为静态属性和实例属性。下面分别进行介绍。

8.4.1   静态属性
(1)index属性。是当前表达式模式首次匹配内容的开始位置,从0开始计数。其初始值为-1,每次成功匹配时,index属性都会随之改变。

(2)input属性。返回当前所作用的字符串,可以简写为$_,初始值为空字符串""。

(3)lastIndex属性。是当前表达式模式首次匹配内容中最后一个字符的下一个位置,从0开始计数,常被作为继续搜索时的起始位置,初始值为-1,表示从起始位置开始搜索,每次成功匹配时,lastIndex属性值都会随之改变。

(4)lastMatch属性。是当前表达式模式的最后一个匹配字符串,可以简写为$&。其初始值为空字符串""。在每次成功匹配时,lastMatch属性值都会随之改变。

(5)lastParen属性。如果表达式模式中有括起来的子匹配,是当前表达式模式中最后的子匹配所匹配到的子字符串,可以简写为$+。其初始值为空字符串""。每次成功匹配时,lastParen属性值都会随之改变。

(6)leftContext属性。是当前表达式模式最后一个匹配字符串左边的所有内容,可以简写为$`(其中“'”为键盘上“Esc”下边的反单引号)。初始值为空字符串""。每次成功匹配时,其属性值都会随之改变。

(7)rightContext属性。是当前表达式模式最后一个匹配字符串右边的所有内容,可以简写为$’。初始值为空字符串""。每次成功匹配时,其属性值都会随之改变。

(8)$1…$9属性。这些属性是只读的。如果表达式模式中有括起来的子匹配,$1…$9属性值分别是第1个到第9个子匹配所捕获到的内容。如果有超过9个以上的子匹配,$1…$9属性分别对应最后的9个子匹配。在一个表达式模式中,可以指定任意多个带括号的子匹配,但RegExp对象只能存储最后的9个子匹配的结果。在RegExp实例对象的一些方法所返回的结果数组中,可以获得所有圆括号内的子匹配结果。

8.4.2   实例属性
(1)global属性。返回创建RegExp对象实例时指定的global标志(g)的状态。如果创建RegExp对象实例时设置了g标志,该属性返回True,否则返回False,默认值为False。

(2)ignoreCase属性。返回创建RegExp对象实例时指定的ignoreCase标志(i)的状态。如果创建RegExp对象实例时设置了i标志,该属性返回True,否则返回False,默认值为False。

(3)multiLine属性。返回创建RegExp对象实例时指定的multiLine标志(m)的状态。如果创建RegExp对象实例时设置了m标志,该属性返回True,否则返回False,默认值为False。

(4)source属性。返回创建RegExp对象实例时指定的表达式文本字符串。

8.5   RegExp对象的方法
RegExp对象的常用方法有test、exec和compile,本节介绍这些方法的功能和用法。最后,对RegExp对象的属性和方法进行一个综合举例。

8.5.1   test方法
语法格式为test(str)。该方法检查一个字符串中是否存在创建RegExp对象实例时所指定的表达式模式,如果存在就返回True,否则返回False。如果找到匹配项,则会更新RegExp对象中的有关静态属性,以反映匹配情况。关于该方法的使用,后面的8.10节中会经常用到,这里不再单独举例。

8.5.2   exec方法
语法格式为exec(str)。该方法使用创建RegExp对象实例时所指定的表达式模式对一个字符串进行搜索,并返回一个包含搜索结果的数组。

      如果为正则表达式设置了全局标志(g),可以通过多次调用exec和test方法在字符串中进行连续搜索,每次都是从RegExp对象的lastIndex属性值指定的位置开始搜索字符串。

      如果没有设置全局标志(g),则exec和test方法忽略RegExp对象的lastIndex属性值,从字符串的起始位置开始搜索。

如果exec方法没有找到匹配,返回值为null;如果找到匹配,则返回一个数组,并更新RegExp对象中有关静态属性以反映匹配情况。返回数组中的元素0包含了完整的匹配结果,而元素1~n依次是表达式模式中定义的各个子匹配的结果。

exec方法返回的数组有3个属性,分别是input、index和lastIndex。

      input属性是整个被搜索的字符串。

      index属性是指匹配在整个被搜索字符串中的位置。

      lastIndex属性是指匹配的子字符串的最后一个字符的下一个字符位置。

代码8.3是对该方法的应用举例。

代码8.3   exec()方法应用:8.3.htm

<html>

<head>

<title>exec()方法应用</title>

<script language = "JavaScript">

    var myString="aaa 111 bbb 222 ccc 1111 222ddd";

    var regex = /111/;     //创建正则表达式对象

    var array=regex.exec(myString);

    if (array){

          var str="找到了匹配子串!"+"\n返回数组的值为:"+array+"\n数组元素个数:"

                          +array.length+"\n被搜索的字符串为:"+array.input

                          +"\n匹配子串的开始位置为:"+array.index

                          +"\n匹配子串后面第一个字符的位置为:"+regex.lastIndex;

                  alert(str);

          }

          else{

                  alert("未找到匹配子串!!");

          }

</script>

<body></body>

</html>

上面代码的运行结果如图8.3所示。


图8.3   运行结果

8.5.3   compile方法
语法格式为compile("pattern"[,"flags"])。该方法可以更换RegExp对象实例所使用的表达式模式,并将新的表达式模式编译为内部格式,从而使以后的匹配过程执行更快。如果要在循环中重复使用某个表达式,对其进行编译将使执行加速。但是,如果在程序中使用了任何其他表达式模式后,再使用原来编译过的表达式模式,则这种编译毫无   益处

posted @ 2008-01-31 16:03 xin478 阅读(48) | 评论 (0)编辑
  2008年1月22日
今天安装了cvsNT 2.5.03.2382,整个过程很简单也很顺利。安装完成后启动Control Panel,建了一个Repository:name为/cvsRoot。默认情况下windows的管理员就是Repository的管理员,可以用 windows的帐户登陆cvs。然后,就想为repository添加更多的用户。有一种简单的方法,就是添加windows的用户,因为 windows的用户也是cvs的帐户。但是,想用cvsNT自己的用户管理方法,于是:
     cmd ,进入Dos。
     set cvsroot=:pserver:administrator@127.0.0.1:/cvsRoot
     cvs login
提示:
      Logging in to :pserver:
administrator @127.0.0.1:2401:/cvsRoot
      CVS Password:_
      输入密码后,登陆成功。
      然后,
      cvs passwd -a test1   //添加用户test1
提示:
       Adding user test1@127.0.0.1
       New Password:_
       为test1用户创建新密码,后在CVSROOT文件夹下生成一个passwd文件,里面放的就是repository用户的登陆信息,包括刚刚注册的用户名test1和加密后的密码。

        既然,添加用户成功了。那接下来就用test1登陆试试了。于是,
      
set cvsroot=:pserver:test1@127.0.0.1:/cvsRoot
      
cvs login
       输入密码后,原以为应该登陆成功,却出现了:
       Fatal error, aborting.
       cvs [login aborted]: test1: no such user
       真是莫名其妙,研究了一个早上都没有结果,后来baidu到篇文章
登陆时出现"no such user"的原因之一     ,对照了一下关键问题出现在cvsNT的Server Settings中,见下图:
 
   

    Run as 选项为(client user)将其改为一个管理员帐户:
   
    

     问题解决,希望同样碰到这个问题的同学能不再烦恼。
posted @ 2008-01-22 11:32 xin478 阅读(69) | 评论 (0)编辑