asp.net treeview 使用集锦

说明:本文在http://blog.csdn.net/cuike519/archive/2004/08/22/81727.aspx文章的基础上做了一点修改。

在做一个文章添加功能时,想在选择大类后,自动将其所属二级小类显示出来,使用DropDownList的SelectedIndexChanged事件可以很容易实现,但每次选择后页面总要刷新一次,让人感觉很不爽。为实现DropDownList无刷新二级联动,这几天在网上找了些资料,但都无法达到我想要的效果,经过反复调试,现已基本实现了此功能,现将代码附下。

一、数据库设计:
字段名 数据类型 说明
ClassID 自动编号 类编号
ClassName varchar(8) 类名
UpClassID int(4) 上级类编号
ClassLevel int(4) 类级别,1为大类,2为小类

二、设计步骤:
1、首先,我们新建一个页面DropTest.aspx,在其中放入两个DropDownList控件:DropDownList1和DropDownList2,其完整代码如下:
<%@ Page language="c#" Codebehind="DropTest.aspx.cs" AutoEventWireup="false" Inherits="studyWEB.DropTest" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>WebForm2</title>
<meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
<script>
function load(ClassID){ //ClassID为接收传递的大类编号
var drp2 = document.getElementById("DropDownList2");
function RemoveAll(oElem) { //清除DropDownList2的所有项
var i = 0;
for (i = oElem.length; i >= 0; i--){
oElem.options.remove(i);
}
}
RemoveAll(drp2)
var oHttpReq = new ActiveXObject("MSXML2.XMLHTTP");
var oDoc = new ActiveXObject("MSXML2.DOMDocument");
oHttpReq.open("POST", "DropChild.aspx?ClassID="+ClassID, false); //调用读取小类数据的页面,将大类
// 编号值传递过去
oHttpReq.send("");
result = oHttpReq.responseText;
oDoc.loadXML(result);
items1 = oDoc.selectNodes("//CLASSNAME/Table/ClassName"); //读取所有请求大类所属小类的类名
items2 = oDoc.selectNodes("//CLASSNAME/Table/ClassID"); //读取所有请求大类所属小类的编号
var itemsLength=items1.length;
for(i=0;i<itemsLength;i++) //将小类的类名和编号赋予DropDownList2
{
var newOption = document.createElement("OPTION");
newOption.text=items1[i].text;
newOption.value=items2[i].text;
drp2.options.add(newOption);
}
}
</script>
</HEAD>
<body MS_POSITIONING="flowLayout">
<form id="Form1" method="post" runat="server">
<asp:DropDownList id="DropDownList1" runat="server"></asp:DropDownList>
<asp:DropDownList id="DropDownList2" runat="server"></asp:DropDownList>
<asp:TextBox id="TH" runat="server" BorderStyle="None" ForeColor="White" BorderColor="White"></asp:TextBox>
<asp:Label id="Label1" runat="server"></asp:Label>
<asp:Button id="Button1" runat="server" Text="Button"></asp:Button>
</form>
</body>
</HTML>
该页面的后台文件(DropDownList1.aspx.cs)中Page_Load内的代码如下:
if(!this.IsPostBack)
{
SqlConnection con = new SqlConnection("server=localhost;database=gswebDB;uid=sa;pwd=;");
SqlDataAdapter da = new SqlDataAdapter("select ClassName,ClassID from classname where ClassLevel=1",con);
DataSet ds = new DataSet();
da.Fill(ds);
this.DropDownList1.DataSource=ds.Tables[0].DefaultView;
this.DropDownList1.DataTextField = "ClassName";
this.DropDownList1.DataValueField = "ClassID";
this.DropDownList1.DataBind();
this.DropDownList1.Attributes.Add("onchange","load(this.options[this.selectedIndex].value)"); //将ClassID作为参数传递给脚本函数load(ClassID),如果要传递的是ClassName,应将value改为innerText,但如果大类为中文,则调用小类时出现无法显示的问题
// this.DropDownList2.Attributes.Add("onChange","javascript:document.Form1.TH.value=this.options[this.selectedIndex].value;"); //读取DropDownList2的值,将其赋给一个TextBox控件TH,以获取DropDownList2的值,为获取DropDownList2的值,网上有人说可通过使用隐藏的TextBox控件来获取,我未能实现,因为在客户端隐藏的TextBox控件也是不可用脚本来访问的,没法给其赋值,我只能通过将其样式、字体颜色设于背景相同来达到隐藏效果,这是一个很笨的方法,有谁有好的方法,请帮我。
}
此页面实现如下功能:首先从数据库内读取所有类级别为1(即大类)的类名和类编号,绑定到DropDownList1控件上;然后通过DropDownList1的Attributes属性调用javascript函数load(ClassID);load()函数通过调用DropChild.aspx页面,读取XML流,得到大类所属小类的ClassName和ClassID。
2、新建DropChild.aspx页面文件,其中不插入任何控件和文本,只在其后台文件(DropChild.aspx.cs)中的Page_Load中加入以下代码:
if(this.Request["ClassID"]!=null)
{
int state = Convert.ToInt32(this.Request["ClassID"]);
SqlConnection con = new SqlConnection("server=localhost;database=gswebDB;uid=sa;pwd=;");
SqlDataAdapter da = new SqlDataAdapter("select ClassName,ClassID from classname where UpClassID=''"+state+"''",con);
DataSet ds = new DataSet("CLASSNAME");
da.Fill(ds);
XmlTextWriter writer = new XmlTextWriter(Response.OutputStream, Response.ContentEncoding);
writer.Formatting = Formatting.Indented;
writer.Indentation = 4;
writer.IndentChar = '' '';
ds.WriteXml(writer);
writer.Flush();
Response.End();
writer.Close();
该方法得到用户选择的大类的编号,通过查询以后得到一个DataSet对象,使用该对象的WriteXML方法直接将内容写到Response.OutputStream里面然后传递到客户端,客户端的load方法通过result =oHttpReq.responseText;句话得到一个XML字符串,最后解析此串。
另外,测试获取DropDownList2值,添加了TextBox控件TH,当点击Button时,处理事件代码如下:
private void Button1_Click(object sender, System.EventArgs e)
{
Label1.Text=TH.Text;
}

由于我是初学ASP.NET,不到之处,请指点一二。

 


komazr 发表于 >2006-3-1 15:09:27  [全文] [评论] [引用] [推荐] [档案] [推给好友] [收藏到网摘]
 

2006-3-1
实现无刷新DropdownList联动效果

 
说明:本文在http://blog.csdn.net/cuike519/archive/2004/08/22/81727.aspx文章的基础上做了一点修改。 

在做一个文章添加功能时,想在选择大类后,自动将其所属二级小类显示出来,使用DropDownList的SelectedIndexChanged事件可以很容易实现,但每次选择后页面总要刷新一次,让人感觉很不爽。为实现DropDownList无刷新二级联动,这几天在网上找了些资料,但都无法达到我想要的效果,经过反复调试,现已基本实现了此功能,现将代码附下。

一、数据库设计:
字段名 数据类型 说明
ClassID 自动编号 类编号
ClassName varchar(8) 类名
UpClassID int(4) 上级类编号
ClassLevel int(4) 类级别,1为大类,2为小类

二、设计步骤:
1、首先,我们新建一个页面DropTest.aspx,在其中放入两个DropDownList控件:DropDownList1和DropDownList2,其完整代码如下:
<%@ Page language="c#" Codebehind="DropTest.aspx.cs" AutoEventWireup="false" Inherits="studyWEB.DropTest" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>WebForm2</title>
<meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5"  name="vs_targetSchema">
 
function load(ClassID){ //ClassID为接收传递的大类编号
var drp2 = document.getElementById("DropDownList2";
function RemoveAll(oElem) { //清除DropDownList2的所有项
var i = 0;
for (i = oElem.length; i >= 0; i--){
oElem.options.remove(i);
}
}
RemoveAll(drp2)
var oHttpReq = new ActiveXObject("MSXML2.XMLHTTP";
var oDoc = new ActiveXObject("MSXML2.DOMDocument";
oHttpReq.open("POST", "DropChild.aspx?ClassID="+ClassID, false); //调用读取小类数据的页面,将大类
// 编号值传递过去
oHttpReq.send("";
result = oHttpReq.responseText;
oDoc.loadXML(result);
items1 = oDoc.selectNodes("//CLASSNAME/Table/ClassName"; //读取所有请求大类所属小类的类名
items2 = oDoc.selectNodes("//CLASSNAME/Table/ClassID"; //读取所有请求大类所属小类的编号
var itemsLength=items1.length;
for(i=0;i<itemsLength;i++) //将小类的类名和编号赋予DropDownList2
{
var newOption = document.createElement("OPTION";
newOption.text=items1[i].text;
newOption.value=items2[i].text;
drp2.options.add(newOption);
}
}
 
</HEAD>
<body MS_POSITIONING="flowLayout">
<form id="Form1" method="post" runat="server">
<aspropDownList id="DropDownList1" runat="server"></aspropDownList>
<aspropDownList id="DropDownList2" runat="server"></aspropDownList>
<asp:TextBox id="TH" runat="server" BorderStyle="None" ForeColor="White" BorderColor="White"></asp:TextBox>
<asp:Label id="Label1" runat="server"></asp:Label>
<asp:Button id="Button1" runat="server" Text="Button"></asp:Button>
</form>
 
</HTML>
该页面的后台文件(DropDownList1.aspx.cs)中Page_Load内的代码如下:
if(!this.IsPostBack)
{
SqlConnection con = new SqlConnection("server=localhost;database=gswebDB;uid=sa;pwd=;";
SqlDataAdapter da = new SqlDataAdapter("select ClassName,ClassID from classname where ClassLevel=1",con);
DataSet ds = new DataSet();
da.Fill(ds);
this.DropDownList1.DataSource=ds.Tables[0].DefaultView;
this.DropDownList1.DataTextField = "ClassName";
this.DropDownList1.DataValueField = "ClassID";
this.DropDownList1.DataBind();
this.DropDownList1.Attributes.Add("onchange","load(this.options[this.selectedIndex].value)"; //将ClassID作为参数传递给脚本函数load(ClassID),如果要传递的是ClassName,应将value改为innerText,但如果大类为中文,则调用小类时出现无法显示的问题
// this.DropDownList2.Attributes.Add("onChange","javascript:document.Form1.TH.value=this.options[this.selectedIndex].value;"; //读取DropDownList2的值,将其赋给一个TextBox控件TH,以获取DropDownList2的值,为获取DropDownList2的值,网上有人说可通过使用隐藏的TextBox控件来获取,我未能实现,因为在客户端隐藏的TextBox控件也是不可用脚本来访问的,没法给其赋值,我只能通过将其样式、字体颜色设于背景相同来达到隐藏效果,这是一个很笨的方法,有谁有好的方法,请帮我。
}
此页面实现如下功能:首先从数据库内读取所有类级别为1(即大类)的类名和类编号,绑定到DropDownList1控件上;然后通过DropDownList1的Attributes属性调用javascript函数load(ClassID);load()函数通过调用DropChild.aspx页面,读取XML流,得到大类所属小类的ClassName和ClassID。
2、新建DropChild.aspx页面文件,其中不插入任何控件和文本,只在其后台文件(DropChild.aspx.cs)中的Page_Load中加入以下代码:
if(this.Request["ClassID"]!=null)
{
int state = Convert.ToInt32(this.Request["ClassID"]);
SqlConnection con = new SqlConnection("server=localhost;database=gswebDB;uid=sa;pwd=;";
SqlDataAdapter da = new SqlDataAdapter("select ClassName,ClassID from classname where UpClassID='"+state+"'",con);
DataSet ds = new DataSet("CLASSNAME";
da.Fill(ds);
XmlTextWriter writer = new XmlTextWriter(Response.OutputStream, Response.ContentEncoding);
writer.Formatting = Formatting.Indented;
writer.Indentation = 4;
writer.IndentChar = ' ';
ds.WriteXml(writer);
writer.Flush();
Response.End();
writer.Close();
该方法得到用户选择的大类的编号,通过查询以后得到一个DataSet对象,使用该对象的WriteXML方法直接将内容写到Response.OutputStream里面然后传递到客户端,客户端的load方法通过result =oHttpReq.responseText;句话得到一个XML字符串,最后解析此串。
另外,测试获取DropDownList2值,添加了TextBox控件TH,当点击Button时,处理事件代码如下:
private void Button1_Click(object sender, System.EventArgs e)
{
Label1.Text=TH.Text;
}

由于我是初学ASP.NET,不到之处,请指点一二。

 

komazr 发表于 >2006-3-1 15:00:33  [全文] [评论] [引用] [推荐] [档案] [推给好友] [收藏到网摘]
 

2006-2-25
treeview 使用集锦

1.下载地址
http://msdn.microsoft.com/downloads/samples/internet/ASP_DOT_NET_ServerControls/WebControls/default.asp
下载后是后缀为bat的版本
(1)bulid.将bulid.bat的路径指向csc.exe所在路径,生成Microsoft.Web.UI.WebControls.dll。
(2)在wwwroot下创建空目录webctrl_client/1_0。
(3)将build/Runtime下的文件拷至webctrl_client/1_0下。
(4)选择工具箱的自定义工具箱,添加Microsoft.Web.UI.WebControls.dll。
有些麻烦
但如果你能找到后缀是msi的自动安装版本,直接下一步就行(我一直用这个版本,hoho)
安装后,通过“自定义工具箱”->“.net框架组件”把TreeView添加到工具箱里

2.运行时无法显示
一般是TreeView的版本问题,最好下载英文版自动安装版本重新安装,安装前应该先到添加删除程序里卸掉原版本

3.显示格式出错(非树状显示)
TreeView要求客户端浏览器版本为IE5.5及以上,最好要求客户端升级为IE6.0

4.框架里使用TreeView
设置NavigateUrl、Target属性,可更新另外的Frame

5.找不到TreeNode类
使用TreeView,最好添加namespace:using Microsoft.Web.UI.WebControls;

6.遍历TreeView节点(递归算法)
private void Page_Load(object sender, System.EventArgs e)
{
 GetAllNodeText(TreeView1.Nodes);
}
void GetAllNodeText(TreeNodeCollection tnc)
{
 foreach(TreeNode node in tnc)
 {
  if(node.Nodes.Count!=0)
   GetAllNodeText(node.Nodes);
  Response.Write(node.Text + " ";
 }
}

7.得到node结点的父节点
TreeNode pnode;
if(node.Parent is TreeNode)
 pnode=(TreeNode)node.Parent;
else
 //node is root node

8.修改TreeView样式(示例)
<iewc:TreeView id="TreeView1" runat="server" HoverStyle="color:blue;background:#00ffCC;" DefaultStyle="background:red;color:yellow;" SelectedStyle="color:red;background:#00ff00;">
用代码:
TreeView1.DefaultStyle["font-size"] = "20pt";

9.展开时不提交,改变选择节点时才提交
将autopostback设置成false; 
在body里添加  <body  οnlοad="initTree()"> 
然后在PageLoad里写: 
string  strTreeName  =  "TreeView1"; 
string  strRef  =  Page.GetPostBackEventReference(TreeView1); 
string  strScript  =  "<script  language=/"JavaScript/">  /n"  +  "<!--  /n"  +  "            function  initTree()  {  /n"  +"                        "  +  strTreeName  +  ".onSelectedIndexChange  =  function()  {  /n"  +    "if  (event.oldTreeNodeIndex  !=   
event.newTreeNodeIndex)  /n"  +  "this.queueEvent('onselectedindexchange',  event.oldTreeNodeIndex  +  ','  +  event.newTreeNodeIndex);  /n"  +    "window.setTimeout('"  +  strRef.Replace("'","//'"    +  "',  0,  'JavaScript');  /n"  +    "                        }  /n"  +      "            }  /n"  +    "//  -->  /n"  +  ""; 
Page.RegisterClientScriptBlock("InitTree",strScript  ; 
 
这样就只有你点击的节点更改的时候才提交!

10.TreeView结合XML
把XML文件设置为如下格式,然后直接设置TreeNodeSrc为该XML文件就行
<?xml version="1.0" encoding="GB2312"?>
<TREENODES>
 <TREENODE TEXT="node0" EXPANDED="true">
  <TREENODE TEXT="node1"/>
  <TREENODE TEXT="node2"/>
 </TREENODE>
 <TREENODE TEXT="node3" NavigateURL="3.aspx"/>
</TREENODES>
或者用代码
TreeView1.TreeNodeSrc="a.xml";
TreeView1.DataBind();

 

客户端控制TreeView
http://expert.csdn.net/Expert/topic/1382/1382892.xml

1.设置所选节点,如选中第二个节点
function SetSelNode()
{
 TreeView1.selectedNodeIndex="1";
}

2.得到所选节点的Text,ID或NodeData
function GetAttribute()
{
 alert(TreeView1.getTreeNode(TreeView1.selectedNodeIndex).getAttribute("Text");
}
替换Text为ID或NodeData,可分别得到所选节点的ID或NodeData

3.修改节点属性,如修改第一个节点的Text
function ModifyNode()
{
 var node=TreeView1.getTreeNode("0";
 node.setAttribute("Text","hgknight";
}

4.得到点击节点
function TreeView1.onclick()
{
 alert(TreeView1.getTreeNode(TreeView1.clickedNodeIndex).getAttribute("Text");
}

5.添加节点
function AddNode()
{
 var node=TreeView1.createTreeNode();
 node.setAttribute("Text","hgknight";
 TreeView1.add(node);   
}

6.js遍历所有节点
 var AllRootNode=new Array();
 AllRootNode=TreeView1.getChildren();
 AlertNode(AllRootNode);  

 function AlertNode(NodeArray)
 {
  if(parseInt(NodeArray.length)==0)
   return;
  else
  {
   for(i=0;i<NodeArray.length;i++)
   {
    var cNode;
    cNode=NodeArray[i];
    alert(cNode.getAttribute("Text");
    if(parseInt(cNode.getChildren().length)!=0)
     AlertNode(cNode.getChildren());   
   }
  }
 }

 


komazr 发表于 >2006-2-25 22:57:19  [全文] [评论] [引用] [推荐] [档案] [推给好友] [收藏到网摘]
 

2006-2-25
treeview控件

ASP.NET中使用TreeView控件[系列]
 

--------------------------------------------------------------------------------
 
  发表时间:2004-10-9  
 
 
作者:未知

    简介

  在2002年,Microsoft发布了四种ASP.NET Web控件,用于为使用 Microsoft Internet Explorer 的 Web 访问者提供更好的体验。这些 Web 控件称为 Internet Explorer Web 控件,也简称为 IE Web 控件,包括以下四种控件:

   MultiPage Web 控件
   TabStrip Web 控件
   Toolbar Web 控件
   TreeView Web 控件

  这些 Web 控件通过提供 Web 访问者熟悉的用户界面,增强了 ASP.NET Web 页面。例如,Toolbar Web 控件可以显示一个与各种 Microsoft Office 产品中的工具栏相类似的可单击工具栏。TabStrip 和 MultiPage Web 控件配合使用后可以显示选项卡式内容。TreeView Web 控件可以用来显示可单击、可展开的树中的数据 - 与在 Microsoft Windows? 资源管理器中用树来显示 PC 文件系统中的驱动器和文件夹很类似。(您可以在 GotDotNet 站点找到这些 Web 控件的生动演示:WebControl Toolbar 演示、TabStrip/MultiPage WebControl 演示和 TreeView Sample WebControl 演示。)

  IE Web 控件可以在安装了 .NET Framework 版本 1.0 或 1.1 的 Web 服务器上使用。尽管 IE Web 控件是设计用来与 Internet Explorer 配合使用的,但这些 Web 控件也可以显示在其他浏览器中。不过,在 Internet Explorer 以外的浏览器中,当用户与 IE Web 控件交互时(例如展开 TreeView Web 控件中的某个节点),会发生回传。在 Internet Explorer 5.5 或更高版本中,IE Web 控件会发送 DHTML 代码,从而避免了回传的发生。也就是说,在访问您的 Web 站点时,使用 Internet Explorer 5.5 或更高版本的访问者将会比使用其他浏览器的用户获得更好的用户体验;当然,没有使用 IE 5.5 或更高版本的用户仍可以看到 IE Web 控件,并可以与之进行交互。

  下面,本文将主要介绍 TreeView IE Web 控件,并讨论如何使用此控件在 ASP.NET Web 页面中显示数据。有关其他 IE Web 控件的详细信息,请参阅 Internet Explorer Web Controls Overview 和 Internet Explorer Web Controls Reference。

  安装IE Web控件

  要在 ASP.NET Web 应用程序中使用 IE Web 控件,首先必须下载控件的源代码,然后运行一个编译批处理文件,对源代码进行编译并将所需的所有文件复制到相应的 Web 应用程序目录中。Internet Explorer Web 控件下载程序包是一个大小为 360 KB 的自解压安装文件。

  下载并安装完 IE Web 控件后,将创建一个新目录(默认为 C:/Program Files/IE Web Controls/,您也可以在安装过程中配置此目录)。找到这个新目录,然后双击 build.bat 文件。这将创建一个新的子目录 build,编译 src 子目录中的类,并将生成的程序集和支持文件复制到 build 子目录中。

  运行完 build.bat 文件后,build 子目录将包含程序集文件 Microsoft.Web.UI.WebControls.dll 和子目录 Runtime。要在 ASP.NET Web 应用程序中使用 IE Web 控件,必须将 build/Runtime 子目录中的内容复制到 Web 应用程序的 /webctrl_client/1_0 子目录中,并将程序集文件 (Microsoft.Web.UI.WebControls.dll) 复制到 Web 应用程序的 /bin 子目录中。(在 IE Web 控件的 README.txt 文件中,提供了示例以及执行这些任务的命令行指令。)

 

IE Web控件入门

  如果使用的是 Microsoft Visual Studio? .NET 来开发 ASP.NET Web 应用程序,则将 IE Web 控件添加到 ASP.NET Web 页是件轻松的事。首先,将 IE Web 控件包含在工具箱中。要完成这项操作,请右击 Toolbox(工具箱),然后选择 Customize Toolbox(自定义工具箱)选项。选择 .NET Framework Components(.NET Framework 组件)选项卡,然后单击 Browse(浏览)按钮。找到 Microsoft.Web.UI.WebControls.dll 程序集文件,然后单击 OK(确定)。这会将 MultiPage、TabStrip、Toolbar 和 TreeView 等 IE Web 控件添加到 Visual Studio .NET 工具箱中。要将以上控件中的任何一种添加到 ASP.NET Web 页中,只需要将相应的控件从工具箱拖放到设计器中即可。

  要在内含代码的类中使用 IE Web 控件,首先需要右击 Reference(引用),然后选择 Add Reference(添加引用),将引用添加到 Microsoft.Web.UI.WebControls.dll 程序集中。然后,在内含代码的类中,如果使用的是 C# ,则添加 using Microsoft.Web.UI.WebControls;如果使用的是 Microsoft Visual Basic .NET,则添加 Imports Microsoft.Web.UI.WebControls。

  如果不是使用 Visual Studio .NET 作为 ASP.NET Web 应用程序编辑器,则需要在 ASP.NET Web 页的顶端手动添加以下 @Register 指令:

<%@ Register TagPrefix=/whatever/
Namespace=/Microsoft.Web.UI.WebControls/
Assembly=/Microsoft.Web.UI.WebControls/ %>

  然后,将IE Web控件添加到Web页中,可以使用以下语法:

<whatever:WebControlName runat=/server/ ...>
...

</whatever:WebControlName>

  例如,要添加 TreeView 控件,可以在页面顶端添加以下 @Register 指令:

<%@ Register TagPrefix=/iewc/
Namespace=/Microsoft.Web.UI.WebControls/
Assembly=/Microsoft.Web.UI.WebControls/ %>

  接着,在ASP.NET Web页中希望显示TreeView的位置添加以下Web控件语法:

<iewc:TreeView runat=/server/ ...>
...
</iewc:TreeView>

 TreeView IE Web 控件入门

 

  当 TreeView IE Web 控件在访问者浏览器中显示时,会显示一棵树,此树与 Windows 资源管理器中的树非常类似。不同的是,TreeView 可以由任意多个 TreeNode 对象组成。每个 TreeNode 对象都可以关联文本和图像。另外,TreeNode 还可以显示为超链接并与某个 URL 相关联。每个 TreeNote 还可以包括任意多个子 TreeNote 对象。包含 TreeNode 及其子节点的层次结构构成了 TreeView 控件所呈现的树结构。

 

  假设您要构建一个用于显示家谱的 TreeView 控件。由于信息基本上不需要改动,因此您可能希望静态地指定 TreeView 结构。如果使用的是 Visual Studio .NET,则静态指定 TreeView 结构就像填写几份表格一样简单。首先,通过将 TreeView 控件从工具箱拖放到设计器中,将新的 TreeView 控件添加到 ASP.NET Web 页中。然后,将 TreeView 控件的 ID 属性设置为 tvFamilyTree。

 

  现在,要静态指定组成 TreeView 的 TreeNode。请从 Properties(属性)窗格中选择 Nodes(节点)属性,然后单击此属性右侧的省略号按钮。这时将显示 TreeNodeEditor(TreeNode 编辑器)对话框。现在可以将新的 TreeNode 添加到 TreeView 中。

 

  填充 TreeNodeEditor(TreeNote 编辑器)对话框后,以下标记将被添加到 ASP.NET Web 页的 .aspx 部分:

 

<ie:TreeView id=/tvFamilyTree/ runat=/server/>

<ie:TreeNode Text=/John Smith/>

<ie:TreeNode Text=/Born: Jan. 3rd, 1885/></ie:TreeNode>

<ie:TreeNode Text=/Died: Feb. 13, 1919/></ie:TreeNode>

<ie:TreeNode Text=/Spouse/>

<ie:TreeNode Text=/Marie Ellsworth/>

<ie:TreeNode Text=/Born: Aug. 1, 1889/></ie:TreeNode>

<ie:TreeNode Text=/Died: Unknown/></ie:TreeNode>

</ie:TreeNode>

<ie:TreeNode Text=/Children/>

<ie:TreeNode Text=/John Smith, Jr./>

<ie:TreeNode Text=/Born: July 4, 1891/></ie:TreeNode>

<ie:TreeNode Text=/Died: Sept. 22, 1893/></ie:TreeNode>

</ie:TreeNode>

<ie:TreeNode Text=/Mary Smith/>

<ie:TreeNode Text=/Born: June 7, 1893/></ie:TreeNode>

<ie:TreeNode Text=/Died: Aug. 13, 1949/></ie:TreeNode>

<ie:TreeNode Text=/Spouse/>

<ie:TreeNode Text=/Edward Joy/>

<ie:TreeNode Text=/Born: Unknown/></ie:TreeNode>

<ie:TreeNode Text=/Died: Aug. 13,

1949/></ie:TreeNode>

</ie:TreeNode>

<ie:TreeNode Text=/Children/>

<ie:TreeNode Text=/Michael Joy/>

<ie:TreeNode Text=/Born: Oct. 8,

1918/></ie:TreeNode>

</ie:TreeNode>

<ie:TreeNode Text=/Michele Joy/>

<ie:TreeNode Text=/Born: May 21,

1920/></ie:TreeNode>

</ie:TreeNode>

</ie:TreeNode>

</ie:TreeNode>

</ie:TreeNode>

</ie:TreeNode>

</ie:TreeNode>

</ie:TreeNode>

</ie:TreeView>

 

  如果不是使用 Visual Studio .NET 作为编辑器,则需要将此内容手动添加到 ASP.NET Web 页。当通过浏览器查看 ASP.NET Web 页时,将显示一棵可展开的树.默认情况下,将仅显示根节点。您可以设置 TreeNote 的 Expanded 属性,以指示首次查看此页面时该 TreeNote 应为展开状态。

 

  除了文本标签以外,TreeNote 还可以关联图像。尤其值得说明的是,每个 TreeNote 可以关联三幅图像:当 TreeNote 处于标准(折叠)状态时显示一幅图像;当 TreeNote 处于展开状态时显示另一幅图像;当 TreeNote 处于选中状态(当用户单击 TreeNote 时,该节点变为选中状态)时显示第三幅图像。这三种属性都需要一个指向指定图像的 URL。

 

  例如,可以通过以下方法展开家族树演示:将 TreeView 的 ImageUrl 属性设置为指向某个闭合的文件夹图像的 URL,将 TreeView 的 ExpandedImageUrl 属性设置为指向某个打开的文件夹图像的 URL,从而分别将折叠和已展开的 TreeNote 显示为闭合的文件夹和打开的文件夹。(如果要为选定的 TreeNote 换一幅图像,只需要将 TreeView 的 SelectedImageUrl 属性设置为相应的 URL 即可。)

 

  请注意,TreeView 和 TreeNote 都具有 ImageUrl、ExpandedImageUrl 和 SelectedImageUrl 属性。不同的是,当设置 TreeView 的属性时,默认情况下,TreeView 中所有 TreeNote 都将显示指定的图像; 如果设置 TreeNote 的属性,则这些属性仅适用于当前特定的 TreeNote。由于我们希望所有 TreeNote 处于折叠状态时显示为闭合的文件夹,处于展开状态时显示为打开的文件夹,因此我们对 TreeView 控件的 ImageUrl 和 ExpandedImageUrl 属性进行了设置。

 

  设置完这些新属性后,外观增色很多。在新的 TreeView 外观中,TreeNote 旁边都显示有图像。

 

  TreeNote 也可以关联 URL。当单击关联有 URL 的 TreeNote 时,会自动将用户快速链接到指定的 URL。TreeNote 的 NavigateUrl 属性用于指示当单击 TreeNote 时将用户链接到的 URL。该功能对于包含两个窗框的 ASP.NET Web 页非常有用。左侧窗框中包含一个 TreeView 控件。当用户单击某个 TreeNote 时,该节点的详细信息将显示在右侧窗框中,这与在 Windows 资源管理器中单击左侧窗格中的某个系统文件夹,该文件夹的文件将显示在右侧窗格中的情形类似。

 

  要关联 URL,只需要将每个 TreeNote 的 NavigateUrl 设置为相应的 URL。要将 TreeNote 的关联 URL 加载到其他浏览器窗框中,请将 TreeNote 的 Target 属性设置为相应的窗框名称。这些步骤都可以通过 TreeNodeEditor(TreeNote 编辑器)来完成。要查看此类应用程序的示例,请参阅 Steve Sharrock 关于使用 TreeView 创建资源管理器风格的 ASP.NET Web 应用程序的文章:TreeView - Programming an Explorer-style Site View。

TreeView 的其他高级功能

 

  虽然使用 Visual Studio .NET 将静态 TreeNote 添加到 TreeView 的过程非常简单,但通常需要将内容动态地添加到 TreeView 中。例如,您将家族树信息存储到了数据库中,或是正在设计一个资源管理器风格的 Web 应用程序(在此应用程序中,用户可以浏览 Web 服务器的文件系统),这时您可能需要根据服务器的文件夹和文件来动态填充 TreeNote。

 

  在内含代码的类中,可以通过编程方式将 TreeNote 添加到 TreeView 中。要将新的 TreeNote 添加到现有的 TreeNote 中,只需要使用 Nodes 属性的 Add() 方法。例如,以下 C# 代码将创建两个 TreeNote,并将第二个 TreeNote 添加为第一个 TreeNote 的子节点。然后,将第一个子节点添加到 TreeView 的根节点中。

 

// 创建第一个 TreeNote

TreeNode tvFirst = new TreeNode();

tvFirst.Text = /First Tree Node/;

 

// 创建第二个 TreeNote

TreeNode tvSecond = new TreeNode();

tvSecond.Text = /Second Tree Node/;

 

// 将第二个 TreeNote 添加为第一个 TreeNote 的子节点

tvFirst.Nodes.Add(tvSecond);

 

// 将第一个 TreeNote 添加到 TreeView 的根节点中。

tvFamilyTree.Nodes.Add(tvFirst); 

 

  遗憾的是,将数据库数据绑定到 TreeView 可不像将数据绑定到某个标准 ASP.NET Web 控件那么简单。因为 TreeView 本身用于显示分层数据,所以不太适合显示简单 SQL 查询的结果。因此,TreeView 不是用来显示简单 SQL 查询的内容的,而是用来显示 XML 文件的内容。所以,为了便于在 TreeView 中显示数据库信息,必须首先将其转换为 XML。

 

  而且,虽然可以在 TreeView 控件中显示静态或动态 XML 文件,但是,TreeView 要求 XML 数据具有特定的格式。因此,要在 TreeView 中显示 XML 文件,必须提供 XSLT 样式表,以将 XML 从当前格式转换到 TreeView 要求的格式。有关如何完成此任务的详细信息,请参阅我的文章:Displaying XML Data in the Internet Explorer TreeView Control。

 

  此外,TreeView 的 TreeNote 除了支持图像和超链接之外,其旁边还可以包含复选框。而且,当用户展开或折叠 TreeNote,选择 TreeNote,或者选中或取消选中带有复选框的 TreeNote 时,都会引发相应的事件。可以为这些事件创建事件处理程序,以自定义这些事件引发的相应操作。

 

  小结

 

  在本文中,我们简要地介绍了 IE Web 控件以及如何获得和安装这些控件,并详细讨论了如何使用 TreeView IE Web 控件。TreeView 控件的显示方式类似于标准的 Windows TreeView(可通过在 Windows 资源管理器中进行操作来体验)。TreeView 用来显示分层数据,可以由任意多个 TreeNote 组成,每个 TreeNote 又可以包含任何多个子 TreeNote。

 

  可以用多种不同的方式自定义 TreeNote 的外观。例如,可以为处于折叠、展开和选中状态的 TreeNote 分别指定不同的图像。当单击 TreeNote 时,TreeNote 可以作为超链接将访问者重定向到其他 URL。TreeNote 还可以包含复选框。

 

  使用 Visual Studio .NET 并借助 TreeNote 编辑器可以很容易地实现在 TreeView 中显示静态数据。通过 XML 文件或通过以编程方式添加 TreeNote,可以动态指定 TreeView 控件的内容。虽然本文介绍的仅是 TreeView 控件的皮毛,但对于您初步了解在 ASP.NET Web 应用程序中使用 TreeView 控件也是大有帮助的。
 
 
 
 
Text


komazr 发表于 >2006-2-25 13:17:32  [全文] [评论] [引用] [推荐] [档案] [推给好友] [收藏到网摘]
 

2006-2-22
ini2xml

public class ini2xml
{
/// <summary>
///
/// </summary>
public ini2xml()
{
}
 
/// <summary>
/// initial size of the buffer used when calling the win32 api functions
/// </summary>
const int initial_buffer_size = 1024;

 

/// <summary>
/// converts an ini file into an xml file.
/// output xml file has the following structure...
///   <?xml version="1.0"?>
///   <configuration>
///       <section name="main">
///           <setting name="timeout" value="90"/>
///           <setting name="mode" value="live"/>
///      </section>
///   </configuration>
/// example:
/// if (loki.ini2xml.convert( txtinifilename.text )
///  system.console.writeline( "successfully converted /"" + txtinifilename.text + "/" to xml" ;
/// else
///  system.console.writeline( "problem converting /"" + txtinifilename.text + "/" to xml" ;
/// if an exception is raised, it is passed on to the caller.
/// </summary>
/// <param name="strinifilename">file name of the ini file to convert</param>
/// <returns>true if successfuly, or false if a problem</returns>
public static bool convert( string strinifilename
{
return convert( strinifilename, "" ;
}

 

/// <summary>
/// converts an ini file into an xml file.
/// output xml file has the following structure...
///   <?xml version="1.0"?>
///   <configuration>
///       <section name="main">
///           <setting name="timeout" value="90"/>
///           <setting name="mode" value="live"/>
///      </section>
///   </configuration>
/// example:
/// if (loki.ini2xml.convert( txtinifilename.text, txtxmlfilename.text )
///  system.console.writeline( "successfully converted /"" + txtinifilename.text + "/" to /"" + txtxmlfilename.text + "/"" ;
/// else
///  system.console.writeline( "problem converting /"" + txtinifilename.text + "/" to /"" + txtxmlfilename.text + "/"" ;
/// if an exception is raised, it is passed on to the caller.
/// </summary>
/// <param name="strinifilename">file name of the ini file to convert</param>
/// <param name="strxmlfilename">file name of the xml file that is created</param>
/// <returns>true if successfuly, or false if a problem</returns>
public static bool convert( string strinifilename, string strxmlfilename
{
char[] charequals = {'='};
string lpsections;
int nsize;
int nmaxsize;
string strsection;
int intsection;
int intnamevalue;
string strname;
string strvalue;
string strnamevalue;
string lpnamevalues;
int intpos;
byte[] str = new byte[1];
system.io.streamwriter filestream;
  
if ( strxmlfilename.length == 0
{
// set the xml's file name based on the ini file name
intpos = strinifilename.lastindexof( ".ini" ;
if ( intpos >= 0
{
strxmlfilename = strinifilename.substring( 0, intpos  + ".xml";
}
else
{
strxmlfilename = strinifilename + ".xml";
}
}
  
// get all sections names
// making sure allocate enough space for data returned
for (nmaxsize = initial_buffer_size / 2,
nsize = nmaxsize;
nsize != 0 && nsize >= (nmaxsize-2);
nmaxsize *= 2)
{
str = new byte[nmaxsize];
nsize = win32wrapper.getprivateprofilesectionnames( str, nmaxsize, strinifilename);
}

 

// convert the byte array into a .net string
lpsections = system.text.encoding.ascii.getstring( str ;
 
// create xml file
filestream = system.io.file.createtext( strxmlfilename ;

 

// write the opening xml
filestream.writeline( "<?xml version=/"1.0/"?><configuration>" ;
 
// loop through each section
char[] charnull = {'/0'};
for (intsection = 0,
strsection = gettoken(lpsections, charnull, intsection);
strsection.length > 0;
strsection = gettoken(lpsections, charnull, ++intsection)
{
// write a node for the section
filestream.writeline( "<section name=/"" + strsection + "/">" ;
  
// get all values in this section, making sure to allocate enough space
for (nmaxsize = initial_buffer_size,
nsize = nmaxsize;
nsize != 0 && nsize >= (nmaxsize-2);
nmaxsize *= 2)
{
str = new byte[nmaxsize];
nsize = win32wrapper.getprivateprofilesection(strsection, str, nmaxsize, strinifilename);
}

 

// convert the byte array into a .net string
lpnamevalues = system.text.encoding.ascii.getstring( str ;
  
// loop through each name/value pair
for (intnamevalue = 0,
strnamevalue = gettoken(lpnamevalues, charnull, intnamevalue);
strnamevalue.length > 0;
strnamevalue = gettoken(lpnamevalues, charnull, ++intnamevalue)
{
// get the name and value from the entire null separated string of name/value pairs
// also escape out the special characters, (ie. &"<>
strname = xmlencode( gettoken( strnamevalue, charequals, 0  ;
strvalue = xmlencode( strnamevalue.substring( strname.length + 1  ;

 

// write the xml name/value node to the xml file
filestream.writeline( "<setting name=/"" + strname + "/" value=/"" + strvalue + "/"/>";
}
   
// close the section node
filestream.writeline( "</section>" ;
}
 
// thats it
filestream.writeline( "</configuration>" ;
filestream.close();
 
return true;
} // convert
 
/// <summary>
/// encodes special characters that xml has problems with, ie.
///       character       encoded to
///       &               &amp;
///       "               &quot;
///       <               &lt;
///       >               &gt;  intsection = 0
///   strsection = gettoken(lpsections, charnull, intsection)
/// </summary>
/// <param name="strtext">text that needs encoding</param>
/// <returns>encoded text</returns>
public static string xmlencode( string strtext)
{
string strtextret = strtext;

 

strtextret = strtextret.replace( "&", "&amp;" ;
strtextret = strtextret.replace( "/"", "&quot;";
strtextret = strtextret.replace( "<", "&lt;";
strtextret = strtextret.replace( ">", "&gt;";

 

return strtextret;
}
 
/// <summary>
/// get a token from a delimited string, eg.
///   intsection = 0
///   strsection = gettoken(lpsections, charnull, intsection)
/// </summary>
/// <param name="strtext">text that is delimited</param>
/// <param name="delimiter">the delimiter, eg. ","</param>
/// <param name="intindex">the index of the token to return, nb. first token is index 0.</param>
/// <returns>returns the nth token from a string.</returns>
private static string gettoken( string strtext, char[] delimiter, int intindex
{
string strtokenret = "";

 

string[] strtokens = strtext.split( delimiter ;

 

if ( strtokens.getupperbound(0) >= intindex
strtokenret = strtokens[intindex];

 

return strtokenret;
} // gettoken
} // class ini2xml


komazr 发表于 >2006-2-22 9:38:53  [全文] [评论] [引用] [推荐] [档案] [推给好友] [收藏到网摘]
 

2006-2-21
发送邮件成功率最高的代码

using System;
using System.Web.Mail;
using CDO;
namespace admin
{
 /** <summary>
 /// MailSender2 的摘要说明。
 /// </summary>
 public class MailSender
 {
  public string Server
  {
   get { return server; }
   set { if (value != server) server = value; }
  } private string server = "";

  /** <summary>
  /// 用户名 [如果需要身份验证的话]
  /// </summary>
  public string UserName
  {
   get { return userName; }
   set { if (value != userName) userName = value; }
  } private string userName = "";

  /** <summary>
  /// 密码 [如果需要身份验证的话]
  /// </summary>
  public string Password
  {
   get { return password; }
   set { if (value != password) password = value; }
  } private string password = "";

  /** <summary>
  /// 发件人地址
  /// </summary>
  public string From
  {
   get { return from; }
   set { if (value != from) from = value;}
  } private string from = "";

  /** <summary>
  /// 收件人地址
  /// </summary>
  public string To
  {
   get { return to; }
   set { if (value != to) to = value;}
  } private string to = "";

  /** <summary>
  /// 邮件的主题
  /// </summary>
  public string Subject
  {
   get { return subject; }
   set { if (value != subject) subject = value; }
  } private string subject = "";

  /** <summary>
  /// 邮件正文
  /// </summary>
  public string Body
  {
   get { return body; }
   set { if (value != body) body = value; }
  } private string body = "";

  /** <summary>
  /// 超文本格式的邮件正文
  /// </summary>
  public string HtmlBody
  {
   get { return htmlBody; }
   set { if (value != htmlBody) htmlBody = value; }
  } private string htmlBody = "";

  /** <summary>
  /// 是否是html格式的邮件
  /// </summary>
  public bool IsHtml
  {
   get { return isHtml; }
   set { if (value != isHtml) isHtml = value; }
  } private bool isHtml = false;

  public void SendMail ()
  {
   CDO.Message  oMsg  =  new  CDO.Message();  
   oMsg.To=to;
   oMsg.Subject=subject;
   oMsg.From=from;
   if(isHtml)
   {
    oMsg.HTMLBody = htmlBody;
   }
   else
    oMsg.TextBody=body;
  
            
   CDO.IConfiguration  iConfg;     
   ADODB.Fields  oFields; 
   iConfg  =  oMsg.Configuration;     
   oFields  =  iConfg.Fields; 
 
   oFields["http://schemas.microsoft.com/cdo/configuration/sendusing" ].Value=2;   
   oFields["http://schemas.microsoft.com/cdo/configuration/sendemailaddress" ].Value=from;   
   oFields["http://schemas.microsoft.com/cdo/configuration/smtpuserreplyemailaddress" ].Value=from; 
   oFields["http://schemas.microsoft.com/cdo/configuration/smtpaccountname" ].Value=userName;   
   oFields["http://schemas.microsoft.com/cdo/configuration/sendusername" ].Value=userName; 
   oFields["http://schemas.microsoft.com/cdo/configuration/sendpassword" ].Value=password; 
   oFields["http://schemas.microsoft.com/cdo/configuration/smtpauthenticate" ].Value=1;   
   oFields["http://schemas.microsoft.com/cdo/configuration/smtpserver" ].Value=server; 
   oFields.Update(); 
        
   oMsg.Send(); 
   oMsg  =  null;


  }

 }
}
 


komazr 发表于 >2006-2-21 10:13:37  [全文] [评论] [引用] [推荐] [档案] [推给好友] [收藏到网摘]
 

2006-2-18
常见的 ASP.NET 性能神话

常见的 ASP.NET 性能神话
有用的 ASP.NET 性能技巧和诀窍
在 ASP.NET 中处理数据库的一些建议
缓冲以及用 ASP.NET 进行后台处理
本文使用下列技术:ASP.NET,.NET 框架,IIS

  用 ASP.NET 编写 Web 应用程序其轻松程度令人难以置信。它是如此的容易,以至于许多开发人员不用花费多少时间来构筑其应用便能获得非常好的性能。在本文中,我将给出10个编写高性能 Web 应用的技巧。我的评论不仅仅局限与 ASP.NET 应用,因为它们只是 Web 应用的一个子集。本文也不是 Web 应用性能调整的权威指南——这方面的内容可以写成一本书。相反,本文可以被视作一个好的起点。
  在废寝忘食地工作之前,我常常要去攀岩。在攀岩之前,我总是要看一下指南手册中的线路并阅读以前来此一游的人留下的建议和忠告。但是,不管指南手册有多磨好,在尝试一次特定的具有挑战性的攀爬之前,你都必须付诸实际的行动。同样,在你面临解决的性能问题或者营运一个高吞吐量的站点之前,你只能想方设法编写高性能 Web 应用程序。
  我们个人经验来自在微软 ASP.NET 团队从事底层架构程序经理,运行和管理 www.asp.net ,并协助架构 Community Server 过程中的经历,Community Server 是几个有名的 ASP.NET 应用程序的下一个版本(它将 ASP.NET Forums,.Text 和 nGallery 整合到一个平台)。我确信这些帮助过我的技巧也会对你有所裨益。
  你应该考虑将应用程序分离成几个逻辑层。你可能听说过术语3-层(或n-层)物理体系结构。它们通常是跨进程和/或硬件对功能进行物理划分的规定的体系结构模式。当系统需要伸缩时,更多的硬件能被添加。然而,总是应该避免与进程和机器忙碌程度相关的性能问题。所以,不管什么时候,只要可能,都要在相同的应用中一起运行 ASP.NET 页面及其相关的组件。
  由于代码和层之间的边界分离,使用 Web 服务或远程调用将降低20%以上的性能。
  数据层则稍微有些不同,因为数据库通常都用专门的硬件。但是,数据库的处理成本仍然很高,因此最优化代码时,数据层的性能应该是首当其充要关注的地方。
  在着手解决你的应用程序的性能问题之前,一定要剖析应用程序,确定问题之所在。获取关键的性能计数器值(如实现垃圾收集所花时间之百分比的性能计数器的值)对于查找应用程序在何处最耗时也是非常重要的。凭借直觉常常也能找到耗时所在。
  本文所描述的性能改进有两种类型:大型优化,如使用 ASP.NET Cache,以及不断重复进行的微型优化。这些微型优化有时很有意思。对代码的小小改动便会引起很大的动静,产生成千次的调用。对于大型优化,你可能会看到整体性能的大跳跃。而对微型优化,给定请求可能只是毫秒级的调整,但按每天的请求总数计算,其结果的改进可能是巨大的。

数据层的性能

  当调整某个应用程序的性能时,有一个简单的试金石,你可以用它按先后次序:检查代码是否存取数据库?如果是,多长时间存取一次?注意相同的测试也可以被应用于使用 Web 服务或远程调用的代码,但我们本文中不涉及这方面内容。
  如果在特定的代码流程中必须具有对数据库的请求以及要考察其它方面,如:想对字符串处理进行优先优化,那么暂且把它放一放,先按照上面定好的优先次序来做。除非你有异乎寻常的性能问题,否则你的时间应该用在尝试最优化与数据库的连接所花的时间,返回的数据量以及多长时间往返一次和数据库的通讯上。
  有了这些概括信息,下面就让我们来看看能帮助你改善应用程序性能的十个技巧。我将从能获得最显著效果的改变开始。

技巧 1 —— 返回多个结果集

  复审你的数据库代码,看看是否有多于一次的对数据库的访问请求。这样每次往返数据库都降低你的应用程序能处理的每秒请求数。通过在单个数据库请求中返回多结果集,你能降低与数据库通信的总体时间。同时你也将使系统更具伸缩性,因为你减少了数据库服务器处理请求的负担。
  虽然你可以用动态 SQL 返回多结果集,我更喜欢使用存储过过程。是否将业务逻辑驻留在存储过程当中是个有待争论的问题,但我认为,如果存储过程中的逻辑能约束返回的数据(降低数据集的尺寸,在网络上传输的时间以及逻辑层不必过虑数据),这是一件好事情。
  使用 SqlCommand 命令实例及其 ExecuteReader 方法来处理强类型的各个业务类,你通过调用 NextResult 可以向前移动结果集指针。Figure 1 示范了处理几个带类型的 ArrayLists 例子会话。从数据库只返回你需要的数据还会降低服务器上内存的分配。

技巧 2 —— 分页数据存取

  ASP.NET DataGrid 提供了非常好的能力:数据分页支持。当启用 DataGrid 中的分页功能,则每次只显示固定数量的记录。此外,分页用户界面也会显示在 DataGrid 底部用于导航记录。分页用户界面允许你向前向后导航所显示的记录,一次显示固定数量的记录。
  有一个美中不足的是用 DataGrid 分页需要将所有数据邦定到此栅格控件(gird)。例如,你的数据层必须返回所有数据,然后 DataGrid 将根据当前页过滤掉所有显示的记录。当你通过 DataGrid 进行分页时,如果有 100,000 条记录被返回,那么每个请求有 99,975 条记录将被废弃掉(假设页尺寸为 25)。当记录数不断增加,此应用程序的性能便会遭受痛苦,因为每次请求所要发送的数据会越来越多。
  编写较好的分页代码的一个好的方法是用存储过程。Figure 2 示范了一个用 Northwind 数据库中 Orders 表通过存储过程分页的例子。很简单,只要你在页面中传递索引以及页尺寸即可。相应的结果集先被计算然后被返回。
  在 Community Server 中,我们编写了几个分页控件来完成数据分页。你将会看到,我使用了技巧 1 中讨论的思路,从一个存储过程中返回连个结果集:总记录数和请求的数据。
  返回的总记录数依赖于所执行的查询不同而不同。例如,某个 WHERE 子句可被用于约束返回的数据。为了计算在分页用户界面显示的总页数,返回的总记录数必须是已知的。例如,如果有 1,000,000 条记录,用一个 WHERE 子句对之过滤后为 1,000 条记录,则分页逻辑必须要知道总记录数以便在分页用户界面中正确呈现。

技巧 3 —— 连接池

  建立 Web 应用程序与 SQL Server 之间的 TCP 连接是一项昂贵的操作。微软的开发人员利用连接池技术已经有好长一段时间了,这个技术使他们能重用到数据库的连接。而不是每次请求都建立新的 TCP 连接,新连接仅在连接池中得不到连接时才建立。当连接被关闭时,它被返回到连接池中,在那里它仍然保持与数据库的连接,与完全断开 TCP 连接相反。
  当然,你需要提防泄漏的连接。当你处理完毕,一定要关闭连接。重申一次:不管人们怎么吹嘘微软 .NET 框架中的垃圾收集特性,每当你处理完毕,一定要显式地调用连接对象的 Close 或 Dispose 方法。不要指望公共语言运行时(CLR)来为你定时清除和关闭连接。CLR 最终将销毁类并强行关闭连接,但你无法保证该对象的垃圾收集届时会起作用。
  为了充分用好连接池,有几条规则必须了然于心。首先,打开连接,进行处理,然后关闭连接。宁愿每个请求的连接打开和关闭多次,也不要保持连接打开状态以及在不同的方法间将它传来传去。其次,使用相同的连接串(如果你使用集成身份检查,那么也要用相同的线程身份)。如果你不用相同的连接串,例如,根据登录用户来定制连接串,你将无法得到连接池所提供的相同的最优化值。当模拟大用户量情形时,如果你使用集成身份检查,那么你的连接池将效力大减。.NET CLR 数据性能计数器在试图跟踪任何与连接池有关的性能问题时是非常有用的。
  不管什么时候,只要你的应用程序连接到运行在其它进程中的资源,比如某个数据库,你都应该针对连接到资源所耗时间,发送和接收数据所耗时间以及往返次数进行优化。为了实现较好的性能,应该首当其充优化应用程序中任何种类的忙碌进程。
  应用层包含到数据层的连接以及将数据转换成有意义的类实例和业务处理的逻辑。以 Community Server 为例,你要在其中处理 Forums 和 Threads 集合;以及应用许可这样的业务规则;尤其重要的是缓冲(Caching)逻辑也实现其中。

技巧 4 —— ASP.NET Cache API

  在编写代码之前要做的头等大事之一是最大限度地构建应用层并发掘 ASP.NET 的 Cache 特性。
  如果你的组件在 ASP.NET 应用程序内运行,那么你只需要在应用程序工程中引用 System.Web.dll 即可。当你需要访问 Cache 时,用 HttpRuntime.Cache 属性(相同的对象也可以通过 Page.Cache 和 HttpContext.Cache 访问)。
  缓冲数据有几个准则。首先,如果数据能被使用多次,缓冲是个好的后选方案。其次,如果数据对给定请求或用户是一般的数据而非专用数据,那么最好是选择缓冲。如果数据用户或请求专用,如果需要保存期很长但可能不被经常使用,那么仍然要用缓冲。第三,常常被忽略的一个准则是有时缓冲太多的东西。一般来说,在x86机器上,为了降低内存不足错误的几率,运行某个进程不要超过800MB私有字节。因此,缓冲应该有个上限。换句话说,你也许能重用某个计算的结果,但如果该计算有10个参数,你可能试图针对10个置换进行缓冲,这样做可能会给你带来麻烦。ASP.NET 提供的最常见的容错是由覆盖缓冲导致的内存不足错误,尤其是大型数据集。
  Cache 有几个重要特性是必须要了解的。第一个是 Cache 实现了最近最少使用(least-recently-used)算法,允许 ASP.NET 强制 Cache 清除操作 —— 如果可用内存下降到低水平 —— 则自动从 Cache 中删除不使用的项目。第二个是 Cache 支持依赖性到期特性,它能强制包括时间,键值,文件失效。时间常常被使用,但 ASP.NET 2.0 引入了具有更强大的失效类型:数据库缓冲失效。也就是当数据库中的数据改变时,缓冲中的条目会自动删除。有关数据库缓冲失效的更多信息参见 Dino Esposito 在 MSDN 杂志 2004 年七月刊的 Cutting Edge 专栏文章。该缓冲的体系结构,参见 Figure 3。


Figure 3 ASP.NET Cache

技巧 5 —— 预请求缓冲(Per-Request Caching)

  在本文前面,我曾提到对频繁执行的代码块所做的小小改动可能产生很大的,整体性能的提升。我把其中一个我特别中意的叫做预请求缓冲(per-request caching)。
  由于 Cache API  被设计用来缓冲长期数据或直到某个条件被满足,预请求缓冲意旨用于请求期间的缓冲该数据。特定的代码流程被每次请求频繁访问但是数据只需要被拾取,应用,修改或更新一次,这样说太理论化,还是让我们看一个具体的例子吧。
在 Community Server 的 Forums (论坛)应用中,某个页面上使用的每个服务器控件需要个性化数据以确定使用那个皮肤和式样页,以及其它的个性化数据,其中有些数据可以被长时间缓冲,但有些数据,比如用于控件的皮肤在单个请求中只被拾取一次并在该请求执行期间被重用多次。
  为了完成预请求缓冲,用 ASP.NET HttpContext。HttpContext 的实例是随每个请求创建的,并可以通过 HttpContext.Current 属性在那个请求执行期间的任何地方存取它。HttpContext 类具有一个特别的 Items  集合属性,被添加到该 Items  集合的对象和数据只是在该请求期间被缓存。就像你可以使用 Cache 来保存频繁使用的数据一样,你可以用 HttpContext.Items 来保存只在某个预请求中使用的数据。在此背景后的逻辑很简单:当数据不存在时被添加到 HttpContext.Items 集合,以及在随后的并发查找中简单地返回 HttpContext.Items 中发现的数据。

技巧  6——后台处理

  你的代码流程应该尽可能快,对吧?你自己可能多次发现要完成每个请求或每n个请求的任务代价很高。发出 e-mail 或解析并检查输入数据的有效性就是个例。
  在重新生成 ASP.NET Forums 1.0 并把它整合到 Community Server 时,我们发现添加新贴的代码流程非常慢。每次添加帖子,应用程序首先要确保没有重复贴,然后必须用“badword”过滤器解析该贴的表情图像,记号并索引,如果必要还要将帖子添加到相应的队列中,对附件进行有效性检查,最终完成发贴后,给预订者发出 e-mail 通知。显然,这里做的工作太多。
  我们发现大多数时间都花在了索引逻辑和发送e-mail上。索引帖子是一个很耗时的操作,此外,内建的 System.Web.Mail 功能要与 SMTP 服务器连接并顺序发送邮件。当特定帖子或主题预定者数量增加时,AddPost 函数的执行时间会越来越长。
  并不是每个请求都需要索引邮件,我们想最好是批量集中处理,并且一次只索引25个帖子或每隔五分钟发送一次邮件。我们决定使用的代码与我曾在原型数据库缓冲失效中所使用的代码相同,最终它也被纳入 Visual Studio 2005。
  名字空间 System.Threading 中的 Timer 类非常有用,但在.NET 框架中鲜为人知,至少对 Web 开发者来说是这样。一旦创建,Timer 将以可定制的间隔针对线程池中的某个线程调用指定的回调函数。这意味着你不用输入请求到 ASP.NET 应用程序便能让代码实行,这是一种最合适后台处理的情形。你也可以在这种后台处理模式中进行例如索引或发送电子邮件这样的工作。
  尽管如此,这个技术存在几个问题,如果你的应用程序域关闭,该定时器实例将停止触发其事件。另外,由于 CLR 有一个硬坎,即每个进程的线程数是固定的,你便可能陷入严重的服务器负荷当中,此时可能就没有线程来处理定时器,从而造成延时。为了让发生这种情况的几率最小化,ASP.NET 通过在进程中预留一定数量的空闲线程,并只使用部分线程来处理请求。然而,如果你有许多异步处理,这样做会有问题。
  由于篇幅所限,在此无法列出代码,但你可以从 http://www.rob-howard.net/  下载可消化的例子。其中有 Blackbelt TechEd 2004 展示的幻灯和 Demo。

技巧 7——页面输出缓存和代理服务器

  ASP.NET 是你的表示层(或者说应该是);它由页面,用户控件,服务器控件(HttpHandlers and HttpModules)以及它们生成的内容组成。如果你有一个产生输出的 ASP.NET 页面,不管是输出 HTML,XML,图像还是任何其它数据,而且每个请求你都运行这个代码并产生相同的输出,此时最好选择使用页面输出缓存。
只要在页面顶部添加这一行代码即可:

<%@ Page OutputCache VaryByParams="none" Duration="60" %>
  你可以为此页面有效地产生一次输出并可以在60秒内多次重用它,一到这个时间点,该页面将重新执行并将再次将输出添加到 ASP.NET Cache。这个行为还能用某些低级编程 APIs 来完成。输出缓存有几个可以配置的设置,比如:VaryByParams 属性。VaryByParams 不是必须的,但允许你指定 HTTP GET 或 HTTP POST 参数来改变缓存入口。例如,default.aspx?Report=1 或 default.aspx?Report=2 可以简单地设置 VaryByParam="Report" 来对输出进行缓存。额外的参数被命名并用用分号分隔。
  在使用输出缓存机制时,许多人都不了解 ASP.NET 页还产生一组下游缓存服务器 HTTP 头,比如 Microsoft Internet Security and Acceleration Server 或 Akamai 使用的 HTTP 头。当设置 HTTP 缓存头,文档可以被缓存到这些网络资源,从而响应客户端请求不必返回原服务器。
  然而,使用页面输出缓存并不会使你的应用程序更有效率,但它能通过下游缓存技术缓存文档从而潜在地降低服务器的负载。当然,这只能是异步内容;一旦实施下游缓存,你将无法看到任何请求,也不能实现身份认证来防止对它的存取。

技巧 8——运行 IIS 6.0 (如果仅用于内核缓存)

  如果你不运行 IIS 6.O(Windows Server 2003),那么你将得不到微软 Web 服务器中一些重大的性能改进。在技巧 7 中,我谈到了输出缓存。在 IIS 5.0 中,请求到达 IIS,然后到达 ASP.NET。当使用缓存时,ASP.NET 中的 HttpModule 接受该请求,并从该缓存中返回内容。
  如果你用 IIS 6.0,有一些巧妙的特性叫内核缓存,它不需要将任何代码改成 ASP.NET。当 ASP.NET对请求进行缓存处理,IIS 内核缓存便接收一份缓存数据的拷贝。当请求来自网络驱动器,内核一级的驱动程序(没有到用户模式的上下文转换)接收该请求,如果缓存,则直接用缓存数据响应并完成执行。这意味着当你使用 IIS 内核模式缓存和 ASP.NET 缓存时,你将看到无法置信的性能结果。在开发 Visual Studio 2005 的 ASP.NET 期间,我是负责 ASP.NET 性能的程序经理。开发人员的工作做的真是棒极了,而我基本上每天都在看报告。内核模式缓存结果总是最有趣的。典型的情况是请求/响应往往使网络饱和,但 IIS 的运行仅占 CPU 的百分之五。真令人惊异!当然使用 IIS 6.O 有其它一些原因,但内核模式缓存是显而易见的理由。

技巧 9——使用 Gzip 压缩

  虽然使用 gzip 压缩不是一个必须的服务器性能技巧(因为你可能看到 CUP 的使用率上升了),但它能降低服务器发送字节的数量。从而感觉页面更快,而且减少带宽的占用。其压缩的效果好坏取决于所发送的数据以及客户端浏览器是否支持这种压缩(IIS 只会将数据发送到支持 gzip 的浏览器,比如:IE 6.0 和 Firefox),从而使服务器可以在每秒钟里处理更多的请求。事实上,只要你降低返回数据的数量,便能提高每秒所处理的请求数。
  有一个好消息是 gzip 压缩是 IIS 6.0 的内建特性,并且比它在 IIS 5.0 中使用的效果更好。但是,要想在 IIS 6.0 中启用 gzip 压缩可能没那么方便,IIS 的属性对话框里找不到设置它的地方。IIS 团队将卓越的 gzip 压缩能力内建在服务器中,但忽视了建立一个启用压缩特性的管理用户界面。要想启用 gzip 压缩机制,你必须深入到 IIS 的 XML 配置设置内部(必须对之相当熟悉才能配置)。顺便提一下,在此感谢 OrcsWeb 的 Scott Forsyth 帮我解决了在 OrcsWeb 数个 http://www.asp.net/  服务器上的这个问题。
  与其在本文中包含整个过程,还不如阅读 Brad Wilson 在 IIS6 Compression 上的文章。微软知识库也有一篇关于为ASPX启用压缩特性的文章:Enable ASPX Compression in IIS。但是,还必须注意一点,动态压缩与内核缓存由于某些实现细节的原因,其在 IIS 6.0 中是相互排斥的。

技巧 10——服务器控件的可视状态

  可视状态(View State)对于 ASP.NET 来说是个奇特的名字,它在所产生的页面中隐藏输入域以存储某些状态数据。当页面被发回服务器,该服务器能解析,检查其有效性并将这个状态数据应用到页面的控件树中。可视状态是一种非常强大的能力,因为它允许状态被客户端持续化并且它不需要cookies 或 服务器内存来存储该状态。许多 ASP.NET 服务器控件使用可视状态来持续化与页面元素交互期间所作的设置,例如,对数据进行分页时保存当前页显示页。
  然而,使用可视状态有许多不利之处,首先,不论是在请求的时候还是提供服务的时候,它都增加造成整个页面的负担。当序列化或反序列化被返回服务器的可视状态数据时还产生一些附加的开销。最终可视状态会增加服务器的内存分配。
  最著名的服务器控件要数 DataGrid 了,使用可视状态有过之而无不及,即便是在不需要使用的时候也是如此。ViewState 属性默认是启用的,但如果你不需要它,可以在页面控件级或页面级关闭它。在某个控件中,只要将 EnableViewState 设置为 false,或者在页面里使用如下全局设置:

<%@ Page EnableViewState="false" %>
  如果在某页面中不进行回发,或每次请求页面时总是重新产生控件,那么你应该在页面级禁用可视状态。

结论

  我已经向你提供了一些我认为有用的编写高性能 ASP.NET 应用程序的技巧。正如我在本文开头时所讲的那样,这是一些很初级的指南,而不是 ASP.NET 性能方面的最终定论。(更多有关改进 ASP.NET 应用程序性能方面的信息请参见:Improving ASP.NET Performance.)只有通过自己的经验方能找到最佳途径来解决具体的性能问题。不管怎样,在你解决问题的过程中,这些技巧多少会对你有所裨益的。在软件开发过程中,每一个应用都有其独特的一面,没有什么东西是绝对的。

——常见的性能神话

  最常见的神话之一是 C# 代码比 Visual Basic 代码快。这样的说法是站不住脚的,虽然在 Visual Basic 中存在一些 C# 没有的性能阻碍行为,比如显式地声明类型。但是如果遵循良好的编程实践,没有理由说明 Visual Basic 和 C# 代码不能以几乎同样的性能执行。简单说来,相同的代码产生相同的结果。
  另一个神话是后台代码比内联代码快,这是绝对不成立的。性能与你的 ASP.NET 应用程序代码在哪没有什么关系,无论是后台代码文件还是内联在 ASP.NET 页面。有时我更喜欢使用内联代码,因为变更不会产生后台代码那样的更新成本。例如,使用后台代码必须更新整个后台 DLL,那时一个可能引起惊慌的主张。
  第三个神话是组件比页面要快。这在经典的 ASP 中是存在的,因为编译的 COM 服务器要比 VBScript 快得多。但是对于页面和组件都是类的 ASP.NET 来说则不然。不论你的代码是以后台代码形式内联在页面,还是分离的组件,所产生的性能差别不大。只是这种组织形式能更好地从逻辑上对功能进行分组,在性能上没有差别。
  我想澄清的最后一个神话是用 Web 服务来实现两个应用程序之间各个功能。Web 服务应该被用于连接异构系统或提供系统功能及行为的远程访问。不应该将它用于两个相同系统的内部连接。虽然使用起来很容易,但有很多其它更好的可选方法。最糟的事情莫过于将 Web 服务用于相同服务器上 ASP 和 ASP.NET 应用程序之间的通讯,我已经不厌其烦地对之进行了说明。

 


komazr 发表于 >2006-2-18 15:05:02  [全文] [评论] [引用] [推荐] [档案] [推给好友] [收藏到网摘]
 

2006-2-18
在本窗口中打开一个新的连接

target(目标)== _parent;

 

komazr 发表于 >2006-2-18 15:00:17  [全文] [评论] [引用] [推荐] [档案] [推给好友] [收藏到网摘]
 

2006-2-17
批量生成缩略图

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

using System.Threading;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms.Design;

namespace Image
{
 public class ImageConvert
 {
  public static void ShowThumbnail(string oldfile, string newfile, int h, int w)
  {
  
   System.Drawing.Image img = System.Drawing.Image.FromFile(oldfile);
   System.Drawing.Image.GetThumbnailImageAbort myCallback = new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback);

   int oldh = img.Height;
   int oldw = img.Width;

   int newh,neww;

   double h1 = oldh*1.0/h;
   double w1 = oldw*1.0/w;

   double f = (h1>w1)? h1:w1;

   if(f < 1.0)
   {
    newh = oldh;
    neww = oldw;
   }
   else
   {
    newh = (int)(oldh/f);
    neww = (int)(oldw/f);
   }

   System.Drawing.Image myThumbnail = img.GetThumbnailImage(neww, newh, myCallback, IntPtr.Zero);

   myThumbnail.Save(newfile, System.Drawing.Imaging.ImageFormat.Jpeg);

   img.Dispose();
   myThumbnail.Dispose();
  }
  private static bool ThumbnailCallback()
  {
   return false;
  }
 }


 public class FolderDialog : FolderNameEditor
 {
  FolderNameEditor.FolderBrowser fDialog = new System.Windows.Forms.Design.FolderNameEditor.FolderBrowser();
  public FolderDialog()
  {
  }
  public DialogResult DisplayDialog()
  {
   return DisplayDialog("请选择一个文件夹";
  }

  public DialogResult DisplayDialog(string description)
  {
   fDialog.Description = description;
   return fDialog.ShowDialog();
  }
  public string Path
  {
   get
   {
    return fDialog.DirectoryPath;
   }
  }
  ~FolderDialog()
  {
   fDialog.Dispose();
  }
 }


 /// <summary>
 /// Form1 的摘要说明。
 /// </summary>
 public class Form1 : System.Windows.Forms.Form
 {
  private System.Windows.Forms.LinkLabel linkLabel1;
  private System.Windows.Forms.LinkLabel linkLabel2;
  private System.Windows.Forms.TextBox path1;
  private System.Windows.Forms.TextBox path2;
  private System.Windows.Forms.TextBox width;
  private System.Windows.Forms.TextBox height;
  private System.Windows.Forms.ListView listView1;
  private System.Windows.Forms.LinkLabel linkLabel3;
  private System.Windows.Forms.LinkLabel linkLabel4;
  private System.Windows.Forms.ColumnHeader columnHeader1;
  private System.Windows.Forms.ColumnHeader columnHeader2;
  private System.Windows.Forms.ColumnHeader columnHeader3;
  private System.Windows.Forms.ColumnHeader columnHeader4;
  private System.Windows.Forms.ColumnHeader columnHeader5;
  private System.Windows.Forms.ColumnHeader columnHeader6;

  private ArrayList threads = new ArrayList();
  private ArrayList images = new ArrayList();
  /// <summary>
  /// 必需的设计器变量。
  /// </summary>
  private System.ComponentModel.Container components = null;

  public Form1()
  {
   //
   // Windows 窗体设计器支持所必需的
   //
   InitializeComponent();

   //
   // TODO: 在 InitializeComponent 调用后添加任何构造函数代码
   //
  }

  /// <summary>
  /// 清理所有正在使用的资源。
  /// </summary>
  protected override void Dispose( bool disposing
  {
   if( disposing
   {
    if (components != null)
    {
     components.Dispose();
    }
   }
   base.Dispose( disposing ;
  }

  #region Windows 窗体设计器生成的代码
  /// <summary>
  /// 设计器支持所需的方法 - 不要使用代码编辑器修改
  /// 此方法的内容。
  /// </summary>
  private void InitializeComponent()
  {
   this.linkLabel1 = new System.Windows.Forms.LinkLabel();
   this.linkLabel2 = new System.Windows.Forms.LinkLabel();
   this.path1 = new System.Windows.Forms.TextBox();
   this.path2 = new System.Windows.Forms.TextBox();
   this.width = new System.Windows.Forms.TextBox();
   this.height = new System.Windows.Forms.TextBox();
   this.listView1 = new System.Windows.Forms.ListView();
   this.linkLabel3 = new System.Windows.Forms.LinkLabel();
   this.linkLabel4 = new System.Windows.Forms.LinkLabel();
   this.columnHeader1 = new System.Windows.Forms.ColumnHeader();
   this.columnHeader2 = new System.Windows.Forms.ColumnHeader();
   this.columnHeader3 = new System.Windows.Forms.ColumnHeader();
   this.columnHeader4 = new System.Windows.Forms.ColumnHeader();
   this.columnHeader5 = new System.Windows.Forms.ColumnHeader();
   this.columnHeader6 = new System.Windows.Forms.ColumnHeader();
   this.SuspendLayout();
   //
   // linkLabel1
   //
   this.linkLabel1.Location = new System.Drawing.Point(456, 16);
   this.linkLabel1.Name = "linkLabel1";
   this.linkLabel1.Size = new System.Drawing.Size(32, 16);
   this.linkLabel1.TabIndex = 0;
   this.linkLabel1.TabStop = true;
   this.linkLabel1.Text = "浏览";
   this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked);
   //
   // linkLabel2
   //
   this.linkLabel2.Location = new System.Drawing.Point(456, 48);
   this.linkLabel2.Name = "linkLabel2";
   this.linkLabel2.Size = new System.Drawing.Size(32, 16);
   this.linkLabel2.TabIndex = 1;
   this.linkLabel2.TabStop = true;
   this.linkLabel2.Text = "浏览";
   this.linkLabel2.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel2_LinkClicked);
   //
   // path1
   //
   this.path1.Location = new System.Drawing.Point(16, 16);
   this.path1.Name = "path1";
   this.path1.Size = new System.Drawing.Size(432, 21);
   this.path1.TabIndex = 2;
   this.path1.Text = "";
   //
   // path2
   //
   this.path2.Location = new System.Drawing.Point(16, 48);
   this.path2.Name = "path2";
   this.path2.Size = new System.Drawing.Size(432, 21);
   this.path2.TabIndex = 3;
   this.path2.Text = "";
   //
   // width
   //
   this.width.Location = new System.Drawing.Point(80, 80);
   this.width.Name = "width";
   this.width.Size = new System.Drawing.Size(72, 21);
   this.width.TabIndex = 4;
   this.width.Text = "";
   //
   // height
   //
   this.height.Location = new System.Drawing.Point(216, 80);
   this.height.Name = "height";
   this.height.Size = new System.Drawing.Size(72, 21);
   this.height.TabIndex = 5;
   this.height.Text = "";
   //
   // listView1
   //
   this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
                      this.columnHeader1,
                      this.columnHeader2,
                      this.columnHeader3,
                      this.columnHeader4,
                      this.columnHeader5,
                      this.columnHeader6});
   this.listView1.Location = new System.Drawing.Point(16, 112);
   this.listView1.Name = "listView1";
   this.listView1.Size = new System.Drawing.Size(472, 152);
   this.listView1.TabIndex = 6;
   this.listView1.View = System.Windows.Forms.View.Details;
   //
   // linkLabel3
   //
   this.linkLabel3.Location = new System.Drawing.Point(304, 80);
   this.linkLabel3.Name = "linkLabel3";
   this.linkLabel3.Size = new System.Drawing.Size(32, 16);
   this.linkLabel3.TabIndex = 7;
   this.linkLabel3.TabStop = true;
   this.linkLabel3.Text = "添加";
   this.linkLabel3.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel3_LinkClicked);
   //
   // linkLabel4
   //
   this.linkLabel4.Location = new System.Drawing.Point(376, 80);
   this.linkLabel4.Name = "linkLabel4";
   this.linkLabel4.Size = new System.Drawing.Size(32, 16);
   this.linkLabel4.TabIndex = 8;
   this.linkLabel4.TabStop = true;
   this.linkLabel4.Text = "开始";
   this.linkLabel4.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel4_LinkClicked);
   //
   // columnHeader1
   //
   this.columnHeader1.Text = "源";
   this.columnHeader1.Width = 122;
   //
   // columnHeader2
   //
   this.columnHeader2.Text = "目的";
   this.columnHeader2.Width = 121;
   //
   // columnHeader3
   //
   this.columnHeader3.Text = "宽";
   this.columnHeader3.Width = 49;
   //
   // columnHeader4
   //
   this.columnHeader4.Text = "高";
   this.columnHeader4.Width = 42;
   //
   // columnHeader5
   //
   this.columnHeader5.Text = "文件数";
   //
   // columnHeader6
   //
   this.columnHeader6.Text = "完成数";
   //
   // Form1
   //
   this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
   this.ClientSize = new System.Drawing.Size(504, 294);
   this.Controls.Add(this.linkLabel4);
   this.Controls.Add(this.linkLabel3);
   this.Controls.Add(this.listView1);
   this.Controls.Add(this.height);
   this.Controls.Add(this.width);
   this.Controls.Add(this.path2);
   this.Controls.Add(this.path1);
   this.Controls.Add(this.linkLabel2);
   this.Controls.Add(this.linkLabel1);
   this.Name = "Form1";
   this.Text = "Form1";
   this.ResumeLayout(false);

  }
  #endregion

  /// <summary>
  /// 应用程序的主入口点。
  /// </summary>
  [STAThread]
  static void Main()
  {
   Application.Run(new Form1());
  }

  private void linkLabel1_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
  {
   FolderDialog dlg = new FolderDialog();
   if(dlg.DisplayDialog()==DialogResult.OK)
    path1.Text = dlg.Path;

  }

  private void linkLabel2_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
  {
   FolderDialog dlg = new FolderDialog();
   if(dlg.DisplayDialog()==DialogResult.OK)
    path2.Text = dlg.Path;
  }

  private void linkLabel3_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
  {
   string[] img = Directory.GetFiles(path1.Text, "*.jpg";

   listView1.Items.Add(new ListViewItem(new string[]{path1.Text, path2.Text, width.Text, height.Text, img.Length.ToString(), "0"}));
  }

  private void linkLabel4_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
  {
   foreach(ListViewItem item in listView1.Items)
   {
    Thread t = new Thread(new ThreadStart(Process));
    t.Start();
    threads.Add(t);
   }
  }

  private void Process()
  {
   int index = threads.IndexOf(Thread.CurrentThread);
   ListViewItem item = listView1.Items[index];
   string path1 = item.SubItems[0].Text;
   string path2 = item.SubItems[1].Text;
   int width = int.Parse(item.SubItems[2].Text);
   int height = int.Parse(item.SubItems[3].Text);
   int i = 0;
   foreach(string file1 in Directory.GetFiles(path1, "*.jpg")
   {
    i++;
    string file2 = path2 + @"/" + Path.GetFileName(file1);
    ImageConvert.ShowThumbnail(file1,file2, height, width);
    lock(listView1)
    {
     listView1.Items[index].SubItems[5].Text = i.ToString();
    }
   }
  }
 }
}

 


komazr 发表于 >2006-2-17 18:12:20  [全文] [评论] [引用] [推荐] [档案] [推给好友] [收藏到网摘]
 

2006-2-16
管理图片库

前台代码:
<%@ Page language="c#" Codebehind="DataGridImage.aspx.cs" AutoEventWireup="false" Inherits="NetTest.DataGridImage" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
 <HEAD>
  <title>DataGridImage</title>
  <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
  <meta name="CODE_LANGUAGE" Content="C#">
  <meta name="vs_defaultClientScript" content="JavaScript">
  <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
 </HEAD>
 <body MS_POSITIONING="GridLayout">
  <form id="Form1" method="post" runat="server">
   <table align="center" border="1" width="60%">
    <TBODY>
     <tr>
      <td align="center"><font style="FONT-WEIGHT: bold; FONT-SIZE: 11pt">DataGrid中显示数据库中的图片</font></td>
     </tr>
     <tr>
      <td>
       <aspataGrid id="DataGrid1" runat="server" AutoGenerateColumns="False" width="100%">
        <Columns>
         <asp:TemplateColumn>
          <ItemTemplate>
           <FONT face="宋体">
            <TABLE id="Table1" cellSpacing="1" cellPadding="1" width="100%" border="0">
             <TR>
              <TD colspan="2"><FONT style="FONT-SIZE: 10pt">图片名称:</FONT> <FONT style="FONT-SIZE: 10pt">
                <asp:Label id="lbImageName" runat="server" Text='<%# DataBinder.Eval(Container,"DataItem.ImageName"%>'>
                </asp:Label></FONT></TD>
             </TR>
             <TR>
              <TD><FONT style="FONT-SIZE: 10pt">图片:</FONT>
               <asp:Image id=Imagebutton1 Width=100 Height=100 runat="server" ImageUrl='<%# "ReadImage.aspx?ImageID="+DataBinder.Eval(Container,"DataItem.ID"%>'>
               </asp:Image>
              </TD>
              <td>
               <IMG width=100 height=100 alt="" src='<%# "ReadImage.aspx?ImageID="+DataBinder.Eval(Container,"DataItem.ID"%>'">
              </td>
             </TR>
            </TABLE>
           </FONT>
          </ItemTemplate>
         </asp:TemplateColumn>
        </Columns>
       </aspataGrid></td>
     </tr>
    </TBODY>
   </table>
  </form>
 
</HTML>

 
 
后台代码: using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;

namespace NetTest
{
 /// <summary>
 /// DataGridImage 的摘要说明。
 /// </summary>
 public class DataGridImage : System.Web.UI.Page
 {
  protected System.Web.UI.WebControls.DataGrid DataGrid1;
  private string str="server=localhost;uid=sa;pwd=;database=northwind";
  private void Page_Load(object sender, System.EventArgs e)
  {
   if(!IsPostBack)
   {
    FillData();
   }
  }

  #region Web 窗体设计器生成的代码
  override protected void OnInit(EventArgs e)
  {
   //
   // CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
   //
   InitializeComponent();
   base.OnInit(e);
  }
 
  /// <summary>
  /// 设计器支持所需的方法 - 不要使用代码编辑器修改
  /// 此方法的内容。
  /// </summary>
  private void InitializeComponent()
  {   
   this.Load += new System.EventHandler(this.Page_Load);

  }
  #endregion

  private void FillData()//绑定DATAGRID
  {
   SqlConnection cn=new SqlConnection(str);
   SqlCommand cmd=new SqlCommand();
   cmd.CommandText="SELECT * from UpImage";
   cmd.Connection=cn;
   cn.Open();
   SqlDataAdapter da=new SqlDataAdapter();
   da.SelectCommand=cmd;
   DataSet ds=new DataSet();
   da.Fill(ds,"Images";
   DataGrid1.DataSource=ds.Tables["Images"];
   DataGrid1.DataBind();
   cn.Close();
  }
 }
}

 
ReadImage.aspx(根据传过来的图片的编号,取得图片。只要建一个页面就可以了,不用放置任何控件)
后台代码: using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;
namespace NetTest
{
 /// <summary>
 /// ReadImage 的摘要说明。
 /// </summary>
 public class ReadImage : System.Web.UI.Page
 {
 
  private void Page_Load(object sender, System.EventArgs e)
  {
   string conn="server=localhost;uid=sa;pwd=;database=northwind";
   SqlConnection cn=new SqlConnection(conn);
   SqlCommand cmd=new SqlCommand();
   cmd.CommandText="select Image from UpImage where ID='"+this.Request["ImageID"]+"'";
   cmd.Connection=cn;
   cn.Open();
   this.Response.ContentType="image/*";
   SqlDataReader dr=cmd.ExecuteReader();
   while(dr.Read())
   {
    this.Response.BinaryWrite((byte[])dr["Image"]);
   }
   cn.Close();
  }

  #region Web 窗体设计器生成的代码
  override protected void OnInit(EventArgs e)
  {
   //
   // CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
   //
   InitializeComponent();
   base.OnInit(e);
  }
 
  /// <summary>
  /// 设计器支持所需的方法 - 不要使用代码编辑器修改
  /// 此方法的内容。
  /// </summary>
  private void InitializeComponent()
  {   
   this.Load += new System.EventHandler(this.Page_Load);

  }
  #endregion

 }
}
 


 
 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值