Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Build a Property Editor That Can Edit Any .NET Type : Page 7

This article describes how to create a Windows Forms control that leverages the power of the .NET Framework's UITypeEditor and TypeConverter classes at runtime to create a control that can display and edit the values of all .NET types.


advertisement
Implementing the IWindowsFormsEditorService Interface
A class that implements the IWindowsFormsEditorService interface launches the UITypeEditor instances. Although the interface contains only three methods, the service is quite complex to implement.

interface IWindowsFormsEditorService { void DropDownControl(Control control); void CloseDropDown(); DialogResult ShowDialog(Form dialog); }

The DropDownControl method must drop the control passed as a parameter; UITypeEditors with the DropDown style use this method. The CloseDropDown method must hide the control dropped by DropDownControl, and the ShowDialog method must display the dialog box passed as a parameter and return the result. UITypeEditors with the Modal style use this method.

To understand how to implement this service you must first understand how the UITypeEditor uses it

Opening a Modal UITypeEditor produces the following sequence of method calls:

  • The application calls the UITypeEditor's EditValue method, passing a service provider and the value to edit. For example, editor.EditValue(serviceProvider provider, object value)
  • The EditValue method creates a dialog box for editing the value.
  • The EditValue method asks the service provider for a service of type IWindowsFormsEditorService and asks this service to show the dialog box it has just created by calling ShowDialog.
  • The IWindowsFormsEditorService.ShowDialog method opens the dialog box and waits until the user chooses a new value from the dialog box or cancels the dialog.
  • The EditValue method returns the new value from the dialog box.
Opening a DropDown UITypeEditor produces a slightly different series of method calls:

  • The application calls the UITypeEditor's EditValue method, passing a service provider and the value to edit. For example, editor.EditValue(serviceProvider provider, object value)
  • The EditValue method creates a UI control for editing the value.
  • The EditValue method asks the service provider for a service of type IWindowsFormsEditorService and asks this service to show the UI control it has just created by calling DropDownControl.
  • The DropDownControl method displays the control and then waits until the user has chosen a new value.
  • After the user chooses the new value, the UI control calls CloseDropDown to close itself.
  • The EditValue method returns the new value from the UI control.
So, you need a service provider that can return an object that implements the IWindowsFormsEditorService interface. The following EditorService class implements both the IServiceProvider and the IWindowsFormsEditorService interfaces:

class EditorService : IServiceProvider, IWindowsFormsEditorService { private GenericValueEditor editor; public EditorService(GenericValueEditor editor) { this.editor = editor; } public object GetService(Type serviceType) { if (serviceType == typeof(IWindowsFormsEditorService)) return this; return null; } ... }

Implementing the ShowDialog method of the interface is easy; just call the ShowDialog method of the dialog itself:



public DialogResult ShowDialog(Form dialog) { dialog.ShowDialog(editor); return dialog.DialogResult; }

Implementing the two remaining methods is more difficult. To display the editor control below the GenericValueEditor, you have to embed it inside a form. Therefore you must define a new class—a subclass of the Form class with no caption and a single-line border. In the DropDownControl method you add the control to this form, place it below the UITypeEditor, and then show the form. The DropDownControl method must block until the user finishes editing; therefore, you need the method to wait until the form is made invisible by a call to CloseDropDown. Here's the code for the DropDownControl method.

public void DropDownControl(Control ctl) { if (dropDownForm == null) dropDownForm = new DropDownForm(this); dropDownForm.Visible = false; dropDownForm.Component = ctl; Rectangle editorBounds = editor.Bounds; Size size = dropDownForm.Size; // Location of the form Point location = new Point(editorBounds.Right - size.Width, editorBounds.Bottom+1); // Location in screen coordinate location = editor.Parent.PointToScreen(location); // Check that the form is in the screen // working area Rectangle screenWorkingArea = Screen.FromControl(editor).WorkingArea; location.X = Math.Min( screenWorkingArea.Right - size.Width, Math.Max(screenWorkingArea.X, location.X)); if (size.Height + location.Y + editor.textBox.Height > screenWorkingArea.Bottom) location.Y = location.Y - size.Height -- editorBounds.Height -1; dropDownForm.SetBounds(location.X, location.Y, size.Width, size.Height); dropDownForm.Visible = true; ctl.Focus(); editor.SelectEdit(); // Wait for the end of the editing while (dropDownForm.Visible) { Application.DoEvents(); MsgWaitForMultipleObjects(0, 0, true, 250, 255); } // Editing is done or aborted }

The tricky part here is the message loop that does a call to MsgWaitForMultipleObjects. This Win32 API method waits—without using 100% of the CPU cycles—until an event appears in the message queue.

Using the techniques shown in this article, you can take advantage of design time classes in the .NET framework (such as TypeConverter and UITypeEditor) to create rich runtime editors such as those used in the .NET property grid. Moreover, the techniques work for building editors that can edit any .NET type.

Author's Note: This article grew out of work done during the creation of a new ILOG product called "ILOG Gantt for .NET." Overall, the effort has been very useful, and has allowed us to provide rich editor support inside our product. We hope you will find this control very useful too.




Emmanuel Tissandier is an ILOG Chief Architect. He has worked with Java technology for over six years designing user interfaces and graphics and leading the ILOG JViews development team. Since 2002 Emmanuel has led the .NET visualization development team at ILOG.
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap
Thanks for your registration, follow us on our social networks to keep up-to-date