Custom Controls and User Controls

概述

<script type="text/javascript"></script> 在本月的专栏中,我将讨论下列主题:

  • 什么是用户控件?
  • 什么是自定义控件?
  • 用户控件和自定义控件进行基本的区别是什么?

我还将介绍几个涉及诸如状态管理和自定义控件的呈现之类的自定义控件的高级主题。

什么是用户控件?

<script type="text/javascript"></script> 用户控件是自定义的可重用的控件,并且使用 HTML 和 Web 服务器控件使用相同的技术。 它们提供了一个简单的方法,进行分区和在 ASP.NET Web 应用程序中重复使用公共用户界面。 它们使用同一个 Web 窗体编程的模型的 Web 窗体页工作。 有关 Web 窗体编程模型的详细信息,请访问下面的 Microsoft Developer Network (MSDN) 网站:

介绍 Web 窗体页
http://msdn2.microsoft.com/en-us/library/65tcbxz3(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/65tcbxz3(vs.71).aspx)

Web 窗体代码模型
http://msdn2.microsoft.com/en-us/library/015103yb(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/015103yb(vs.71).aspx)
如何创建用户控件

<script type="text/javascript"></script> 用于创建用户控件的语法与用于创建 Web 窗体页 (.aspx) 的语法类似。 唯一的区别是用户控件不包含在的 <html> <body>,和 <form> 元素,因为在 Web 窗体页承载用户控件。 要创建用户控件,请按下列步骤操作:

  1. 打开文本或 HTML 编辑器,并创建服务器端代码块公开所有属性、 方法和事件。
    <script language="C#" runat="server">
       public void button1_Click(object sender, EventArgs e)
       {
          label1.Text = "Hello World!!!";
       }
    </script>
    
  2. 创建用户控件在用户界面。
    <asp:Label id="label1" runat="server"/>
     <br><br>
    <asp:button id="button1" text="Hit" OnClick="button1_Click" runat="server" />
    
如何在 Web 窗体页中使用用户控件

<script type="text/javascript"></script>

  1. 在 Microsoft Visual Studio.NET 2002、 Microsoft Visual Studio.NET 2003、 Microsoft Visual Studio 2005 或任何文本编辑器中创建新的 Web 窗体页 (.aspx)。
  2. 声明 @ Register 指令。 是例如使用下面的代码。
    <%@ Register TagPrefix="UC" TagName="TestControl" Src="test.ascx" %>
    请注意 采用用户控件和 Web 窗体页位于同一位置。
  3. Web 窗体页中使用用户控件,请 @ Register 指令后使用以下代码。
    <html>
        <body>
              <form runat="server">
                   <UC:TestControl id="Test1" runat="server"/>
              </form>
        </body>  
    </html>
    
如何在代码隐藏文件在 Web 窗体页中的以编程方式创建用户控件的实例

<script type="text/javascript"></script> 上一示例实例化用户控件,Web 窗体页使用 @ Register 指令中的声明。 但是,您可以动态方式实例化用户控件,并将它添加到页。 下面是执行的步骤:

  1. 在 Visual Studio 中创建新的 Web 窗体页。
  2. 定位到代码隐藏文件生成为此 Web 窗体页。
  3. Page 类的 Page _ Load 事件中, 写入以下 code.
    // Load the control by calling LoadControl on the page class.
    Control c1 = LoadControl("test.ascx");
                
    // Add the loaded control in the page controls collection.	
    Page.Controls.Add(c1);
    
    Page.controls.Add(c1), 说明 您可以将用户控件添加动态在页生命周期的某些事件。

    有关详细信息,请访问下面的网站:
    以编程方式向 Web 窗体页添加控件
    http://msdn2.microsoft.com/en-us/library/kyt0fzt1(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/kyt0fzt1(vs.71).aspx)

    控件执行生命周期
    http://msdn2.microsoft.com/en-us/library/aa719775(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/aa719775(vs.71).aspx)

    动态的 Web 控件、 回发,和视图状态的 Scott Mitchell
    http://aspnet.4guysfromrolla.com/articles/092904-1.aspx (http://aspnet.4guysfromrolla.com/articles/092904-1.aspx)
如何处理用户控件

<script type="text/javascript"></script> 出现带有用户控件的页面请求时, 以下情况:

  • 页面分析程序分析 @ Register 指令中 Src 属性中指定的.ascx 文件,并生成从 System.Web.UI.UserControl 类派生的类。
  • 解析程序然后动态编译类为程序集。
  • 如果您使用 Visual Studio,然后在仅设计时,Visual Studio 创建一个代码隐藏文件在用户控件,并由本身设计预编译该文件是。
  • 最后,类为用户控件生成完成动态代码生成和编译的过程包括代码隐藏文件代码 (ascx.cs) 以及.ascx 文件中编写的代码。

什么是自定义控件?

<script type="text/javascript"></script> 自定义控件是在服务器上执行,提供在对象模型的已编译的代码组件和将标记文本,如 HTML 或 XML,呈现为普通的 Web 窗体或用户控件不会。

如何选择自定义控件的基类

<script type="text/javascript"></script> 若要写入自定义控件则应直接或间接派生新类从 System.Web.UI.Control 类,或从 System.Web.UI.WebControls.WebControl 类:

  • 如果您希望在控件呈现派生自非可视元素则应从 System.Web.UI.Control 中进行派生。 例如 <meta> <head> 是派生自非可视呈现的示例。
  • 如果您希望以呈现生成一个 Visual 接口在客户端计算机上的 HTML 控件则应从 System.Web.UI.WebControls.WebControl 中进行派生。

如果您想要更改如按钮或标签,之类的现有控件的功能您可以直接派生新类与这些现有的类,并可以更改其默认行为。

简要, Control 类提供了基本的功能,通过它您可以放置它 Page 类的控件树中。 WebControl 类将功能添加到基本的 控件 类,用于在客户端计算机上显示 Visual 的内容。 是例如可以使用 WebControl 类控件的外观和样式属性 (如字体、 颜色和高度。

如何创建和使用从 System.Web.UI.Control 扩展使用 Visual Studio 的简单自定义控件

<script type="text/javascript"></script>

  1. 启动 Visual Studio。
  2. 创建一个类库项目然后赋予它一个的名称是例如 CustomServerControlsLib。
  3. 将受源代码文件添加到项目,是例如 SimpleServerControl.cs。
  4. System.Web 命名空间的引用纳入参考部分中。
  5. 检查是否将以下命名空间包括 SimpleServerControl.cs 文件
    System
    System.Collections
    System.ComponentModel
    System.Data
    System.Web
    System.Web.SessionState
    System.Web.UI
    System.Web.UI.WebControls
    
    中。
  6. 继承 控件 的基类 SimpleServerControls 类。
    public class SimpleServerControl : Control
  7. 重写 Render 方法将输出写入输出流。
    protected override void Render(HtmlTextWriter writer) 
    {
    	 writer.Write("Hello World from custom control");
    }
    
    请注意 HtmlTextWriter 类具有 HTML 写入文本 Stream 的功能。 Write 方法 HtmlTextWriter 类的输出指定的文本到 HTTP 响应流, Response.Write 方法相同。
  8. 编译类库项目。 它将生成 DLL 输出。
  9. 打开现有或创建新的 ASP.NET Web 应用程序项目。
  10. 添加一个 Web 窗体页,可以在其中使用自定义的控件。
  11. ASP.NET 项目的参考部分中添加对该类库的引用。
  12. 注册 Web 窗体页上自定义的控件。
    <%@ Register TagPrefix="CC " Namespace=" CustomServerControlsLib " Assembly="CustomServerControlsLib " %>
  13. 要实例化,或使用 Web 窗体页上自定义的控件,将代码的下行添加在 <form> 标记中。
    <form id="Form1" method="post" runat="server">
        <CC:SimpleServerControl id="ctlSimpleControl" runat="server">
        </CC:SimpleServerControl >
    </form>
    
    注意 在此代码, SimpleServerControl 是在该类库控件类名)。
  14. 运行在 Web 窗体页,并您将会看到自定义控件输出。

如果要不 Visual Studio 使用需要执行以下步骤:

  1. 打开任何文本编辑器。
  2. 创建一个名为 SimpleServerControl.cs 的文件并编写该的代码,以指定在步骤 1 至 14。
  3. 在 PATH 变量中添加下面的路径:
    c:/windows (Winnt)/Microsoft.Net/Framework/v1.1.4322
  4. 打开一个命令提示符窗口,然后转到存在 SimpleServerControl.cs 所在的位置。
  5. 运行以下命令:
    csc /t:library / out: CustomServerControlsLib。 SimpleServerControl.dll /r:System.dll /r:System.Web.dll SimpleServerControl.cs
    有关 C# 编译器 (csc.exe),请访问下面的 MSDN 网站:
    http://msdn2.microsoft.com/en-us/library/1700bbwd(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/1700bbwd(vs.71).aspx)
  6. 若要运行 Web 窗体页上自定义的控件,执行以下操作:
    1. 创建一个在 Wwwroot 文件夹下的目录。
    2. 启动 Microsoft Internet Information Services (IIS) 管理器,并在新目录标记为虚拟根目录。
    3. 创建一个新的目录下的 Bin 文件夹。
    4. 将自定义控件 DLL 复制到文件夹中。
    5. 将以前的步骤,在新的目录中创建示例 Web 窗体页。
    6. 运行示例页通过 IIS 管理器。

既然您所生成简单的自定义控件,让我们来看一下如何公开属性,并应用该自定义控件上的设计时属性。

如何公开自定义控件上的属性

<script type="text/javascript"></script> 我将基于上一个示例,并引入一个或多个属性,可以使用 Web 窗体页上自定义的控件时配置。

下面的示例显示如何定义一个属性,将显示控件中的消息的时间,控件的属性中指定特定数量:

  1. 在文本编辑器中打开 SimpleServerControl.cs。
  2. SimpleServerControl 类中添加属性。
    public class SimpleServerControl : Control
    {
       private int noOfTimes;
       public int NoOfTimes
       {
           get { return this.noOfTimes; }
           set { this.noOfTimes = value; }
       } 
       protected override void Render (HtmlTextWriter writer)
       {
         for (int i=0; i< NoOfTimes; i++)
         {
           write.Write("Hello World.."+"<BR>");
         } 
       }
    }
    
  3. 编译自定义控件。
  4. 若要使用 Web 窗体页上的自定义控件,请向控件声明中添加新的属性。
    <CC:SimpleServerControl id="ctlSimpleControl" NoOfTimes="5" runat="server"></CC:SimpleServerControl>
  5. 运行页将显示自定义控件中的"Hello World"条消息按控件的属性中指定的次数。
如何应用自定义控件上的设计时属性

<script type="text/javascript"></script>

为什么需要设计时属性

<script type="text/javascript"></script> 您在前面的示例生成自定义控件正常工作。 但是,如果想要在 Visual Studio 中使用该控件,您可能需要在突出自动显示在属性窗口中在设计时选中自定义控件时, NoOfTimes 属性。

要实现这一点,必须可以来执行此在称为属性的 Visual Studio 中使用一项功能的 Visual Studio 提供元数据信息。 属性可以定义类、 方法、 属性或字段。 Visual Studio 加载自定义控件的类时, 它将检查在类、 方法、 属性或字段级定义的任何属性,并相应地更改设计时时自定义控件的行为。

若要了解有关属性的详细信息,请访问下面的 MSDN 网站:

http://msdn2.microsoft.com/en-us/library/Aa288059(VS.71).aspx (http://msdn2.microsoft.com/en-us/library/Aa288059(VS.71).aspx)

让我们生成示例的使用常用属性:

  1. 在文本编辑器中打开 SimpleServerControl.cs。
  2. 介绍一些基本属性类级别是例如 DefaultProperty ToolboxData TagPrefixAttrbute 。 我们将我们的示例基于这三个属性
            [
    	// Specify the default property for the control.		
    	DefaultProperty("DefaultProperty"),
    	
    	// Specify the tag that is written to the aspx page when the
            // control is dragged from the Toolbox to the Design view. 
    	// However this tag is optional since the designer automatically 
    	// generates the default tag if it is not specified.		
    	ToolboxData("<{0}:ControlWithAttributes runat=/"server/">" +
    		"</{0}:ControlWithAttributes>")
    	]
    	public class ControlWithAttributes : Control
    	{
    		private string _defaultProperty;
    		public string DefaultProperty
    		{
    			get { return "This is a default property value"; }
    			set { this._defaultProperty = value; }
    		}
    
    		protected override void Render(HtmlTextWriter writer)
    		{
    			writer.Write("Default Property --> <B>" + 
    			DefaultProperty + "</B>");
    		}
             }
    
  3. 没有名为 TagPrefixAttrbute 的更多标记。 它是控件从工具箱拖动到设计器时,提供与标记前缀的程序集级属性。 否则,设计器在默认情况下生成一个前缀,如"cc 1"。 TagPrefixAttrbute 不直接应用于控件类。 若应用 TagPrefixAttrbute ,请打开 AssemblyInfo.cs 中,包括下行的代码,然后重新生成项目
    [assembly:TagPrefix("ServerControlsLib ", "MyControl")]
    注释 ,如果要生成使用该命令行来源需要创建 AssemblyInfo.cs 文件、 放置该文件包含所有源文件,在目录中的并运行以下命令以生成该控件:。
    > csc /t:library / out: ServerControlsLib.dll /r:System.dll /: System.Web.dll *.cs

用户控件和自定义控件进行基本的区别是什么?

<script type="text/javascript"></script> 现在,有用户控件和自定义控件以及如何创建一个基本了解,让我们看这两者的区别在快速看。

收起该表格 展开该表格
因素 用户控件 自定义控件
部署用于单应用程序方案

应用程序的源代码与的一起部署源形式 (.ascx)

如果在同一控件需要在多个应用程序中使用,介绍冗余和维护问题
设计可由多个应用程序

部署应用程序的 Bin 目录中或全局程序集缓存中

分发轻松且不与冗余和维护相关的问题
创建创建与 Web 窗体页的创建,适合快速应用程序开发 (RAD) 方式类似编写涉及大量代码,因为没有任何设计器支持
内容更多好的选择当您需要固定的布局中的静态内容时,是例如使时页眉和页脚适合应用程序需要动态的更多要显示的内容 ; 可重复使用的应用程序,是例如的数据与动态行的表格控件绑定
设计编写不需要多应用程序设计因为它们都是在设计时编写的主要包含静态数据从零开始编写需要好地理解控件的生命周期和是通常执行负责在用户控件中的顺序在其中事件执行

高级的主题

<script type="text/javascript"></script> 下一步,让我们看一看几个可以开发自定义控件时使用的高级功能。

状态管理

<script type="text/javascript"></script> Web 应用程序构建是无状态的 HTTP 上。 其子控件和页在每次请求创建,并通过请求后被释放。 若要保持在传统 ASP 编程中的状态,您可以使用会话和应用程序的对象。 但是,需要执行大量代码。 要避免这一点,ASP.NET 提供了称为多个请求之间维护状态的视图状态一个机制。 若要进一步了解状态管理和视图,请访问下面的 MSDN 网站:

Web 窗体状态管理介绍
http://msdn2.microsoft.com/en-us/library/75x4ha6s(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/75x4ha6s(vs.71).aspx)

ASP.NET 视图状态
http://msdn.microsoft.com/msdnmag/issues/03/02/cuttingedge/default.aspx (http://msdn.microsoft.com/msdnmag/issues/03/02/cuttingedge/default.aspx)

保存 Web 窗体页使用视图状态的值
http://msdn2.microsoft.com/en-us/library/4yfdwycw(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/4yfdwycw(vs.71).aspx)
使用自定义的控件中的视图状态的示例

<script type="text/javascript"></script> ViewStateExample.cs

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Text;

namespace ServerControlLib
{
	/// <summary>
	/// When a page framework reloads this control after postback, it   
        /// will restore the values which are in view state.
	/// This control can easily perform state management without 
        /// implementing our own logic for maintaining the state.
	/// </summary>
	public class ViewStateExample : WebControl
	{
		// Text to be displayed in Text box control.
		private string _text;
		
		/*
		 * This property needs to be populated before every 
                 * postback in order to 
		 * retain its value.
		*/ 
		public string Text
		{
			get { return (_text == null) ? "_text property is empty"  : _text; }
			set { _text = value; }
		}

		/*
		 * This property needs to be filled once and should be 
                 * available on the successive postbacks.
		*/ 
		public string TextInViewState
		{
			get
			{
				object o = ViewState["TextInViewState"];
				return (o == null) ? "View state is empty" : (string)o;
			}
			set { ViewState["TextInViewState"] = value; } 
		}

		/*
		 * Over-ridden method on WebControl base class which                   
                 * displays both of the property values 
		 * i.e. one stored in view state and other which is not 
                 * saved in view state.
		*/
		protected override void RenderContents(HtmlTextWriter writer)
		{
			writer.Write("Text Without View State = ");
			writer.Write(Text);
			writer.Write("<hr><br>");
			writer.Write("Text In View State = ");
			writer.Write(TextInViewState);
		}
	}
}
使用上一个 Web 窗体页上的控件的示例

<script type="text/javascript"></script> ViewStateExampleDemo.aspx

<%@ Page Language="C#" %>
<%@ Register TagPrefix="CC" Namespace="ServerControlLib" Assembly = "ServerControlLib" %>

<html>
  <head>
    <script runat="server">
      void button1_Click(object sender, EventArgs e)
      {
          Control1.Text = textbox1.Text;
          Control1.TextInViewState = textbox2.Text;
      }
    </script>
  </head>
  <body>
    <form runat="server" ID="Form1">
      <br>
      Property Value Without View State: <asp:TextBox id="textbox1" 
        runat="server" />
      <br>
      Property Value with View State: <asp:TextBox id="textbox2" 
        runat="server" />

      <asp:Button text="Cause Postback" onClick="button1_Click" 
        id="button1" Runat="server" />

      Output from the ViewStateExample Control :
      <CC:ViewStateExample id="Control1" runat="server"/>
    </form>
  </body>
</html>
呈现

<script type="text/javascript"></script> 本节中, 我将简要介绍从 Control 类或 WebControl 类派生自定义控件时应重写的方法。

呈现 System.Web.UI.Control 类的方法

<script type="text/javascript"></script> 有关呈现方法在 System.Web.UI.Control 类的信息,请访问下面的 MSDN 网站:

Control.Render 方法
http://msdn2.microsoft.com/en-us/library/system.web.ui.control.render(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/system.web.ui.control.render(vs.71).aspx)

Control.RenderControl 方法
http://msdn2.microsoft.com/en-us/library/system.web.ui.control.rendercontrol(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/system.web.ui.control.rendercontrol(vs.71).aspx)

Control.RenderChildren 方法
http://msdn2.microsoft.com/en-us/library/system.web.ui.control.renderchildren(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/system.web.ui.control.renderchildren(vs.71).aspx)
如何在页面上呈现控件

<script type="text/javascript"></script> 每个页都有代表该页面的所有子控件的集合的控件树。 若要显示管理树, HtmlTextWriter 类的创建对象,包含要在客户端计算机上呈现 HTML。 该对象传递给 RenderControl 方法中。 反过来, RenderControl 方法将调用此 Render 方法。 然后, Render 方法会使一个递归循环,直到到达集合的末尾每个子控件上调用 RenderChildren 方法。 此过程最下面的示例代码进行解释。

public void RenderControl(HtmlTextWriter writer) 
{
    // Render method on that control will only be called if its visible property is true.
    if (Visible)
    {
        Render(writer);
    }
}

protected virtual void Render(HtmlTextWriter writer) 
{
    RenderChildren(writer);
}
protected virtual void RenderChildren(HtmlTextWriter writer) 
{
    foreach (Control c in Controls) 
    {
        c.RenderControl(writer);
    }
} 

如果 (Visible) {Render(writer);}} 保护虚拟 void 呈现 (HtmlTextWriter 编写器) {RenderChildren(writer);} 保护虚拟 void RenderChildren (HtmlTextWriter 编写) {foreach (在控件中控制 c) {c.RenderControl(writer);}}

呈现 System.Web.UI.WebControl 类的方法

<script type="text/javascript"></script> 有关呈现方法 System.Web.UI.WebControl 类的信息,请访问下面的 MSDN 网站:

WebControl.RenderBeginTag 方法
http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.renderbegintag(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.renderbegintag(vs.71).aspx)

WebControl.RenderContents 方法
http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.rendercontents(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.rendercontents(vs.71).aspx)

WebControl.RenderEndTag 方法
http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.renderendtag(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.renderendtag(vs.71).aspx)
WebControl 类的呈现方式会发生

<script type="text/javascript"></script> 下面的代码示例演示自定义控件在 Render 方法。

protected override void Render(HtmlTextWriter writer)
{
    RenderBeginTag(writer);
    RenderContents(writer);
    RenderEndTag(writer);
}

不必重写为 WebControl Render 方法。 如果要呈现在 WebControl 类中的内容,您需要重写 RenderContents 方法。 但是,如果您仍然想重写 Render 方法,您必须覆盖 RenderBeginTag 方法以及上一代码示例所示的特定顺序 RenderEndTag 方法。

结论

<script type="text/javascript"></script> 这就为现在用户控件和 ASP.NET 1.0 和 ASP.NET 1.1 中的自定义控件。 我希望此列可帮助您了解基本的区别它们与不同的方法可用来开发它们之间。

感谢您的时间。 我们期望在不久的将来写入详细信息,如状态管理、 控件样式、 复合的控件和自定义的控件的设计时支持之类的自定义控件的高级主题。

有关控件的更多信息请访问下面的 MSDN 网站:

ASP.NET 服务器控件开发基础知识
http://msdn2.microsoft.com/en-us/library/aa310918(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/aa310918(vs.71).aspx)

一个广泛的 Examination of 用户控件
http://msdn2.microsoft.com/en-us/library/ms972975.aspx (http://msdn2.microsoft.com/en-us/library/ms972975.aspx)

生成模板化自定义 ASP.NET 服务器控件
http://msdn2.microsoft.com/en-us/library/Aa478964.aspx (http://msdn2.microsoft.com/en-us/library/Aa478964.aspx)

在 ASP.NET 服务器控件中的事件
http://msdn2.microsoft.com/en-us/library/aa720049(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/aa720049(vs.71).aspx)

与用户控件的复合控件
http://msdn2.microsoft.com/en-us/library/aa719735(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/aa719735(vs.71).aspx)

开发 ASP.NET 服务器控件
http://msdn2.microsoft.com/en-us/library/aa719973(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/aa719973(vs.71).aspx)

开发自定义控件: 主要概念
http://msdn2.microsoft.com/en-us/library/aa720226(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/aa720226(vs.71).aspx)

向 ASP.NET 控件添加设计时支持
http://msdn2.microsoft.com/en-us/library/Aa478960.aspx (http://msdn2.microsoft.com/en-us/library/Aa478960.aspx)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值