Create a designable component for Microsoft Visual Studio .NET designer

xiaoxiao2021-03-06  72

Create a designed component Shawn Burke for Microsoft Visual Studio .NET Designer

Microsoft Corporation

July 2000

Summary: Microsoft .NET components are built with management code and build on a universal language run. This article discusses how it provides developers with a new hybrid development environment, as as easy as Microsoft Visual Basic, while providing powerful low-level programming capabilities, more correlated with ATL or MFC.

table of Contents

Introduction Components What is custom metadata property browser interface introduced from the outside: The code persistent component designer access designer service and infrastructure conclusion

Introduction

Microsoft's upcoming Visual Studio .NET will enable program developers to get an integrated development environment, not only for developing traditional C / C applications, but also provide a rich tool for exciting Microsoft .NET components. These are written in management code, and components built at universal language run provide a new hybrid development environment to developers, as as easy as Microsoft Visual Basic, while providing powerful low-level programming capabilities, more than ATL or MFC. Related. With the arrival of production efficiency, it can work well with traditional COM components. Developers can spend more time on building large components without having to worry about memory leakage, security and header files.

In addition to the development of Microsoft .NET Framework components, Visual Studio .NET (VS .NET) also has many tools that allow components to use the advantages of the designer architecture in VS .NET to design the advantages and performance and vs .NET Products that come with a component. When developing management components, all features obtained in the VS.NET designer use the component itself .NET Framework, thus obtaining a tight integration between the design and runtime components.

What is the component?

Obviously, Microsoft .NET Framework components are easy to write. The only requirement for working with the Visual Studio .NET designer is that they implement System.comPonentModel.icomponent, which usually indicates the default application inherited to IComponent. IComponent enables components to track information when design (such as its container component or name) or access to the designer.

Let us write a simple .NET component, its form as follows:

Using system;

Using system.componentmodel;

Public class booltracker: Component {

Private bool stat;

Private eventHandler Handler;

Private static object EventValueChanged = New Object ();

Public booltracker () {

}

Public bool value {

Get {

Return State;

}

SET {

IF (this.State! = value) {

THIS.STATE = VALUE;

OnValueChanged (New EventArgs ());

}

}

}

Public void addonvaluechanged (eventhandler h) {

delegate.comBBINE (Handler, H);

}

Protected Virtual Void OnValueChanged (Eventargs E) {

IF (Handler! = null) {handler (this, e);

}

}

Public Void RemoveonValueChanged (EventHandler H) {

Handler = (EventHandler) Delegate.Remove (Handler, H);

}

}

Obviously, this component does not complete what function, but it will place it into the Visual Studio .NET WIN Form Designer or Component Designer, you can see it from the property browser, there is also a "value" Attribute, use the drop-down arrow to set the value to true or false, when the value is switched between TRUE and FALSE, the event ONVALUECHANGED can be triggered.

For designer, the component is just half of us to explain, the most important part is attribute, which makes metadata, metadata is information about classes, attributes, events, etc. Let us take the value attribute as an example. Only as attributes, there is already related metadata, such as types (Boolean, behavior (read / write), or name ("Value"). Use "Reflection" to retrieve the basic metadata, that is, the general language runtime allows the user to check the type of object, the basic type, attributes, methods, constructors, fields, and access levels at runtime. All of this information is considered to be metadata.

Custom metadata

Custom metadata includes any information segment (field, attribute, or method) that can be added to the class or class member, in fact, the type itself is identified by a particular customer. For the Visual Studio .NET designer, custom metadata constitutes all expandable foundations. All metadata properties of the VS .NET designer understand are based on a class called System.comPonentModel.Membuttribute. It provides a basic class, so the properties of the developer care can be quickly identified by their type.

This concept can be easier to understand through a typical example. For example, we don't want the value attribute to display in the property browser. We can add a metadata properties System.comPonentModel.BrowsableAttribute to control whether an attribute can be browsed.

[Browsable (false)]

Public bool value {

Get {

Return State;

}

SET {

IF (this.State! = value) {

THIS.STATE = VALUE;

OnValueChanged (New EventArgs ());

}

}

}

When specifying properties, "BrowsableAttribute" can be abbreviated as "browsable". Add the word "attribute" to us by the C # compiler. The only restriction is if the property value is specified, it must match the properties type of the constructor, and the value must be constant. In this example, BrowsableAttribute has a single Boolean parameter "browsable" constructor, the compiler binds the metadata property to the constructor and creates an instance of a attribute class. If the attribute class browser gets this object, it will enumerate the properties of the object and ignore the "Browsable" property because it is label with this property. So this object does not have attributes. BrowsableAttribute can also be applied to events.

Microsoft .NET Framework has a wealth of property set to control the designer how to use components. Here is some of these useful properties, so that you can understand its meaning in later reading:

Attribute Name Description BrowSableAttribute control property or event is displayed in the properties browser. BindableAttribute determines if the property is suitable for binding the data binder. CategoryAttribute Specifies the category that attributes should be packet in the property browser ("APPEARANCE", "Layout", "Behavior", "MISC", etc.). DEFAULTEVENTATTRIBUTE / DEFAULTPROPERTYATTRIBUTE Specifies the default event or attribute of the object. HelPattribute specifies the help files and themes for attributes or events. LicenseProViderattribute points to LicenseProvider that provides license information for components. MergablePropertyAttribute allows or blocks the included properties when multiple components are browsed and selected in the Properties Browser. PersistableAttribute determines whether the attribute value should be consistent with the code when generating a code in a visual designer such as Win Forms Designer or Component Designer. The PersistContentSattribute determines whether the code generates whether the non-numeric property of the object should be returned to the object and whether the hold code is consistent with the attribute value. The ICollection property type is a typical example of this application. ShowIntoolBoxAttribute determines if this component is allowed to use this component in the toolbox. ToolboxItemAttriubte Specifies the ToolboxItem type that should be used when you create a class in the toolbard. Property browser interface

You may notice that the property browser has been mentioned many times in the previous part. This is because a large number of activities involved in the designer participation occurred in the property browser. Designer organizes and displays components, but mainly by the object browser decision allows you to modify them. In previous versions, the browser displays the comes with the COM objects that have the defined subsets of the data to be displayed: numbers, strings, fonts, colors, images, boolean values, and enumeration values. In addition, other properties operations are completed by the property page or dialog box. However, the VS .NET Designer allows the component designer to define how the property browser handles any property type of the object, and how the user edits these types.

.NET Framework uses these editors to edit many built-in types, for example, system.drawing.color, system.drawing.font or Win Forms control Dock and Anchor properties.

Figure 1. Property editor

This property browser extensible architecture provides four basic features:

Value converter property enumerate drop-down / pop-up editor

System.comPonentModel.TypeConverter processes the first three feature types, from System.WinForms.Design.uityPeEditor's editor to process the last one.

All properties encountered in the .NET Framework have built-in TypeConverters. Let's take a look at the TypeConverter class and its function, then discuss a specific example. The following code is the reduction version of TypeConverter. It has many features that have been listed, but for simplicity, ignore them, only those core methods are retained. All the methods listed here are virtual, so they can ignore them when needed. However, TypeConverter is implemented as a base class rather than an interface, most important functions have been built-in, and users can ignore part of the application.

Public class typeconverter {

//

// Value Conversion Method.

//

/ / Determine TypeConverter to convert from a specific type to the target type.

Public Virtual Bool CanconvertFrom

ITYPEDEScriptorContext Context,

TYPE SOURCEPE);

/ / Determine if TypeConvert can be converted from the target type to a specific type.

Public Virtual Bool CanconvertTo (ItypeDescriptorContext Context,

Type destinationType);

/ / The value in the TypeConverter conversion target type value is converted.

Public Virtual Object ConvertFrom

ITYPEDEScriptorContext Context,

Object Value,

Object [] arguments);

// Translate the value from the TypeConvert of Target Type.

Public Virtual Object ConvertTo

ITYPEDEScriptorContext Context,

Object Value,

Type destinationType,

Object [] arguments);

//

// Instance creation method.

//

// Create an object of the target type.

Public Virtual Object CreateInstance

ITYPEDEScriptorContext Context,

Persistinfo Persistinfo;

// Create a target type object and place it from a given IDictionary.

Public Virtual Object CreateInstance

ITYPEDEScriptorContext Context,

IDictionary property accuracy;

// Specify whether TypeConverter knows how to create an object instance of the target type.

Public Virtual Bool GetcreateInstanceSupported

ITYPEDEScriptorContext context);

// Get the value of Persistinfo,

// PersistInfo is an object that describes a given value reserved state.

Public Virtual Persistinfo getPersistinfo

ITYPEDEScriptorContext Context,

Object value);

//

// Sub property method.

//

// Retrieve any subtribraclea to display in this type in the property browser.

Public Virtual PropertyDescriptorCollection GetProperties

ITYPEDEScriptorContext Context,

Object Value,

MEMBERATITRIBUTE [] Attributes);

/ / Specify whether this type should be displayed with ' ' in the property browser and display subastributes.

Public Virtual Bool GetPropertiesupported

ITYPEDEScriptorContext context);

//

// Pre-defined / standard value method.

//

// Retrieve a predefined "standard" value collection for this type.

Public Virtual StandardValeScollection GetStandValues

ITYPEDEScriptorContext context);

// Specify the value collection of getStandardValues ​​is a full list of possible or valid values.

Public Virtual Bool GetStandardValeSexClusive (

ITYPEDEScriptorContext context);

/ / Determine if the TypeConverter can return a list of standard values.

Public Virtual Bool GetStandardValuessupported

ITYPEDEScriptorContext context);

// Check the value if it is a valid value for this type.

Public Virtual Bool IsValid

ITYPEDEScriptorContext Context, Object Value; //

// Practical method.

//

/ / The properties collection is arranged in the order specified by the name array.

Protected PropertyDescriptorCollection Sortproperties

PropertyDescriptorCollection Props,

String [] names);

}

Public Interface ItypedScriptorContext: iServiceObjectProvider {

// Returns an icontainer that is in line with this context.

IconTainer Container {Get;}

// Returns the instance being checked.

// If value is passed to TypeConvert,

// iTypedScriptorContext :: Instance will return an object that provides a value.

Object installation {get;}

// Call before the object returned from the instance. If false returns, you cannot make changes and should be aborted.

Bool oncomponentchanging ();

// After the change, or the object returned from the instance is changed.

void oncomponentchanged ();

}

As you can see, TypeConverter contains a lot of content. It also includes a brief description of ITYPEDEScriptorContext. Because it appears in a parameter in most TypeConverter methods. ITYPEDEScriptorContext allows access to service and component objects, which provide all values ​​that are passed to the TypeConverter.

However, carefully study TypeConvert will find that it is not as complex. Its function can be divided into four groups:

Value Conversion: Clients such as attribute browsers need to easily convert a string representation to another. TypeConverter provides a standard method for this, and a method of determining whether a given conversion is feasible. Because the conversion between strings is most common, TypeConvert provides more advantageous ways for ConvertfromString and ConvertTString (not shown). The creation and persistence of an instance: TypeConverter is responsible for creating a given type of instance. TypeConverter enables the creator of the type to control this process instead of forcing the client to check the constructor or know the default. In this way, TypeConverter also plays the role of the code hold components in the designer. It can create and use the PersistInfo object that describes which part of the object status is related to the persistence correlation (often taken from code), and how to keep them. Sub Properties: TypeConverter allows objects to be controlled on subtribracots displayed in the property browser. System.drawing.font is an example, the attribute displayed when the instance is expanded does not completely match the actual properties of the Font object itself. They are changed and re-sorted for clarity and availability. Standard value: Many types (such as enumeration) have defined values. Other types can have a predefined complete set, but they can also accept other values. TypeConverter allows clients to check these lists and check if the values ​​in the list are acceptable.

TypeConverter can be associated with attributes by one of two ways. By having TypeConvertRibute in class declaration, the type can specify their own TypeConverter. Usually these classes make their converters a nested class, so information in type and design is a whole. In other words, the attribute can also specify TypeConverter to ignore the TypeConvert associated with the attribute type by the attribute declaration itself. Of course, the TypeConverter that is specified there must be aware of a specific type. TypeConverter cannot be specified any, but this method helps to understand the display method of gived a given property, add or delete subastributes or add support for different string conversion. You can export a type from the default TypeConveter and specify the type of TypeConverter to give this knowledge as a TypeConverter for a given property. The other half of the attribute browser interface involves the property editor. The structure of the attribute editor is far from the TypeConverter structure. In order to remain open to the editor that does not rely on Win Forms or not, there is no basic editor type. Since the editor typically uses the user interface (UI) driver, all standard editors in .NET Framework are from System.drawing.Design.uitypeEditor. Public class uitypeEditor {

// Call when editing the value.

Public Virtual Object EditValue

IServiceObjectProvider Provider, iServiceObjectProvider Province, IservePriptorContext Context

Object value);

/ / Specify whether this editor can display the value.

Public Virtual Bool GetPainTValeSupported

ITYPEDEScriptorContext context);

// If there is, returns the user interface style of this editor.

Public Virtual UITYPEEDITOREDITSTYLEEDITSTYLE

ITYPEDEScriptorContext context);

// When the client needs to call when the value is displayed on the UI.

Public Virtual Void PainTValue

ITYPEDEScriptorContext Context,

Object Value,

Graphics Canvas,

Rectangle Rectangle;

}

Public enum uitypeeditorEditStyle {

// There is no interactive UI component.

None = 1,

// Modal UI attribute will display a [...]

// To start a dialogue.

MODAL = 2,

/ / The drop-down UI property will display the button of the down arrow, and

// UI will be in the drop-down menu of a similar combo box.

Dropdown = 3

}

// Interface can be called by calling UITYPEEDITOR :: EditValue

// provider.getserviceObject (IwinFormSeditorvice))

// Retrieve.

Public interface ionformseditorService {

// Turn off the currently displayed drop-down menu.

Void Closedropdown ();

/ / For the value of the value of the UI editor to give a given control

// Place in the drop-down menu.

Void DropDownControl (Control Control);

// Start the Modal dialog box to edit the attribute value

DialogResult Showdialog (Form Dialog);

}

EditoAttribute is similar to TypeConvertRibute, which can be specified on their application or a particular type of attribute, which will replace any value specified in the Type itself.

User Click the drop-down or ellipse button on the property browser will call UITYPEEDITOR.EDITVALUE. Here is a typical implementation of EditValue in the drop-down editor: Public Override Object EditValue

IServiceObjectProvider Provider, iServiceObjectProvider Province, IservePriptorContext Context

Object value) {

Object returnvalue = value;

IF (provider! = null) {

IwinformSeditorService EDSVC = (IwinFormSeditorvice)

Provider.getServiceObject (

TypeOf (iWinformSeditorvice);

IF (EDSVC! = null) {

MyUieditorControl uieditor =

New myuieditorcontrol (edsvc);

Edsvc.dropdownControl (UIEditor);

Value = uieditor.newvalue;

}

}

Return Value;

}

PainTValue allows the editor to display the representative representation of a visible specific value. For example, the WinForms object uses the editor to edit images, colors, and fonts.

Figure 2. Editor display

This is a code based on code:

Public Override Void PainTValue

ITYPEDEScriptorContext Context,

Object Value,

Graphics Canvas,

Rectangle Rectangle {

Value is color) {

Color color = (color) value;

Solidbrush B = New Solidbrush (Color);

Canvas.FillRectangle (B, Rectangle);

b.dispose ();

}

}

Coloreditor's PainTValue Code.

From external introduction: code persistence

Unlike some past designers, WIN FORMS and other VS .NET designers for .NET Framework components are only dependent on code persistence. There is no incredible format, there is no hidden data, only concise code. Of course, content such as bitmaps and localized strings are packaged with code in binary form, but the status of components and their composition remain continuous in the code. A code is generated when making changes in the designer. If you handle the code, it will be reanprically, and the changes will also be reflected in the designer.

In order to take advantage of this feature, the designer in .NET Framework provides all channels. For any type, all designers must learn about the following:

What information is meaningful for persistence and object status? How does information return to an active object?

These have been briefly discussed in the previous chapters. We again emphasize TypeConverter is the core of the process. Code Generation and Code Analyzer involves a special type of persistinfo called CreationBundle. E.g:

[TypeConverter (TypeOf (INTBoolString.intBoolStringConverter)]]

Public class

INTBOOLSTRING {

PRIVATE INT INT INTVAL

PRIVATE STRINGVAL;

Private Bool BoolVal;

Public intBoolString (String S, INT I, BOOL B) {

This.intval = i;

THIS.STRINGVAL = S; this.boolval = B;

}

Public bool bool {

Get {return boolval;}

SET {BOOLVAL = Value;}

}

Public int int {

Get {return.

Set {INTVAL = Value;

}

Public String String {

Get {return stringval;}

SET {stringval = value;}

}

Public Override string toString () {

Return IntVal "," Boolval "," Stringval;

}

Public Class IntBoolStringConverter: typeconverter {

Public Override Bool CanconvertFrom

ITYPEDEScriptorContext Context,

TYPE SOURCEPE) {

Return (SourceType == TypeOf (String));

}

Public Virtual Object ConvertFrom

ITYPEDEScriptorContext Context,

Object Value,

Object [] arguments) {

Value Is String {

String stringvalue = (string) Value;

Int IntValue;

Bool boolvalue;

Int commandex =

StringValue.indexof (',');

IF (COMMAINDEX! = -1) {

INTVALUE = INT32.

Parse (StringValue.

Substring (0, COMMAINDEX);

COMMAINDEX = StringValue.

Indexof (',',

COMMAINDEX 1);

IF (COMMAINDEX! = -1) {

Int nextcomma = stringValue.indexof (',', COMMAINDEX 1);

IF (NextComma! = -1) {

BoolValue = Boolean.Pars (StringValue.Substring (CommaIndex 1,

Nextcomma - commandex);

StringValue = stringvalue.substring (NextComma 1);

Return New IntBoolstring (intVal, BoolVal, StringValue);

}

}

}

Throw new formatexception ("Can't Convert" ' StringValue "' To IntBoolstring Object");

}

}

Public Override Persistinfo getPersistinfo (iTYPEDEScriptorContext Context, Object value) {

Value is IntBoolstring {

INTBOOLSTRING IBS = (intBoolstring) Value;

Return New CreationBundle (INTBoolstring), NULL,

NEW CREATIONARGUMENT [] {new codeargument (ibs.int, typeof (int32)),

NEW CREATIONARGUMENT (Ibs.Bool, TypeOf (Bool),

NEW CREATIONARGUMENT (Ibs.String, TypeOf (String))})

}

Return Base.getPersistInfo (Context, Value);

}

}

Public Override Object CreateInstance (ITYPEDESCRIPTORCONTEXT

Context, iDictionary propertyValues) {

Return New IntBoolString ((int) PropertyValues ​​["int"],

(BOOL) PropertyValues ​​["bool"],

(String) PropertyValue ["String"]);

}

Public Override Bool GetcreateInstanceSupported (iTYPEDEScriptorContext Context) {

Return True;

}

}

The advantage of using the CreationBundle object is that if the builder matches each type of CreationArguments, then the object knows how to create the object of the storage information. When calling TypeConverter :: CreateInstance and trying to create and initialize the object in this way, the default implementation of TypeConverter calls CREATIONBundle :: Invoke. If there is no builder, CreateInstance calls will be created more flexible objects using iDictionary. The incoming IDictionary object contains the non-sustainable value of each attribute name.

Components often contain attribute values ​​that make up multiple objects. Other frameworks often use attribute arrays for this purpose. But there are some shortcomings using arrays. For example, you need to copy an array when tuned and tuned an array, which will bring performance issues. An array cannot provide intelligent notifications for operations such as adding, modifying, or deleting values. In fact, if the attribute is transmitted back to an array, you have to make a lot of work to add and delete items. Arranges are still a snap value and will not be updated when the basic object changes.

Unlike this, .NET Framework uses a collection for this purpose, and the collection is an object of Icollection. Objects can create a collection and pass it to either object, and any changes to the basic object will update the reference. This object is notified if the collection is changed by other objects. In order to make the .NET Framework designer use a collection, they also need to support all properties, which have "get" and "set", which is an array of objects held by a collection. E.g:

Public Class IntCollection: Icollection {

PRIVATE INT [] VALUES

Public intcollection (int [】 intValues) {

THIS.VALUES = (int []) intValues.clone ();

}

Public int [] all {

Get {

Return (int []) Values.clone ();

}

SET {

VALUES = (int []) value.clone ();

}

}

Public int count {

Get {

IF (VALUES == NULL) {

Return 0;

}

Return VALUES.LENGTH;

}

}

[Browsable (false)]

Public Object syncroot {

Get {

Return this;

}

}

[Browsable (false)]

Public Bool IsReadonly {

Get {

Return False;

}

}

[Browsable (false)]

Public bool issynchronized {

Get {

Return True;

}

}

}

The .NET Framework persistence mechanism allows a collection or relief of the set. If a collection consists of a higher level, such as the above BOOLINSTRING sample type, you only need to create a valid Persistinfo (especially for the VS .NET Designer for the VS .NET Designer) with each item associated with this type of TypeConverter .

Component designer

As mentioned earlier, the .NET Framework built-in designer can meet the requirements of most of the major components. Despite this, .NET Framework provides a fully extended architecture for the component designer. All designers are based on the following system.componentmodel.design.IDesigner interface:

Public interface IDesigner {

// Component associated with this designer.

IComponent Component {get;}

/ / The design is associated with this component verb,

// For example, "Add Tag" for TabControl.

DesignerB [] Verbs {Get;

// Distribute the resources used by the designer,

// Designer is no longer available after calling.

Void dispose ();

// Call to make the designer execute "default operation",

/ / Is usually called to the component's double click on the response.

Void Dodefault ();

// initialize the designer with a given component.

Void Initialize;

}

As you can see, Idesigner is straightforward. The designer is associated with the component through DesigneRATIRATRIBUTE:

[Designer ("MyNamespace.Design.mycomponentDesigner, MyNamespace.dll"]]

Public class mycomponent: Component {

}

If Designerattribute does not appear in the class, the class hierarchy will be traveled until the development environment is found. In the previous example, the default ComponentDesigner is positioned on the Component base class and then use it. Some designers use the UI. And others are otherwise. For ComponentDesigner, you will see an icon that represents an object because the components usually do not have a UI. On the other hand, the WIN FORMS control has designers that display the actual control when design.

Figure 3. WIN FORM control at design time

Note that the control does not display the UI is the icon below the designer, and the Win Forms control with the UI is displayed in the Form Designer, which is the same as running. All of this is built on the iDesigner. Typically, the control's designer controls the WindowProc's WindowProc (from System.winForms.Design.ControlDesigner) to perform this task by simply overriding the WindowProc method) to perform complexity. task. However, for most components, the built-in default designer should be sufficient.

Access designer service and infrastructure

Many of the services and infrastructure components of the .NET Framework designer development environment simplifies complex operations, allowing interworking information between components. These services are always accessible by using the getServiceObjectProvider's iServiceObjectProvider. This is some interesting designer service list: Type Description IdesignerHost is the primary class associated with any top designer. Provide methods to add services, create and place components, delete components, and process the operation batch. IComponentChangeService provides notifications when adding, deleting, renamed, or modifying components. ISELECTIONSERVICE Sets or gets the project that is currently selected in the designer. ItoolboxService allows you to check or modify projects on the toolbox and their selection status, and more. IUndoservice provides tools for creating an operational revoking / redo unit and manages undo / re-stack. IHELPSERVICE Allows Settings Help Topics or call Help item IMenuCommandService Allows the designer menu command and verbs. IREferenceService maps the designer to the object. For example, naming components "Button 1".

IdesignerHost is the foundation of all designers in VS .NET. Idesignerhost is also an iServiceObjectProvider, which can dynamically add or delete services. It also provides methods to create components to ensure proper settings. Here is an example of creating components using IdesignerHost:

Public class myDesigner: idsigner {

//.

Private Void OnsurfaceDoubleDoubleClick (Object S, Eventargs E) {

Idesignerhost Host =

(Idesignerhost) this.component.site.getServiceObject (TypeOf (iDesignerhost));

IF (Host! = Null) {

Object newcomponent = host.createcomponent (TypeOf (MyComponent));

DOSMETHINTERESTINGWITHCOMPONENT (Newcomponent);

}

}

// ...

Grant a license for the component

In the scalable model of .NET Framework, the system structure granted to the license can also be expanded. For easy use, the framework defines a built-in, standard license grant method to control whether the components are licensed when designing, but developers can replace this scenario in any way they think.

// Add licenseProviderattribute to the control.

LicenseProvider (TypeOf (LicfilelicenseProvider)]

Public class mycontrol: richcontrol {

// Create a new empty certificate.

Private license license = NULL;

Public myControl () {

/ / Add a verification to the builder of the control.

License = licenseManager.validate (TypeOf (MyControl), this)

/ / Execute other instantiated tasks ...}

Public override void dispose () {

IF (license! = NULL) {

license.dispose ();

License = NULL;

}

}

Protected Override Void Finalize () {

Dispose ();

Base.Finalize ();

}

}

This example uses built-in license support to grant license. LicfieLicenseProvider is just in the same directory as the class assembly, looking for a file called .lic, classname is a full name. The name of the String type is system.string.lic. This file contains a string "System.String is a license component". If you find this file, LicenseManager.validate will return a license object, which will be assigned together with the class instance. It is also easy to implement your own license scheme. Simply create your own class from LicenseProvider and implement your own getLicense method. You may have to implement a registry-based license scheme, where the licensed design time has an entry in the registry:

Public Class RegistryLicenseProvider: licenseProvider {

Public Override license getLicense

LicenseContext context,

Type Type,

Object Instance,

Bool allowexceptions) {

RegistryKey licenseKey = registry.localmachine.

OpenSubKey ("Software // MyCompany // Componentlicenses");

IF (context.usagemode == licenseusagemode.designtime) {

IF (licenseKey! = null && licensekey.getvalue (type.fullname)! = NULL) {

Return New Reglicense (this, Type);

}

IF (allowexception) {

Throw new licenseexception (Type, Instance,

"Couldn''t get design-time license for ''" "

Type.Fullname "'');

}

Return NULL;

}

Else {

Return New RuntimeReglicense (this, Type);

}

}

Private class runtimereglicense: license {

Public string licenseKey {

Get {

Return Type.FullName;

}

}

Public override void dispose () {

}

}

PRIVATE CLAS reglicense: license {

Private registryLicenseProvider Owner;

Private type type;

Public Reglicense (RegistryLicenseProvider Owner, Type Type) {

this.owner = Owner;

THIS.TYPE = TYPE;

}

Public string licenseKey {

Get {

Return Type.FullName;

}

}

Public override void dispose () {

}

}

[LicenseProvider (TypeOf (RegistryLicenseProvider)]]]

Public class mycontrol: control {

}

Components using this license will have an entry in the following locations of the registry:

HKEY_LOCAL_MACHINE / SOFTWARE / MyCompany / Componentlicensees = "True"

in conclusion

Write controls in management code far better than traditional C / COM methods. Mircosoft's fundamental engineering improvements in the Visual Basic language programming from trivial program to C, from universal language to the restructuring Visual Basic language, making it possible to reduce the faults that may be greatly reduced. Mircosoft .NET Framework is the first code set developed by these technologies and principles, which supports the integrated designer is the key to this method.

转载请注明原文地址:https://www.9cbs.com/read-97894.html

New Post(0)