ASP.NET技术开发http://www.singletowm.com

http://www.singletowm.com

常用链接

统计

ASP.NET经典网站

最新评论

2009年1月20日 #

ASP.NET非TreeView的无限分类示例(zhuan)

采用递归算法.
其中表结构都是如下:
表名称是ClassName
id                     主键
sid                    对应的父类的id
ClassName        对应类别的名称.
代码段一:
1function loadNextType(upid,rank)
2    dim rs
3    set rs="select * from classname where sid="&upid
4    do while not rs.eof
5       loadNextType=loadNextType &rs("ClassName")&"<br>"& string("-",rank) & loadNextType(rs("id"),rank+1)
6       rs.movenext
7    loop
8end function调用时:response.write(loadNextType(0,0))

另外一段代码就跟上面原理就一样的.只不过是加入了树型结构的显示方式.
代码段二:
 1'定义第一级分类
 2sub mainfl()
 3       dim rs
 4       set rs=conn.execute("select id,F_id,F_name from ClassNae where sid=0 order by id desc")
 5       if not rs.eof then
 6          do while not rs.eof
 7          response.write rs(2) & "<br>"
 8          call subfl(rs(0),"  |-") '循环子级分类
 9          rs.movenext
10          if rs.eof then exit do '防上造成死循环
11          loop
12          end if
13end sub
14'定义子级分类
15sub subfl(fid,strdis)
16       dim rs1
17       set rs1=conn.execute("select id,sid,ClassName from ClassName where sid="&fid&" order by id desc")
18       if not rs1.eof then
19       do while not rs1.eof
20       response.write rs1(2) & "<br>"
21       call subfl(rs1(0),"  "&strdis) '递归子级分类
22       rs1.movenext
23       if rs1.eof then
24       rs1.close
25       exit sub
26       end if
27       loop
28       end if
29end sub
我参考上面的代码改成了asp.net版本的无限分类.开始遇到了语法上的限制.当时的处理是直接把rs换成SqlDataReader,然后加以修改,代码如下(错误代码):
测试数据库的表Tree结构是:id,ParentID,Name。
 1private void Display(string parentid/**//*, int rank*/)
 2    {
 3        SqlDataReader dr;
 4        SqlCommand cmd;
 5        String strSQL;
 6
 7        strSQL = "Select * From Tree Where ParentID =" + parentid + "Order By ID DESC";
 8        cmd = new SqlCommand(strSQL,conn);
 9        //cmd.Connection.Open();
10
11        using(dr = cmd.ExecuteReader())
12        {
13            while(dr.Read())
14            {
15                Response.Write(dr["Name"].ToString() + "<br>");
16                Display(dr["ID"].ToString());
17            }
18        }
19        cmd.Connection.Close();
20    }调用使用Display("0").
错误原因是SqlDataReader每次使用之后都需要关闭,所以DataReader是不可以嵌套使用的.
后来我改成了用DataTable的形式实现了无限分类,但是感觉这种方式的效率不高,需要改进(还在研究中)
修改后的代码如下:
 1private void Display(string parentid, String space)
 2    {
 3        DataTable dt;
 4        String strSQL;
 5        strSQL = "Select * From Tree Where ParentID =" + parentid + " Order By ID DESC";
 6
 7        SqlDataAdapter sda = new SqlDataAdapter(strSQL, conn);
 8        DataSet ds = new DataSet();
 9        sda.Fill(ds, "Tree");
10        dt = ds.Tables["Tree"];
11
12        if (dt.Rows.Count > 0)
13        {
14            foreach (DataRow dr in dt.Rows)
15            {
16                strOpinion += space + "<font color=red>[" + dr["Name"].ToString() +"<br>";
17                Display(dr["ID"].ToString(), "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + space, false);
18            }
19        }
20    }调用时候使用Display("0","↓→→")。

ASP.NET技术网站 http://www.singletowm.com/

posted @ 2009-01-20 11:34 linxiao1314 阅读(282) 评论(0) 编辑

2008年12月31日 #

关于ASP.NET Web 部件连接的引入

创建用于 ASP.NET 2.0 应用程序的 Web 部件

  您可以用两种方法创建 Web 部件。第一种方法涉及创建一个自定义的 Web 部件类,该类从 System.Web.UI.WebControls.WebParts 命名空间中定义的 WebPart 类继承。使用该方法时,将自定义的 Web 部件类打包到一个程序集 DLL 中通常是有意义的,因为这样可以提供对重用、版本控制和 Visual Studio® 2005 集成的更多控制。如果您对使用以前的 ASP.NET 版本生成自定义控件很熟悉,则许多相同的技术适用于将自定义的 Web 部件生成到 DLL 程序集中。

  用于创建 ASP.NET 2.0 Web 部件的第二种方法涉及使用用户控件。虽然该方法不产生相同的重用和版本控制级别,但是它的确允许您使用 Visual Studio 窗体设计器来创建 Web 部件的用户界面部分。如果您想通过将用于用户输入、验证和数据绑定的控件拖放到设计界面上来创建应用程序,则该方法适合于您。当然,如果您已经花时间创建了一个您想用作 Web 部件的用户控件,它也是个可以采用的好方法。

  当创建一个专门设计为 Web 部件的用户控件时,建议您实现 IWebPart 接口。这样,Web 部件后台的代码就可通过编程方式分配自己的几个内部 Web 部件属性,如它的 Title 和 TitleIconUrl。

  本月专栏附带的代码示例使用一个名为 WebPartBase 的自定义基类,该基类从 UserControl 继承并实现 IwebPart。该基类的定义部署在 App_Code 目录中名为 WebPartBase.vb 的源文件中。每当您使用用户控件创建一个新 Web 部件时,只需在该代码隐藏文件中更改该基类以利用该技术:

Partial Class WebParts_Customers
        Inherits WebPartBase

  Sub New()
    Title = "Northwind Customer List"
    TitleIconImageUrl = "~\img\Customers.gif"
  End Sub

End Class

  设计可连接的 Web 部件

  使用 Web 部件连接,您可以使用户更轻松地形象化数据各项之间存在的关系。例如,Web 部件连接可以建模一个主-从方案,其中显示客户列表的 Web 部件连接到另一个显示当前所选客户详细信息的 Web 部件。图 1 的示例说明这种设计可能生成的用户界面外观。


  Web 部件连接还可用于建模一对多关系。例如,显示客户列表的 Web 部件可以连接到另一个显示针对当前所选客户的所有定单的 Web 部件。

  通常使用 Web 部件连接建模的另一个方案是表单查询。在这种方案中,一个 Web 部件提供一个用户界面,该用户界面允许用户选择查询数据(如数据库表)时所用的搜索或筛选条件。然后,该 Web 部件连接到另一个显示查询结果的 Web 部件。Web 部件连接用于在运行查询前,将筛选条件从一个 Web 部件传递到另一个 Web 部件。

  Web 部件连接基于提供者和使用者的概念。提供者 Web 部件通过一个编程接口为一个或多个使用者 Web 部件提供信息。提供者和使用者之间交换的信息可以是简单的数据项(如数字或字符串),也可以是较特殊的内容(如对一个复杂数组或自定义对象集合的引用)。

  如果针对 Windows® SharePoint® Services 2.0 (WSS) 编写了 Web 部件,您可能已经熟悉它用于连接 Web 部件的模型。在 WSS 中,Web 部件只能使用一组预定义的接口对连接。这些接口对的示例包括 ICellProvider 和 ICellConsumer,以及 IRowProvider 和 IRowConsumer。

  ASP.NET 2.0 中的 Web 部件连接模型比 WSS 中的旧式模型更容易、更灵活,因为您可以使用自己的自定义接口。这意味着您无需使用由 Microsoft 人员创建的接口定义。而且,您无需对接口对进行任何操作,它们必须由提供者和使用者实现。使用 ASP.NET 2.0,只有提供者需要实现一个接口。

  要了解其工作方式,我们先在两个 Web 部件之间创建一个连接。对于我要在本月专栏中提供的示例,我决定使用 Northwind 数据库,因为它有一个 Customers 表和一个 Orders 表。这使我能为您展示如何针对主-从和一对多关系设计 Web 部件。有一点需要注意,如果使用 SQL Server® 2005,则在产品安装过程中并不安装该示例 Northwind 数据库。要安装它,您必须下载并运行 Microsoft Web 站点上可用的脚本(请参阅 Microsoft SQL Server 主页)。

  现在,假设您要在一个显示客户列表的 Web 部件和一个显示当前所选客户的详细信息的客户 Web 部件之间建立一个 Web 部件连接,如图 1所示。显示客户列表的 Web 部件将扮演提供者的角色,而显示当前所选客户的详细信息的 Web 部件则作为使用者。在这种情况下,您希望提供者为使用者提供当前所选客户的 CustomerID 字段。

  首先,创建一个名为 ICustomerIDProvider 的简单接口:

Public Interface ICustomerIDProvider
    ReadOnly Property CustomerID() As String
End Interface

  在本月专栏附带的代码示例中,我使用带有 SqlDataSource 和 GridView 控件的用户控件创建了提供者 Web 部件,以显示来自 Northwind 的客户。Web 部件源文件是 Customers.ascx 和 Customers.ascx.vb,如清单 2 所示。

Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts

Partial Class WebParts_Customers
        Inherits WebPartBase
        Implements ICustomerIDProvider

    Sub New()
        Title = "NorthWind Customer List"
        TitleIconImageUrl = "~\img\Customers.gif"
    End Sub

    <ConnectionProvider("Customer ID Provider")> _
    Public Function GetCustomerProvider() As ICustomerIDProvider
        Return Me
    End Function

    Public ReadOnly Property CustomerID() As String _
            Implements ICustomerIDProvider.CustomerID
        Get
            If gridCustomers.SelectedDataKey Is Nothing Then
                 Return String.Empty
            Else
                 Return Me.gridCustomers.SelectedDataKey.Value
            End If
        End Get
    End Property
End Class

  您可以看到,WebParts_Customers 作为提供者并实现用于该 Web 部件连接的接口。在本例中,WebParts_Customers 实现 ICustomerIDProvider 接口。虽然最常见的模式是提供者本身实现该连接接口,但是它不需要这么做。唯一的实际要求是,ConnectionProvider 方法返回指定接口的一个实例。因此,作为替代方案,该提供者 Web 部件可以返回一个实现该连接接口的 helper 对象。如果一个提供者 Web 部件具有多个接口类型相同的连接点,这通常是有必要的。

  通过返回 GridView 控件的 SelectedDataKey 属性的值,WebParts_Customers 类实现 CustomerID 属性。GridView 控件已经进行了设置以便显示来自 Northwind Customers 表的记录,而且它还将 CustomerID 字段识别为 SelectedDataKey 值。

  您应该注意到 WebParts_Customers 类有一个名为 GetCustomerProvider 的方法,该方法具有一个根据 ICustomerIDProvider 接口定义的返回类型。在这种情况下,由于 Web 部件本身实现所需的接口,因此 GetCustomerProvider 可以只返回对该类的当前实例的 Me 引用。您还要注意该方法已经使用 ConnectionProvider 属性进行了定义:

<ConnectionProvider("Customer ID Provider")>

  WebPartManager 负责在运行时连接 Web 部件。当 WebPartManager 看到一个 Web 部件包含一个使用 ConnectionProvider 属性定义的方法时,它知道该 Web 部件公开一个连接点,因此可以作为提供者并且连接到使用者。当需要将两个 Web 部件连接在一起时,WebPartManager 将调用 GetCustomerProvider 方法获取对提供者 Web 部件的强类型引用。

  定义一个提供者 Web 部件是否接受到使用者的多个连接是可能的。在某种情况下,一个提供者同时具有到多个使用者的连接是很有用的。在其他情况下,您可能想限制提供者,使它最多可以有一个到使用者 Web 部件的连接。默认情况下,提供者允许多个连接,而使用者则不然。要改变这一点,当您应用 ConnectionProvider 属性时,可以使用命名参数 AllowsMultipleConnections,如下所示:

<ConnectionProvider("Customer ID Provider", _
    AllowsMultipleConnections:=False)>

  既然您已经看到如何创建一个在提供者 Web 部件中公开连接点的方法,我们来看看这在使用者 Web 部件中是如何实现的。使用者 WebPart 通过提供一个使用 ConnectionConsumer 属性定义的方法来公开连接点。使用者的连接点方法与提供者的连接方法不同,因为它不定义返回值。相反,它获取一个用该连接的接口类型定义的参数:

<ConnectionConsumer("Customer ID Consumer")>  _
Sub RegisterCustomerProvider(ByVal provider As ICustomerIDProvider)
    ... ' implementation
End Sub

  请记住,提供者的连接点方法名称与使用者的连接点方法名称并不重要。唯一需要注意的是,每个方法分别使用 ConnectionProvider 属性和 ConnectionConsumer 属性进行定义。

  现在,我们看看 WebPartManager 在运行时是如何建立该连接的。WebPartManager 调用提供者的连接点方法以获取对提供者对象的引用。接下来,WebPartManager 调用使用者的连接点方法,以便为它传递一个对提供者的强类型引用。

  一旦 WebPartManager 完成它的工作之后,使用者 Web 部件就有一个返回到提供者 Web 部件的活动连接。此时,使用者可以使用该引用访问接口中定义的方法和属性,从而与提供者直接交互。但是,ASP.NET 小组建议使用者 Web 部件在 PreRender 阶段之前不应使用提供者接口上的方法和属性。具体说来,它们不应该在 方法本身中使用提供者接口上的方法和属性。原因是这些连接可能彼此依赖。您可能有一个连接到 ProviderConsumerWebPart 进而连接到 ConsumerWebPart 的 ProviderWebPart。在这两个连接建立之前,ConsumerWebPart 无法查询提供者接口,而且连接建立的顺序取决于框架。

Partial Class WebParts_CustomerDetails
        Inherits WebPartBase

    Sub New()
        Me.Title = "Customer Details"
        Me.TitleIconImageUrl = "~\img\Customer.gif"
    End Sub

    Private provider As ICustomerIDProvider

    <ConnectionConsumer("Customer ID Consumer")> _
    Sub RegisterCustomerProvider(ByVal provider As ICustomerIDProvider)
        Me.provider = provider
    End Sub

    Protected Sub SqlDataSource1_Selecting(ByVal sender As Object, _
            ByVal e As SqlDataSourceSelectingEventArgs) _
            Handles SqlDataSource1.Selecting
        SqlDataSource1.FilterExpression = _
            "CustomerID='" & provider.CustomerID & "'"
    End Sub

End Class

  清单 3 显示 CustomerDetails.ascx.vb 中使用者 Web 部件的完整代码列表。您可以看到,使用者 Web 部件负责持续引用,以便可以跟踪到提供者的连接。该使用者 Web 部件包含一个名为 provider 的私有字段,该字段是根据 ICustomerIDProvider 接口定义的。

  当 WebPartManager 调用 RegisterCustomerProvider 时,使用者获取传入的引用参数并将它分配给提供者字段。当提供者字段分得该引用后,使用者 Web 部件就可以与提供者 Web 部件直接交互。为连接设计该接口时,您应该添加将提供您所需交互的任何方法和属性。

  在某些情况下,使用者 Web 部件可能设计为无论是否有到提供者的活动连接都正常工作。在这种设计中,当提供者字段有一个 Nothing 值时,您可能希望将临时代码添加到正常工作的使用者 Web 部件中:

If provider IsNot Nothing Then
    ... ' interact with provider
Else
    ... ' contingency code goes here if required
End If

  为一个 Web 部件连接计时

  当您开始设计支持连接的 Web 部件时,了解所涉及的计时是非常重要的。图 4 显示在 HTTP GET 期间运行提供者 Web 部件和使用者 Web 部件的页面的一小部分。虽然有更多在 HTTP POST 期间激发的页面级事件,但是连接建立时的计时则保持相同。


  图 4 中显示的跟踪信息阐释了对于标准的 ASP.NET 2.0 页面级事件而言,每个连接方法何时激发。您应该能够从该跟踪信息中看到,WebPartManager 在页面级 LoadComplete 命令中将 Web 部件连接在一起。

  需要牢记的是,当页面级事件 PreInit、Init、PreLoad 和 Load 执行时,Web 部件连接尚未建立。这意味着您绝不应该尝试访问使用者 Web 部件的处理程序方法(它绑定到这些事件之一)中的提供者。在尝试访问提供者 Web 部件之前,使用者 Web 部件中的代码必须等待 LoadComplete 事件执行完毕。

  在本示例中,使用者 Web 部件处理 SqlDataSource 控件的 Selecting 事件,该事件在页面级 PreRender 事件中激发。此时,访问提供者并检索客户 ID 是安全的。

  定义静态 Web 部件连接

  既然您已经看到如何创建支持连接的 Web 部件,并且了解了所涉及的计时,现在该探究如何将它们实际连接在一起了。您将看到,可以将标记直接添加到一个 Web 部件页面定义中,以便建立一个静态 Web 部件连接。也可以在运行时通过代码或用户交互动态建立 Web 部件连接。首先,我要展示如何在两个 Web 部件之间创建一个静态连接,因为这是最简单的方法。

  要在一个页面上的两个 Web 部件之间创建静态 Web 部件连接,需要将 StaticConnections 元素添加到 WebPartManager 标记中:

<asp:WebPartManager ID="WebPartManager1" runat="server">
    <StaticConnections>
        <asp:WebPartConnection ID="c1"
            ProviderID="Customers1"
            ConsumerID="CustomerDetails1" />
    </StaticConnections>
</asp:WebPartManager>

  要使该代码正常运行,名为 Customers1 的提供者 Web 部件和名为 CustomerDetails1 的使用者 Web 部件也必须在同一页面上的 Web 部件区域中静态定义和正确命名。

  需要牢记的是,每个页面只有一个 WebPartManager 控件。然而,在许多涉及 Web 部件的应用程序设计中,您会发现将 WebPartManager 添加到用户控件或母版页很方便,原因是可以在许多页面上重用它。

  当 Web 部件页面基于母版页,或者使用的是包含 WebPartManager 控件的用户控件时,您不能添加 WebPartManager 控件的第二个示例来定义 StaticConnections 标记。针对这些情况,ASP.NET 2.0 Web 部件控件集提供了 ProxyWebPartManager 控件。以下是关于如何使用它的示例:

<asp:ProxyWebPartManager ID="ProxyWebPartManager1" runat="server">
    <StaticConnections>
        <asp:WebPartConnection ID="c1"
            ProviderID="Customers1"
            ConsumerID="CustomerDetails1" />
    </StaticConnections>
</asp:ProxyWebPartManager>

  ProxyWebPartManager 控件的价值在于,它允许您在页面无法包含 WebPartManager 标记时,在页面级添加静态连接。在本专栏附带的示例页面 default.aspx 中,必须使用 ProxyWebPartManager 建立一个静态 Web 部件连接,原因是 WebPartManager 已经封装在名为 WebPartManagerPanel.ascx 的用户控件中。

  命名连接点

  在我目前生成的示例中,提供者 Web 部件和使用者 Web 部件之间的连接已经基于默认的连接点。但是,Web 部件连接方法提供一个命名连接点是可能的。要将一个命名连接点添加到提供者,您只需将第二个字符串参数添加到 ConnectionProvider 属性:

<ConnectionProvider("Customer ID Provider", "CustomerIDProvider")> _
Public Function GetCustomerProvider() As ICustomerIDProvider
    Return Me
End Function

  之所以使用命名连接点的一个原因是提供者或使用者可能有多个连接点,因此必须能区分它们。要将一个命名连接点添加到使用者 Web 部件,您可以将第二个字符串参数添加到 ConnectionConsumer 属性:

<ConnectionConsumer("Customer ID" & "Consumer", "CustomerIDConsumer")> _
Sub RegisterCustomerProvider(ByVal provider As ICustomerIDProvider)
    Me.provider = provider
End Sub

  当您开始使用命名连接点时,在页面级定义 StaticConnections 标记时,必须为 ProviderConnectionPointID 和 ConsumerConnectionPointID 提供两个额外的属性值。

  动态建立连接

  当您想将 Web 部件连接在一起时,有时却无法依赖静态 Web 部件连接。例如,如果您想连接通过自定义代码动态创建的 Web 部件,或者由使用 Web 部件目录将 Web 部件添加到页面的用户动态创建的 Web 部件,就会出现这种情况。

  在无法使用静态 Web 部件连接时,您必须使用动态技术连接 Web 部件。为此,可以使用自定义代码,或者使用 ASP.NET 2.0 Web 部件控件集附带的 ConnectionsZone 控件。

  让我们首先看一下创建两个 Web 部件并将它们动态连接在一起的自定义代码,如图 5 所示。该代码通过用户控件为提供者和使用者创建了 Web 部件实例,并将它们添加到宿主 Web 部件页面的现有 Web 部件区域。然后,该代码在它们之间建立一个连接。请注意,Web 部件和连接将保存为用户个性化信息的一部分,因此它们应该只添加到 WebPartManager 一次。如果您不想以这种方式保存 Web 部件和连接,也可以使用其他 API。


图 6 连接显示模式

  清单5:

'*** get WebPartManager object
Dim wpMgr As WebPartManager = _
    WebPartManager.GetCurrentWebPartManager(Me.Page)
'*** create and add provider Web Part
Dim uc1 As UserControl = Me.Page.LoadControl("~\WebParts\Customers.ascx")
uc1.ID = "wp1"
Dim wp1 As GenericWebPart = wpMgr.CreateWebPart(uc1)
wp1 = wpMgr.AddWebPart(wp1, LeftWebPartZone, 0)
'*** create and add consumer Web Part
Dim uc2 As UserControl = _
    Me.Page.LoadControl("~\WebParts\CustomerDetails.ascx")
uc2.ID = "wp2"
Dim wp2 As GenericWebPart = wpMgr.CreateWebPart(uc2)
wp2 = wpMgr.AddWebPart(wp2, RightWebPartZone, 0)
'*** get desired connection points for provider and consumer
Dim cp1 As ProviderConnectionPoint = _
  wpMgr.GetProviderConnectionPoints(wp1)("CustomerIDProvider")
Dim cp2 As ConsumerConnectionPoint = _
  wpMgr.GetConsumerConnectionPoints(wp2)("CustomerIDConsumer")
'*** dynamically establish Web Part connection
wpMgr.ConnectWebParts(wp1, cp1, wp2, cp2)

  您可以看到,清单 5 中显示的技术需要使用 ProviderConnectionPoint 对象和 ConsumerConnectionPoint。通过调用 WebPartManager 提供的方法并传递那些命名连接点的字符串标识符,可以检索这些对象。

  您和您的用户可以用来建立动态 Web 部件连接的另一种技术涉及到 ConnectionsZone 控件。要有效地使用该技术,您应该创建一个 Web 部件页面,其右侧有一个包含 ConnectionsZone 控件的任务窗格。当用户使该页面处于连接视图显示模式中时,Connect 命令将添加到公开连接点的每个 Web 部件的 Web 部件菜单中,如图 6 所示。

  当用户选择 Connect 命令时,Web 部件页面会显示 ConnectionsZone 控件,并允许用户查看该页面上所有可连接的 Web 部件的所有兼容连接点(请参见图 7)。使用该技术,您可以将使用者连接到提供者。同样,您也可以将提供者连接到使用者。


.NET

posted @ 2008-12-31 13:35 linxiao1314 阅读(127) 评论(0) 编辑

2008年12月26日 #

用.NET读取Flash格式文件信息

一直以来存在这么一个问题,就是当用户上传的Flash文件时都需要附带输入Flash的宽和高,否则显示的时候由于不知道这些数值而导致Flash比例不正常。

近日我做网站也涉及到了这方面的问题,于是打算解决一下。

首先在Google上搜索,可以找到获取Flash宽和高的java script,但是是在Flash载入后而不是之前,而且也没法动态更改object标记的宽和高,最重要的是有Flash Player的安全警告信息,所以放弃了在客户端读取,转而考虑服务器端。

在VS内导入flash.ocx控件,试图获取Flash文件信息,结果在调用TGetProperty()方法是总是以返回E_FAIL错误而失败,如果哪位高手知道如何在.NET下使用,欢迎指明。

想来想去,只剩下一个办法,也是最可行的办法,就是直接读取Flash文件并分析格式。

在Google上搜到 Macromedia Flash (SWF) File Format Specification Version 7 (http://www.xiaowowo.com/gt_book/new/flashfileformat.rar)

经过反复阅读和尝试,最终写出了 FlashInfo 类,调用方法如下:

FlashInfo flashInfo = new FlashInfo(@"c:\test.swf"); // 构造函数,参数是Flash文件地址
Console.WriteLine(string.Format("Version: {0}", flashInfo.Version)); // Flash版本
Console.WriteLine(string.Format("Compressed: {0}", flashInfo.IsCompressed)); //是否被压缩
Console.WriteLine(string.Format("Width: {0}", flashInfo.Width)); // Flash的宽度
Console.WriteLine(string.Format("Height: {0}", flashInfo.Height)); // Flash的高度
Console.WriteLine(string.Format("FrameRate: {0}", flashInfo.FrameRate)); // 帧速率
Console.WriteLine(string.Format("FrameCount: {0}", flashInfo.FrameCount)); // 总帧数
Console.WriteLine(string.Format("FileLength: {0}", flashInfo.FileLength)); // 未压缩时的文件大小
自从Flash格式版本6以后,增加了可压缩选项,用的是ZLib压缩,为了支持压缩格式,只好又在Google上找了一个ZLib .NET Wrapper (http://zlibnetwrapper.sourceforge.net/)

FlashInfo 类的源代码和编译好的库文件提供给有同样需求的朋友下载:http://files.cnblogs.com/gmm/FlashInfo.zip

ASP.NET技术网站:http://www.singletowm.com/

posted @ 2008-12-26 23:08 linxiao1314 阅读(193) 评论(0) 编辑

如何把图片插入到Excel里

在一篇帖子中有人询问如何能将用户照片放入Excel。
  先录制了一个宏,得到的结果是:
  ActiveSheet.Pictures.Insert("D:\tt.bmp").Select

  然而,在C#中,WorkSheet类似乎并不直接支持Pictures.Insert这样的方法。而在MSDN
  网站上,几篇Office开发文档介绍的也只是常见的Application、WorkBook、Sheet这些对
  象如何读写。最后,还是看了VBA的帮助,才找到了解决的办法,也仍然非常简单:





  Excel.Worksheet xSheet=(   Excel.Worksheet)xBook.Sheets[1]; 
  xSheet.Shapes.AddPicture("D:\\tt.bmp", MsoTriState.msoFalse  ,
  MsoTriState.msoTrue,10,10,150,150);   

  就可以了。其中,第二、三个参数分别表示是否链接到文件、是否在文档中保存图片
  信息(还是只保存链接信息)。

ASP.NET技术网站:http://www.singletowm.com

posted @ 2008-12-26 16:04 linxiao1314 阅读(1583) 评论(1) 编辑

C#中如何从MP3中取得歌曲信息方法详解

当我们用winamp软件听音乐时,播放清单就自动将这些信息读出来。大部分人都喜欢从网上下载音乐,但下载下来的MP3文件名都是文件上传系统自动取名的

  下面以C#为工具,把开发过程写出来。

  一首MP3的额外信息存放在文件的最后面,共占128个字节,其中包括以下的内容(我们定义一个结构说明):

  public struct Mp3Info
  {
   public string identify;//TAG,三个字节
   public string Title;//歌曲名,30个字节
   public string Artist;//歌手名,30个字节
   public string Album;//所属唱片,30个字节
   public string Year;//年,4个字符
   public string Comment;//注释,28个字节
   public char reserved1;//保留位,一个字节
   public char reserved2;//保留位,一个字节
   public char reserved3;//保留位,一个字节
  }

  所以,我们只要把MP3文件的最后128个字节分段读出来并保存到该结构里就可以了。函数定义如下:

  ///


  /// 获取MP3文件最后128个字节
  ///

  ///


  /// 返回字节数组
  private byte[] getLast128(string FileName)
  {
   FileStream fs = new FileStream(FileName,FileMode.Open,FileAccess.Read);
   Stream stream = fs;
   stream.Seek(-128,SeekOrigin.End);
   const int seekPos = 128;
   int rl = 0;
   byte[] Info = new byte[seekPos];
   rl = stream.Read(Info,0,seekPos);
   fs.Close();
   stream.Close();
   return Info;
  }  再对上面返回的字节数组分段取出,并保存到Mp3Info结构中返回。

  ///


  /// 获取MP3歌曲的相关信息
  ///

  ///


  /// 返回一个Mp3Info结构
  private Mp3Info getMp3Info(byte[] Info)
  {
   Mp3Info mp3Info = new Mp3Info();
   string str = null;
   int i;
   int position = 0;//循环的起始值
   int currentIndex = 0;//Info的当前索引值
   //获取TAG标识
   for(i = currentIndex;i
   {
    str = str+(char)Info[i];
    position++;
   }
   currentIndex = position;
   mp3Info.identify = str;
   //获取歌名
   str = null;
   byte[] bytTitle = new byte[30];//将歌名部分读到一个单独的数组中
   int j = 0;
   for(i = currentIndex;i
   {
    bytTitle[j] = Info[i];
    position++;
    j++;
   }
   currentIndex = position;
   mp3Info.Title = this.byteToString(bytTitle);
   //获取歌手名
   str = null;
   j = 0;
   byte[] bytArtist = new byte[30];//将歌手名部分读到一个单独的数组中
   for(i = currentIndex;i
   {
    bytArtist[j] = Info[i];
    position++;
    j++;
   }
   currentIndex = position;
   mp3Info.Artist = this.byteToString(bytArtist);
   //获取唱片名
   str = null;
   j = 0;
   byte[] bytAlbum = new byte[30];//将唱片名部分读到一个单独的数组中
   for(i = currentIndex;i
   {
    bytAlbum[j] = Info[i];
    position++;
    j++;
   }
   currentIndex = position;
   mp3Info.Album = this.byteToString(bytAlbum);
   //获取年
   str = null;
   j = 0;
   byte[] bytYear = new byte[4];//将年部分读到一个单独的数组中
   for(i = currentIndex;i
   {
    bytYear[j] = Info[i];
    position++;
    j++;
   }
   currentIndex = position;
   mp3Info.Year = this.byteToString(bytYear);
      //获取注释
   str = null;
   j = 0;
   byte[] bytComment = new byte[28];//将注释部分读到一个单独的数组中
   for(i = currentIndex;i
   {
    bytComment[j] = Info[i];
    position++;
    j++;
   }
   currentIndex = position;
   mp3Info.Comment = this.byteToString(bytComment);
   //以下获取保留位
   mp3Info.reserved1 = (char)Info[++position];
   mp3Info.reserved2 = (char)Info[++position];
   mp3Info.reserved3 = (char)Info[++position];
   return mp3Info;
  }
  上面程序用到下面的方法:
   ///
  /// 将字节数组转换成字符串
  ///

  ///
  /// 返回转换后的字符串
  private string byteToString(byte[] b)
  {
   Encoding enc = Encoding.GetEncoding("GB2312");
   string str = enc.GetString(b);
   str = str.Substring(0,str.IndexOf('\0') >= 0 ? str.IndexOf('\0') : str.Length);//去掉无用字符
   return str;
  }  改名怎么办呢?我们按(演唱者)歌名 的格式对歌曲进行改名,程序如下:

  ///


  /// 更改文件名
  ///

  ///


  ///
  private bool ReName(string filePath)
  {
   if(File.Exists(filePath))
   {
    Mp3Info mp3Info = new Mp3Info();
    mp3Info = this.getMp3Info(this.getLast128(filePath));//读出文件信息
    mp3Info.Artist = this.DeleteNotValue(mp3Info.Artist);
    mp3Info.Title = this.DeleteNotValue(mp3Info.Title);
    if(mp3Info.Artist.Trim().Length==0)
    {
     mp3Info.Artist="未命名";
    }
    if(mp3Info.Title.Trim().Length==0)
    {
     mp3Info.Title="未知名歌曲";
    }
    try
    {
     //更名
     File.Move(filePath,filePath.Substring(0,filePath.ToLower().LastIndexOf("\\")).Trim() + "\\" + "(" + mp3Info.Artist.Trim() + ")" +mp3Info.Title.Trim() + ".mp3");
     return true;
    }
    catch(Exception)
    {
     return false;
    }
   }
   else
   {
    return false;
   }
  }

 

ASP.NET技术网站:http://www.singletowm.com/

posted @ 2008-12-26 16:00 linxiao1314 阅读(526) 评论(1) 编辑