Componenteditor
"Second choice"
In the previous article, I have said so much about the editor. Are you done? No. The previous article only introduced the uitypeeditor of Operation attributes. Do you still remember "Property generator..." under the Property Window of the DataGrid?
When we click "generate generator... ", IDE will pop up a form that provides an all-round interactive interface for operations on the DataGrid attributes. This interface is more convenient and easy to use than propertygrid, and more in line with the" national conditions "of the DataGrid ". Therefore, the user has a second option outside the attribute pane.
So what is this "Property generator? It is also an editor, but it is not a uitypeeditor, but a componenteditor. Right, it is a component editor. It is not used to edit a property, but to operate the entire control.
Let's take an example to see what to do to implement the component editor?
Control Subject
[
Designer (typeof (mydesigner )),
Editor (typeof (mycomponenteditor), typeof (componenteditor ))
]
Public class mycontrol: webcontrol {
}
Here we use two attributes to describe our control subject class: designer and editor. The first one is to associate the control subject class with a designer. The designer is used here, this is because the designer class is used to conveniently call the component editor. The second attribute is associated with an editor for the control subject class. You can see that its second parameter is componenteditor rather than uitypeeditor.
Editor form class
Public class mycomponenteditorform: system. Windows. Forms. FORM {
Private mycontrol _ mycontrol;
Public mycontrolcomponenteditorform (mycontrol component ){
Initializecomponent ();
_ Mycontrol = component;
// Use the _ mycontrol attribute to initialize the operation controls on the form (for example, some Textbox, also use the propertygrid value I mentioned earlier ).
}
// The following figure shows the logic outline after you click OK.
Private void okbutton_click (Object sender, system. eventargs e ){
Propertydescriptor is used to assign values to component and directly use _ mycontrol. property_1 = textbox1.text is an advantage of the Undo function that supports operations. # region uses propertydescriptor to assign values to component and directly uses _ mycontrol. property_1 = textbox1.text has the advantage of assigning values based on logic such as the Undo function that supports operations.
Propertydescriptorcollection props = typedescriptor. getproperties (_ mycontrol );
Try {
Propertydescriptor property_1 = props ["property_1"];
If (textproperty! = NULL ){
Textproperty. setvalue (_ mycontrol, textbox1.text );
}
}
Catch {
}
Dialogresult = dialogresult. OK;
Close ();
# Endregion
}
}
Editor class
Public class mycomponenteditor: windowsformscomponenteditor {
// Main logic of the Operation Control
Public override bool editcomponent (itypedescriptorcontext context, object component, iwin32window owner ){
Mycontrol control = component as mycontrol;
If (control = NULL ){
Throw new argumentexception ("Operation object check, can only be a specific class", "component ");
}
Iserviceprovider site = control. Site; // each control has a site attribute. Its getservice method enables the control to get various design-period services in the design environment. Such as icomponentchangeservice, idesignereventservice, idesignerhost, idesigneroptionservice, etc.
Icomponentchangeservice changeservice = NULL; // icomponentchangeservice specifies that the design interface is modified when the component is added, deleted, or modified, and provides a method to trigger the componentchanged or componentchanging event. Not Implemented by. Net FW, but implemented by vs.net.
Designertransaction transaction = NULL; // designertransaction provides a way to group A series of design-time operations to improve performance and ensure that most types of changes can be undone.
Bool changed = false;
Try {
If (site! = NULL ){
Idesignerhost designerhost = (idesignerhost) site. getservice (typeof (idesignerhost); // specifies support for designer transactions, management components and designers, and designer information. Implemented by vs.net.
Transaction = designerhost. createtransaction ("transaction group name"); // The designertransaction is obtained by idesignerhost.
Changeservice = (icomponentchangeservice) site. getservice (typeof (icomponentchangeservice ));
If (changeservice! = NULL ){
Try {
Changeservice. oncomponentchanging (control, null); // The second parameter is memberdescriptor. It is the base class of eventdescriptor and propertydescriptor class, indicating the member being modified. If this change is irrelevant to a single member, it will be a null reference.
}
Catch (checkoutexception ex) {// The checkoutexception here indicates that the VSS check fails.
If (EX = checkoutexception. canceled)
Return false;
Throw ex;
}
}
}
Try {
// The following Code Implement calling a compiled editor window
Mycomponenteditorform form = new mycomponenteditorform (control );
If (Form. showdialog (owner) = dialogresult. OK) {// from. showdialog (owner) specifies a modal window where from is the owner.
Changed = true;
}
}
Finally {
If (changed & changeservice! = NULL) {// if you click OK in the editor window, a change event is triggered.
Changeservice. oncomponentchanged (control, null); // because the change is not related to a single attribute, all three parameters are null.
}
}
}
Finally {
If (transaction! = NULL ){
If (changed) {// if everything is normal, submit the designer event
Transaction. Commit ();
}
Else {
Transaction. Cancel ();
}
}
}
Return changed;
}
}
After doing this, you can use the Attribute Editor. We can see that the attribute page button at the end of the attribute pane is available. You can click this button to open the Attribute Editor.
Designer
"Wyswyg"
Maybe you will say: Remember that the property editor of The DataGrid can be opened with a hyperlink and right-click menu at the bottom of the property pane. Why is it not?
To answer this question, we need to use designer.
The designer is a class used to manage the display behavior of controls during design. The core designer of webform and winform comes from system. componentmodel. design. componentdesigner, so both of them have the same setup, but their engines are completely different. webform uses ie as the engine, and winform uses GDI + as the engine. Since I have little access to winform, the following describes how to develop the webform control designer.
Let's take a look at how to solve the above problems. You can use the shortcut menu to open the component editor and other functions by customizing the designer verb.
Designer verb
The designer verb is the life cycle in the design interface. The designer provides a designer verb set: designerverbcollection verbs {Get ;}
Let's take a look at how our designer class customizes verbs:
Public class mycontroldesigner: controldesigner {
Private designerverbcollection designerverbs;
Public override designerverbcollection verbs {
Get {
If (designerverbs = NULL ){
Designerverbs = new designerverbcollection ();
Designerverbs. Add (New designerverb ("Native Editor", new eventhandler (this. oncontrolpropertybuilder); // Add a verb and associate it with a method.
}
Return designerverbs;
}
}
Private void oncontrolpropertybuilder (Object sender, eventargs e ){
Mycomponenteditor compeditor = new mycomponenteditor ();
Compeditor. editcomponent (component );
}
}
Now you can see that the editor command is opened in the lower and context menu of the attribute pane.
The main function of designer is to implement the "What you see is what you get" of controls during the design period. So we need to know more about the design period. Let's look at the following code:
Public override void initialize (icomponent component ){
If (! (Component is mycontrol )){
Throw new argumentexception ("component must be a mycontrol control.", "component ");
}
Base. initialize (component );
}
Public override string getdesigntimehtml (){
Mycontrol control = (mycontrol) component;
String designtimehtml = string. empty;
Try {
Designtimehtml = base. getdesigntimehtml ();
}
Catch (exception e ){
Designtimehtml = geterrordesigntimehtml (E );
}
Return designtimehtml;
}
Protected override string getemptydesigntimehtml (){
Return createplaceholderdesigntimehtml ("right-click to set control attributes .");
}
Protected override string geterrordesigntimehtml (exception e ){
Return createplaceholderdesigntimehtml ("generated error .");
}
We can understand the meaning of these overwriting methods.
Note the following points:
1. If the control is a composite control (that is, the control synthesized by multiple basic controls .), You 'd better ask the designer to call the getdesignertimehtml method first to ensure that its sub-control is not null.
2. The getdesigntimehtml method of the controldesigner base class calls the control's rendercontrol method to return an HTML string. By default, the control will look similar to the control in the design period and runtime. Is there a way to make the design period different from the operation period? Of course you can. The simplest way is to use the overridegetdesigntimehtml method to implement your own rendering logic. However, you can also use another technique, that is, the onperrender method will be called at runtime and then the render method will be called, by default, the onperrender method is not called during the design period. Therefore, you can use this difference to easily make the two different.
In addition, the design class of the template control is reserved for the template ControlArticleAbout