【Visual Studio风格开发系列 - 可视化界面设计】Create And Host Custom Designers With The .NET Framework 2.0 (英文原文)

[c# 自定义设计器] DesignSurface 和DesignSurfaceManager .NETFramework 2.0引入了两个类DesignSurface 和DesignSurfaceManager.给设计器提供宿主以及给设计器提供服务。DesignSurface是使用者所感知的设计器,它是UI使用者操纵改变设计时特征,DesignSurface 可能被当作一个单独的设计者使用或者和DesignSurfaceManager结合使用为设计器应用程序提供多个DesignSur... 阅读详情
Create And Host Custom Designers With The .NET Framework 2.0
Dinesh Chandnani
Version 1.0 of the Microsoft ® .NET Framework provided a very flexible design-time architecture, but offered virtually no implemented code to actually create and host designers. All of the hosting logic was implemented in Visual Studio ® .NET, requiring third parties to rewrite all of this complex logic. This has now changed; the .NET Framework 2.0 introduces a set of classes that can be used to host designers right out of the box.
Figure 1  Runtime 
To understand how .NET Framework designers work, it is important to know how designers are used. A designer is an object that only exists at design time and that connects to an object that normally exists at run time. The framework connects these two objects and provides a conduit for the design-time object to augment the behavior of the run-time object. At run time, a form and a button on that form are connected only through the parent/child relationship between the two controls (see Figure 1). There is no other object that controls the lifetime of these controls.
Figure 2   
The picture looks a little more complex at design time. Both the form and the button have designers associated with them. Both objects are also connected to a host container (see Figure 2), which owns these two objects. The host container also provides services—such as selection services to select one or more objects at design time, and UI services for displaying messages, invoking help, and interacting with the development environment—that the objects and designers may use.
The host container has many responsibilities. It creates components, binding them to designers and providing services to the components and designers it maintains. It loads designers from some sort of persistent state and saves them back to that state. The host container provides logic for undo, clipboard functions, and many other services that the designers rely upon to deliver a robust design-time environment.
Figure 3  Designer Hosting 
The host container can also persist the state of the designer. To do this, it would use a designer loader. The designer loader may, in turn, use serializers to serialize the components, as shown in Figure 3.
Extensibility with Services
The .NET Framework designer architecture is extensible. Critical to this extensibility, services provide the ability to enhance the functionality available to the various designers. A service is any object that can be queried by a type. Typically you would define some abstract class or interface that represents the service and then provide an implementation of that service. You can add services to and remove services from an object called a service container. IDesignerHost, the primary host interface for designers, is a service container. A service is a feature that may be shared between components written by different parties. Because of this, you must follow certain rules when using and creating services.
Services are not guaranteed. Whenever you ask for a service by calling the GetService method, you must always check to see whether GetService returned a valid object. Not all services are available on all platforms, and services that were once available may not be available in the future. Thus, your code should be written to degrade gracefully, usually by disabling the feature that required the service, in case a service does become unavailable.
If you add a service, remember to remove it when your designer is disposed. The designer host may destroy and recreate your designer from time to time. If you fail to remove a service, the old designer may be left in memory.

DesignSurface and DesignSurfaceManager
The .NET Framework 2.0 introduces two classes that are used for hosting designers and providing services to the designers: DesignSurface and DesignSurfaceManager. DesignSurface is what the user perceives as a designer; it is the UI the user manipulates to change design-time features. DesignSurface may be used as a standalone designer or it may be coupled with DesignSurfaceManager to provide a common implementation for an application that hosts multiple DesignSurfaces.
DesignSurface provides several design-time services automatically (see Figure 4). Most of these can be overridden in the service container. It is illegal to replace the non-replaceable services because their implementations all depend on each other. Note that all services added to the service container that implement IDisposable will be disposed when the design surface is disposed.
 
In addition to the default services, DesignSurface also provides IDictionaryService, available through a component's site. This service, which provides a generic dictionary of key/value pairs that can be used to store arbitrary data about a component, is unique to each component. It is not possible to replace these services because there is no way to replace services on a per-site basis.
DesignSurfaceManager is intended to be a container of designers. It provides common services that handle event routing between designers, property windows, and other global objects. Using DesignSurfaceManager is optional, but recommended if you intend to have several designer windows.
DesignSurfaceManager also provides several design-time services automatically (see Figure 5). Each of these can be overridden by replacing their value in the protected ServiceContainer property. As with DesignSurface, all DesignSurfaceManager services added to the service container that implement IDisposable will be disposed when the designer application is disposed.
IDesignerEventService is a particularly useful service. It allows an application to know when a designer becomes active. IDesignerEventService provides a collection of designers and is a single place where global objects, such as the Property window, can listen to selection change events.

The Hosting Form
To demonstrate how simple it is to host a designer, I wrote the following sample code to create a basic Windows ® Forms designer and display it:
In this code snippet, I have loaded the DesignSurface with a Form. Similarly, you can load the DesignSurface with any component that has a root designer available for it. For example, you could load a UserControl or a Component instead.
The sample provided in the code download for this article hosts four different root components: Form, UserControl, Component, and MyTopLevelComponent (a graph designer). When you run the sample, a shell UI will open. This interface includes a toolbox, a properties browser, a tab control for hosting designers, an output window, and a Solution Explorer, as shown in Figure 6. Selecting File | New | Form from the menu opens a new designer host with Windows Forms Designer. This essentially uses the code I've just shown you to load the designer. Rather than loading a Form, the sample app illustrates how to load a UserControl or Component.
Figure 6  Hosting Windows Forms Designer 
To create a root component, create a designer that implements IRootDesigner and then associate this designer with your component. The View property of the root component specifies the view that will be presented to the user.
One of the main services provided by DesignSurface is IDesignerHost. It is the master interface used to provide designers and controls access to types, services, and transactions. It can also be used to create and destroy components. To add a button to the Windows Forms designer I created earlier, all I need to do is get the IDesignerHost service from the DesignSurface and use it to create the button as shown in Figure 7.
Figure 7  Create a Button with IDesignerHost
IToolboxUser specifies that the designer supports adding controls from the toolbox. This means that if you do have a toolbox that implements ToolboxService, you can use the IToolboxUser interface to add controls to the root component. For instance:
When controls are added to the custom RootDesigner in the sample application by double-clicking the items in the toolbox, the view of the RootDesigner updates to display a pie chart as shown in Figure 8. Clicking on the GraphStyle link changes the view to a bar graph.
Figure 8  Custom RootDesigner Updates 

The Toolbox
MyRootDesigner implements the IToolboxUser interface. This has two methods: GetToolSupported and ToolPicked. You can use GetToolSupported to filter the items that can be added onto the designer. ToolPicked eventually calls into the CreateComponents method (which, as the name implies, is responsible for creating the components) of ToolboxItem.
Now that I have added the controls and components to the designer, let's take a closer look at how to implement a toolbox. First, your toolbox needs to implement IToolboxService—this service is added to the service container and can be accessed by anyone who needs to use it. The main functions of IToolboxService are shown in Figure 9.
To allow the items from the toolbox to be added onto the designer using the mouse or keyboard, the toolbox in the sample hooks onto the KeyDown and MouseDown events. For the Enter key or a mouse double-click, IToolboxUser.ToolPicked is called. The sample shows how to serialize the ToolboxItem into DataObject and DoDragDrop for when a mouse single-click event occurs. IToolboxService.SerializeToolboxItem will be called on mouse up and the item will be added to the designer.
When a new control or component is added to the designer, you can provide a custom name for the control by implementing INameCreationService. The sample application shows an example of this service in action using CreateName, ValidateName, and IsValidName.

Multiple DesignSurfaces
When managing multiple DesignSurfaces, it is a good idea to use a DesignSurfaceManager. This makes it easier to manage these DesignSurfaces. (Note that the services of DesignSurfaceManager are also available to DesignSurface.)
Calling DesignSurfaceManager.CreateDesignSurface calls into CreateDesignSurfaceCore. You can override this function to create a custom DesignSurface and add the services. The sample app creates a custom HostSurface by overriding this function in the HostSurfaceManager class:
You can then hook into the ActiveDesignSurfaceChanged event and update the output window in the HostSurfaceManager class, as shown here:
DesignerLoaders
So far I've created DesignSurfaces, hosted designers, added controls, implemented a toolbox, and added and accessed services like OutputWindow. The next step is to persist the designer. The designer loader is, as you'd expect, responsible for loading the designer from some persistent state. Simple and flexible, designer loaders have very few requirements. In fact, you can create an instance of the Windows Forms designer with a one-line designer loader that simply creates an instance of System.Windows.Forms.Form.
In addition to loading a form design, a designer loader is also responsible for saving the design. Because saving is an optional behavior, a designer loader listens to change events from the designer host and automatically saves state according to these events.
The .NET Framework 2.0 introduces two new classes for writing custom loaders: BasicDesignerLoader and CodeDomDesignerLoader. The sample app illustrates implementations of both loader types. Earlier I demonstrated loading the DesignSurface with a root component by passing in the type of the component. However, if you are using a loader, it should be used to load the design surface. The BeginLoad code snippet you'll need when using loaders should look something like this:
The DesignerLoader is responsible for loading the root component in the DesignSurface and creating any components. When creating a new form or any other root component, the loader simply loads it. In comparison, when loading from a code file or some other store, the loader is responsible for parsing the file or store and recreating the root component along with any other necessary components.
The .NET Framework defines an abstract base class called DesignerLoader that is used to load and save designers from persistent storage. The base class is abstract so that any type of persistence model can be used. This, however, adds to the complexity of implementing the class.
BasicDesignerLoader provides a complete and common implementation of a designer loader minus any information related to the persistence format. Like DesignerLoader, it is abstract, not dictating anything about the persistence format. BasicDesignerLoader does, however, handle the standard work of knowing when to save, knowing how to reload, and tracking change notifications from designers. Its features include support for multiple load dependencies, tracking of the modified bit to indicate a need to save changes, and deferred idle time reload support.
The services shown in Figure 10 are added to the designer host's service container by BasicDesignerLoader. As with other services, you can change replaceable services by editing their value in the protected LoaderHost property.The sample app implements a BasicDesignerLoader that persists the state in an XML format. To see how it works, select File | Type | BasicDesignerLoader. Then create a new Form by selecting File | New | Form. To see the XML code that is generated, select View | Code | XML. The XML code that is generated by the app will look something like this:
PerformFlush and PerformLoad are the two abstract functions of the BasicDesignerLoader that you need to implement for serializing and deserializing, respectively.
CodeDomDesignerLoader
Design-time serialization is handled by generating source code. One of the challenges of any code-generation scheme is the handling of multiple languages. The .NET Framework is designed to work with a variety of languages, so I also want the designers to emit to several languages. There are two ways to address this. The first is to require each language vendor to write the code-generation engine for their language. Unfortunately, no language vendor can anticipate the wide variety of code-generation requirements that third-party component vendors may need. The second approach is to require each component vendor to provide code generation for each language they want to support. This is equally bad, because the number of languages supported is not fixed.
To solve this problem, the .NET Framework defines an object model called the Code Document Object Model (CodeDOM). All source code can essentially be broken down into primitive elements and the CodeDOM is an object model for those elements. When code adheres to CodeDOM, the generated object model can later be sent to a code generator for a particular language to render the appropriate code.
The .NET Framework 2.0 introduces CodeDomDesignerLoader, which inherits from BasicDesignerLoader. The CodeDomDesignerLoader is a full loader that works by reading and writing CodeDOM. It is a turnkey designer loader, so all you need to do is provide the CodeDOM.
In the sample app you can select File | Type | CodeDomDesigner-Loader to see an example of the CodeDOM in action. Create a new form by selecting File | New | Form—this creates a DesignSurface and loads it using a CodeDomDesignerLoader. To check the code, select View | Code | C# to see the C# version of the form's code, or View | Code | VB to see the Visual Basic ® version.
To generate the code, the sample app uses CSharpCodeProvider and VBCodeProvider. It also uses the code providers to compile the code and run the executable (see Figure 11).
Figure 11 Generate, Compile, and Run
ITypeResolutionService, which is required when using the CodeDomDesignerLoader, is responsible for resolving a type. One scenario, for example, where this service is called to resolve types is when adding a control from the toolbox into the designer. The sample application resolves all types from the System.Windows.Forms assembly so that you can add controls from the Windows Forms tab of the toolbox.
Conclusion
As you've seen, the .NET Framework provides a powerful and flexible designer hosting infrastructure. Designers provide straightforward extensibility that help to address very specific needs or more advanced scenarios than were supported by previous versions of Visual Studio. Of course, designers can be hosted easily outside Visual Studio, as well. Be sure to download the sample application, so you can play around with the code and start implementing your own custom designers today.
------------------------------------------------------------------------
Dinesh Chandnani is a Software Design Engineer in Test for the .NET Client Team at Microsoft, working on designer hosting and other designer features. He started working for Microsoft in 2002 after completing his masters' degree in Computer Science at the University of Arizona.
(src:http://msdn.microsoft.com/zh-cn/magazine/cc163634(en-us).aspx)
C#用DesignSurface实现一个简单的窗体设计器 System.ComponentModel.Design.DesignSurface是为设计组件提供一个用户界面,通过它可以实现一个简单的窗体设计器。     在构建之前,我们需要引入System.Design.dll,否则会出现找不到DesignSurface的错误。 1 private void Form1_Load(object sender, Even 阅读详情

相关推荐

C# winform DesignSurface界面设计类。功能强大

C# .net framework 画面设计类,包括designsurfaceext_release.zip designsurfaceext_tinyformdesigner_sourcecode.zip pDesigner_designsurfaceext2_release.zip pFDesigner_sourcecode_and_demo.zip 篇文章描述一个增加了设计功能(TabOrder, UndoEngine,对齐线/网格对齐)的.net 2.0 中DesignSurface扩展类。这个类托管在DLL程序集中并准备在.net解决方案中使用。

php设计窗体界面,C#利用DesignSurface实现简单的窗体设计器的方法介绍(图文)

这篇文章主要介绍了C#利用DesignSurface如何实现简单窗体设计器的相关资料,文中通过图文及示例代码介绍的很详细,对大家具有一定的参考价值,需要的朋友们下面来一起学习学习吧。System.ComponentModel.Design.DesignSurface是为设计组件提供一个用户界面,通过它可以实现一个简单的窗体设计器。在构建之前,我们需要引入System.Design.dll,否则会出...

weixin_39956182的博客 553

DesignerHosting winform设计器

微软winform设计器,支持用户控件,winform,支持设计界面保存xml,加载xml创建设计界面

用c# 实现设计器 DesignSurface<转>

DesignSurface 实现设计器问题?http://topic.csdn.net/u/20090419/02/4c0fe387-c019-4159-ac60-71c04495e2b2.html DesignSurface 实现设计器问题?http://topic.csdn.net/u/20090419/02/4c0fe387-c019-4159-a...

weixin_34037515的博客 1103

用c# 实现设计器 DesignSurface

用c# 实现设计器 DesignSurface的实例

winform 表单设计器

基于DesignerHosting修改后的表单设计器,已经可以完成创建、打开、保存、编译、运行表单功能,并且可以编辑属性及事件,弥补了DesignerHosting的缺点。 目前尚有一问题没有解决,使用datagridview控件后,无法在设计模式下创建列。希望大家完善。

.NET2.0下如何开发可视化窗体设计器(含源代码)

 The Perfect HostCreate And Host Custom Designers With The .NET Framework 2.0Dinesh ChandnaniPrintThis article discusses:

荣植华的专栏 5242

C# 窗体(WInform)界面开发大全

C#界面设计典例,WInform界面开发系列的介绍,主要针对性介绍Winform开发过程中,经常用到的模块:数据字典模块、参数配置模块、权限管理模块的模块化应用,以及各模块的分合之道。

C#-WinForm-设计时编程【4】-响应鼠标事件

在设计器中,先看效果: 1、鼠标离开 2、鼠标进入(手形光标没截出来) 3、鼠标单击 代码及其分析: 引用命名空间: 1 using System.ComponentModel; 2 using System.ComponentModel.Design; 3 using System.Drawing; 4 using System.Windows...

weixin_30852451的博客 321

C#利用DesignSurface如何实现简单的窗体设计器

System.ComponentModel.Design.DesignSurface是为设计组件提供一个用户界面,通过它可以实现一个简单的窗体设计器。 在构建之前,我们需要引入System.Design.dll,否则会出现找不到DesignSurface的错误。 private void Form1_Load(object sender, EventArgs e) { //引用System.Deisgn.dll DesignSurface ds = new DesignSurface(); //开始加载窗体 ds.BeginLoad(typeof(Form)); Co

LinuxCNC 源码解析:从界面开发到硬件交互的实战指南

本文深入解析LinuxCNC源码架构,从用户界面开发到硬件交互的实战指南。涵盖GTK与Tkinter界面开发、HAL硬件抽象层、G代码解析器改造及运动控制核心等关键模块,提供定制化开发技巧与性能优化方案,助力开发者高效掌握数控系统开发。

weixin_27066963的博客 190

提升WinForm界面设计效率:C WinForm DesignSurface 界面设计类推荐

提升WinForm界面设计效率:C# WinForm DesignSurface 界面设计类推荐 【下载地址】CWinFormDesignSurface界面设计类 本仓库提供了一个功能强大的 C# WinForm DesignSurface 界面设计类资源文件。该资源文件适用于 .NET Framework 环境,旨在帮...

gitblog_09778的博客 766

视觉惯性SLAM系列——ORB-SLAM3的整体介绍及各个线程的功能(五)

跟踪线程(Tracking Thread)作用:负责处理每一帧图像,进行相机位姿的估计和定位。它首先执行与前一帧图像的特征匹配,然后通过仅运动(motion-only)BA(Bundle Adjustment)优化位姿。如果跟踪失败,它会尝试在所有地图中进行重定位。此外,跟踪线程还负责决定何时插入新的关键帧,以及何时将关键帧从局部地图中移除。详细介绍见局部建图线程(Local Mapping Thread)作用:管理局部地图,向活跃地图添加关键帧和点,移除多余的关键帧和点。

曾经也曾立志 1004

用C#实现类似Visual Studio的界面设计器

如果想用C#实现类似Visual Studio的界面设计器,以下几个网址必须要看1、编写组件自己的设计器http://www.microsoft.com/china/community/Column/80.mspx2、Designerhost .Net1.1下运行的Form设计器 http://support.microsoft.com/?id=813808 3、DesignerHosting .Net2.0下运行的Form设计器 http://msdn.microsoft.com/msdnmag/issu

人生倒计时 1万+

ANSYS WB 网格划分详解与技巧

本文详细介绍了网格操作中的关键设置与功能选项。主要内容包括:1)网格显示风格与物理偏好设置;2)单元阶次选择对精度的影响;3)单元尺寸控制方法;4)尺寸调整功能,重点讲解了自适应尺寸调整、增长率控制和捕获曲率等选项;5)网格质量评估标准;6)四种主要划分方法(四面体、六面体主导、扫掠、多区域)的特点与适用场景;7)三种尺寸调整方式(直接调整、边缘尺寸调整、影响范围调整)的具体应用。文章强调在实际建模中需要根据模型特点合理选择网格参数,平衡计算精度与效率。

2403_87939837的博客 1695

华为云HCS解决方案笔记HUAWEI CLOUD Stack【面试篇】

华为云解决方案介绍、华为云服务介绍,华为云网络平面规划等

weixin_48375618的博客 1万+

自定义工作流设计器

自定义工作流设计器 第一部分基础工作,建立代码结构框架1.创建项目WorkflowDesignerControl1.1:WorkflowView和DesignSurface,workflowView是微软提供的工作流设计API,所有的操作都要在上面进行;DesignSurface是WorkflowView的设计时支持WorkflowView需要从中获得一些资源。1.2:工具箱和属性窗口也要

姜兴的专栏 2904

Qemu开发ARM篇-5、buildroot制作根文件系统并挂载启动

在上一篇中,我们编译了kernel,并在qemu上进行了运行,但到最后,在挂载根文件系统时候,挂载失败,这是因为我们还没有根文件系统,在本章中,我们将制作根文件系统。rootfs制作方式有很多方式,如busyBoxbuildrootYocto等,在该篇章中,我们使用buildroot来制作根文件系统,主要考虑到busyBox制作完还需要手动首改一些启动配置比较繁琐,而Yocto如果电脑配置不是很好,编译时间过长,比较麻烦。

sinat_33909696的博客 2465

【Visual Studio风格开发系列 - 可视化界面设计】利用 .NET Framework 2.0 创建并宿主自定义的设计(全部图)

 Microsoft .NET Framework 1.0提供了一个非常通用的设计时框架,不过没有提供所有实现代码来完成一个设计器,Visual Studio? .NET实现了所有的复杂逻辑,要第三方去重新实现这个复杂的逻辑。.NET Framework 2.0引入了一组类能够用于设计器的实现。  理解.NET Framework怎么工作,非常重要的是要了解设计器是怎么使用的。设计器是负责管理设计界面上的组件的设计时期行为和表现的对象。框架关联设计时对象和运行时对象,为设计时组件提供了一个管道扩展运行时对象

wonsoft的专栏 9417

基于Simulink的自适应反步法(Adaptive Backstepping)控制​

本文针对非线性系统控制中未知参数和强非线性耦合的挑战,提出基于Simulink的自适应反步法解决方案。通过融合参数在线估计与反步递归设计,该方法显著提升了永磁同步电机(PMSM)速度控制的鲁棒性,使跟踪误差从20%降至3%,参数估计收敛时间小于0.5秒。文章详细阐述了从算法推导到Simulink实现的完整流程,包括系统架构设计、核心算法推导(以PMSM为例)、模块化建模方法、参数优化策略以及工程部署建议。提供的自适应控制器MATLAB代码和关键参数表可直接应用于实际工程,为电机驱动、机械臂等非线性系统控制提

xiaoheshang_123的博客 101

WinClaw安全实战 02|五层纵深防护体系全解析:从原理到实操,打造零风险AI智能体

2026年AI智能体爆发式普及,OpenClaw以27.3万GitHub星标成为现象级工具,但恶意Skill投毒、提示词注入、数据外泄等安全事故频发,国家互联网应急中心、工信部等多部门接连发布风险警示。威努特基于国家关键信息基础设施安全防护经验,打造WinClaw安全版AI智能体,其核心竞争力在于**五层纵深防护体系**。本文从安全痛点切入,通过真实事故案例揭示风险本质,全景解构五层防护的架构设计与技术原理,逐层拆解身份认证、安装审查、消息拦截、执行约束、监控审计的实现逻辑,搭配20+实操演示、对比表格

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 496

DesignSurface:演示用ISelectionService来获得当前组件,并用PropertyGrid来编辑该组件

<br />这是个非常简单的例子,演示了用ISelectionService来获得当前组件,并用PropertyGrid来编辑该组件。<br />也演示了锁定、复制、删除、移到上层等简单操作,以及在锁定的状态下禁止一些操作。<br /><br />虽然例子本身非常简单,但设计器本身是个非常大的议题,因此代码将分两部分贴出。<br />有兴趣的朋友们还可以参考:Windows Forms Programming: Design-Time Architecture<br /> using System;usin

ggw128的专栏 3453

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

具有强大的DesignSurface的大DesignTime经验(扩展)类

本人英文不好,所以还请大家包涵呀。 原文地址:http://www.codeproject.com/Articles/24385/Have-a-Great-DesignTime-Experience-with-a-Powerful                     http://www.codeproject.com/script/Articles/ArticleVersion.as

andycode的专栏 6110

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

上一篇: 【Visual Studio风格开发系列 - PropertyGrid控件】深度解析 TypeConverter & TypeConverterAttribute
下一篇: 【Visual Studio风格开发系列 - WinForm设计时异常】关于VS.NET中窗体设计器初始化控件引发的设计时异常
wonsoft
博客等级 码龄23年 228粉丝 98原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值