Component Editors


A component editor is a class that provides a custom user interface for editing the properties of a control as a whole. The UI offered by a component editor is analogous to the property pages offered by ActiveX controls. A component editor is not a replacement for the property browser; rather, it offers a more convenient UI for editing the commonly accessed properties of a control. The DataList and DataGrid controls utilize component editors to offer richer property editing.

In this section, we'll show you how to implement a component editor for the MyLabel control we developed earlier in the "UI Type Editors" section.

The MyLabelComponentEditor Example

The MyLabelComponentEditor that we will now implement provides the UI shown in Figure 15-8 for editing the properties of the MyLabel control. The UI that Visual Studio .NET displays for a component editor refers to the editor as a property builder . MyLabelComponentEditor enables a page developer to edit three properties of MyLabel : BackColor , ForeColor , and Text . The editor also provides a UI to launch the color picker dialog box for editing the properties of type Color .

Figure 15-8. The UI created by the MyLabelComponentEditor class

graphics/f15hn08.jpg

We have associated MyLabelComponentEditor with MyLabel by applying the EditorAttribute metadata attribute to the control:

 [ Editor(typeof(MSPress.ServerControls.Design.MyLabelComponentEditor), typeof(ComponentEditor)) ] publicclassMyLabel:Label{...} 

We described EditorAttribute in the previous section. Note that the second argument passed into the constructor of the attribute is the type of the ComponentEditor class, which is the base class for component editors.

Listing 15-10 contains the code for the MyLabelComponentEditor class. MyLabelComponentEditor derives from WindowsFormsComponentEditor , which in turn derives from ComponentEditor . The code demonstrates how to override the EditComponent method to create a Windows Forms Form for property editing.

Listing 15-10 MyLabelComponentEditor.cs
 usingSystem; usingSystem.Design; usingSystem.ComponentModel; usingSystem.ComponentModel.Design; usingSystem.Windows.Forms; usingSystem.Windows.Forms.Design; usingMSPress.ServerControls; 
 namespaceMSPress.ServerControls.Design{ publicclassMyLabelComponentEditor:WindowsFormsComponentEditor{ publicoverrideboolEditComponent(ITypeDescriptorContextcontext,objectcomponent, IWin32Windowowner){ MyLabellabel=componentasMyLabel; if(label==null){ thrownewArgumentException("ComponentmustbeaMyLabelobject", "component"); } IServiceProvidersite=label.Site; IComponentChangeServicechangeService=null; DesignerTransactiontransaction=null; boolchanged=false; try{ if(site!=null){ IDesignerHostdesignerHost=(IDesignerHost) site.GetService(typeof(IDesignerHost)); transaction=designerHost.CreateTransaction("PropertyBuilder"); changeService=(IComponentChangeService) site.GetService(typeof(IComponentChangeService)); if(changeService!=null){ try{ changeService.OnComponentChanging(label, null); } catch(CheckoutExceptionex){ if(ex==CheckoutException.Canceled) returnfalse; throwex; } } } try{ MyLabelComponentEditorFormform= newMyLabelComponentEditorForm(label); if(form.ShowDialog(owner)==DialogResult.OK){ changed=true; } } finally{ if(changed&&changeService!=null){ changeService.OnComponentChanged(label,null, null,null); } } } finally{ if(transaction!=null){ if(changed){ transaction.Commit(); } else{ transaction.Cancel(); } } } returnchanged; } } } 

Every control has a Site property whose type is the System.ComponentModel.ISite interface. The ISite interface derives from the System.IServiceProvider interface whose GetService method allows a component to access various design-time services when it is hosted in a design environment. In its implementation of the EditComponent method, MyLabelComponentEditor retrieves the IComponentChangeService and IDesignerHost services via the Site property associated with the MyLabel instance. The IComponentChangeService specifies the contract for updating the design surface when components are added, changed, or removed from the design surface. The IDesignerHost interface specifies the contract for supporting designer transactions, for managing components and their designers, and for obtaining information on the state of the designer. The .NET Framework does not provide an implementation of these interfaces ”they are implemented by a design environment such as the Web Forms designer in Visual Studio .NET. MyLabelComponentEditor uses the IDesignerHost instance to start a designer transaction and the IComponentChange ­Service instance to tell the design environment whether the properties of the MyLabel instance are changed by the page developer.

MyLabelComponentEditor creates and launches an instance of the MyLabelComponentEditorForm class, which is a Windows Forms Form that defines the UI (shown in Figure 15-8) for editing the properties of a MyLabel control. The form contains the logic to initialize its own UI with the current property values of the control it is associated with. When the form is committed, it updates the control with the modified values. The code for MyLabelComponentEditorForm is shown in Listing 15-11.

Listing 15-11 MyLabelComponentEditorForm.cs
 usingSystem; usingSystem.Collections; usingSystem.ComponentModel; usingSystem.Drawing; usingSystem.Web.UI.Design; usingSystem.Windows.Forms; usingMSPress.ServerControls; namespaceMSPress.ServerControls.Design{ publicclassMyLabelComponentEditorForm: System.Windows.Forms.Form{ privateSystem.Windows.Forms.Labellabel1; privateSystem.Windows.Forms.ComboBoxforeColorCombo; privateSystem.Windows.Forms.ButtonforeColorButton; privateSystem.Windows.Forms.ButtonbackColorButton; privateSystem.Windows.Forms.ComboBoxbackColorCombo; privateSystem.Windows.Forms.Labellabel2; privateSystem.Windows.Forms.LabeltextLabel; privateSystem.Windows.Forms.TextBoxtextBox1; privateSystem.Windows.Forms.ButtonokButton; privateSystem.Windows.Forms.ButtoncancelButton; privateMyLabel_myLabel; publicMyLabelComponentEditorForm(MyLabelcomponent){ InitializeComponent(); _myLabel=component; textBox1.Text=_myLabel.Text; foreColorCombo.Text= ColorTranslator.ToHtml(_myLabel.ForeColor); backColorCombo.Text= ColorTranslator.ToHtml(_myLabel.BackColor); } 
 #regionWindowsFormDesignergeneratedcode  #endregion privatevoidokButton_Click(objectsender,System.EventArgse){ //WesetthepropertiesoftheMyLabelinstancebyusing //PropertyDescriptorstoenableundofunctionality //afterapagedevelopersetsthese //propertiesinthedesigner. //Ifyoudonotwanttoprovideundofunctionality, //youcanreplacetheimplementationofthismethod //withthesimplercodeshowninthecommentedblock. // /* try{ _myLabel.Text=textBox1.Text; _myLabel.ForeColor= ColorTranslator.FromHtml(foreColorCombo.Text.Trim()); _myLabel.BackColor= ColorTranslator.FromHtml(backColorCombo.Text.Trim()); } catch{ } */ PropertyDescriptorCollectionprops= TypeDescriptor.GetProperties(_myLabel); try{ PropertyDescriptortextProperty=props["Text"]; if(textProperty!=null){ textProperty.SetValue(_myLabel,textBox1.Text); } } catch{ } try{ PropertyDescriptorforeColorProperty= props["ForeColor"]; if(foreColorProperty!=null){ ColorforeColor= ColorTranslator.FromHtml(foreColorCombo.Text.Trim()); foreColorProperty.SetValue(_myLabel,foreColor); } } catch{ } try{ PropertyDescriptorbackColorProperty= props["BackColor"]; if(backColorProperty!=null){ ColorbackColor= ColorTranslator.FromHtml(backColorCombo.Text.Trim()); backColorProperty.SetValue(_myLabel,backColor); } } catch{ } DialogResult=DialogResult.OK; Close(); } privatevoidforeColorButton_Click(objectsender, System.EventArgse){ stringcolor=foreColorCombo.Text.Trim(); color=ColorBuilder.BuildColor(_myLabel,this,color); if(color!=null){ foreColorCombo.Text=color; } } privatevoidbackColorButton_Click(objectsender, System.EventArgse){ stringcolor=backColorCombo.Text.Trim(); color=ColorBuilder.BuildColor(_myLabel,this,color); if(color!=null){ backColorCombo.Text=color; } } } } 

MyLabelComponentEditorForm derives from System.Windows.Forms.Form . The argument of its constructor is a MyLabel instance. The constructor uses the initial values of the BackColor , ForeColor , and Text properties of the MyLabel instance to initialize the values of the combo boxes and the text box.

The okButton_Click event handler is associated with the okButton Button instance on the form and updates the BackColor , ForeColor , and Text properties of MyLabel with the values in the combo boxes and the text box on the form.

The combo boxes offer a drop-down list of standard color names . In addition, when clicked, the buttons next to the combo boxes launch the color picker dialog box shown in Figure 15-8. The backColorButton_Click and foreColorButton_Click event handlers associated with the buttons utilize the static BuildColor method of the System.Web.UI.Design.ColorBuilder class to start the color picker dialog box. The event handlers also update the combo boxes with the color selected by the page developer within the color picker dialog box.

The ColorBuilder is a helper class that allows MyLabelComponentEditor to easily create a specialized UI for editing a property of type Color . In the present version of the .NET Framework, two helper classes provide a custom UI for property editing: ColorBuilder and System.Web.UI.Design.UrlBuilder . In the future, the .NET Framework might offer additional builder classes for creating a UI geared toward editing specific property types.

Designer Verb That Initiates Component Editing

We'll now show you how to implement a designer verb that launches the component editor. A page developer can launch a component editor in one of three standard ways:

  • Click the Property Pages button at the top of the property browser, as shown in Figure 15-9. This button is enabled when a component has an associated component editor. This mechanism does not use a designer verb.

  • Click the Property Builder command that appears at the bottom of the property browser, as shown in Figure 15-9. This command represents a designer verb.

  • Right-click the component and choose the Property Builder command from the context menu. This command also represents a designer verb.

    Figure 15-9. The Property Pages button and the Property Builder designer verb in the property browser of Visual Studio .NET

    graphics/f15hn09.jpg

The first mechanism is available by default when a component has an associated component editor (specified via the EditorAttribute metadata attribute). To enable the latter two mechanisms, you have to implement a designer that provides a designer verb that launches the component editor. A designer verb makes the component editor more discoverable by creating commands on the design surface. In Visual Studio .NET, a designer verb creates a command link in the property browser and a menu command in the context menu associated with the control.

Listing 15-12 contains the code for the MyLabelDesigner that creates the designer verb shown in Figure 15-9. The designer is associated with MyLabel control via the DesignerAttribute , as shown in Listing 15-6.

Listing 15-12 MyLabelDesigner.cs
 usingSystem; usingSystem.Collections; usingSystem.ComponentModel; usingSystem.ComponentModel.Design; usingSystem.Diagnostics; usingSystem.Web.UI; usingSystem.Web.UI.Design; usingSystem.Web.UI.Design.WebControls; usingSystem.Web.UI.WebControls; usingMSPress.ServerControls; namespaceMSPress.ServerControls.Design{ 
 publicclassMyLabelDesigner:LabelDesigner{ privateDesignerVerbCollection_designerVerbs; publicoverrideDesignerVerbCollectionVerbs{ get{ if(_designerVerbs==null){ _designerVerbs=newDesignerVerbCollection(); _designerVerbs.Add(newDesignerVerb("PropertyBuilder...", newEventHandler(this.OnPropertyBuilder))); } return_designerVerbs; } } privatevoidOnPropertyBuilder(objectsender,EventArgse){ MyLabelComponentEditorcompEditor= newMyLabelComponentEditor(); compEditor.EditComponent(Component); } publicoverridevoidInitialize(IComponentcomponent){ if(!(componentisMyLabel)){ thrownewArgumentException("ComponentmustbeaMyLabelcontrol.",  "component"); } base.Initialize(component); } } } 

MyLabelDesigner adds a DesignerVerb to its Verbs collection, which we described earlier in this chapter in the "Designers" section. The constructor of a DesignerVerb takes two arguments: a string that specifies a command name , and an event handler that performs some logic in response to the command. MyLabelDesigner creates a verb with the text "Property Builder ", which invokes the OnPropertyBuilder event handler. In the OnPropertyBuilder method, MyLabelDesigner creates an instance of MyLabelComponentEditor and invokes its EditComponent method to launch the component editing UI.



Developing Microsoft ASP. NET Server Controls and Components
Developing Microsoft ASP.NET Server Controls and Components (Pro-Developer)
ISBN: 0735615829
EAN: 2147483647
Year: 2005
Pages: 183

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net