36
1 out of 2 rated this helpful - Rate this topic Walkthrough: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features Visual Studio 2010 Updated: July 2010 The design-time experience for a custom control can be enhanced by authoring an associated custom designer. This walkthrough illustrates how to create a custom designer for a custom control. You will implement a MarqueeControl type and an associated designer class, called MarqueeControlRootDesigner. The MarqueeControl type implements a display similar to a theater marquee, with animated lights and flashing text. The designer for this control interacts with the design environment to provide a custom design-time experience. With the custom designer, you can assemble a custom MarqueeControl implementation with animated lights and flashing text in many combinations. You can use the assembled control on a form like any other Windows Forms control. Tasks illustrated in this walkthrough include: Creating the Project Creating a Control Library Project Referencing the Custom Control Project Defining a Custom Control and Its Custom Designer Creating an Instance of Your Custom Control Setting Up the Project for Design-Time Debugging Implementing Your Custom Control Creating a Child Control for Your Custom Control Create the MarqueeBorder Child Control Creating a Custom Designer to Shadow and Filter Properties Handling Component Changes Adding Designer Verbs to your Custom Designer Creating a Custom UITypeEditor Testing your Custom Control in the Designer When you are finished, your custom control will look something like the following: Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb 1 of 36 5/25/2012 11:39 AM

Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Embed Size (px)

Citation preview

Page 1: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

1 out of 2 rated this helpful - Rate this topic

Walkthrough: Creating a Windows FormsControl That Takes Advantage of Visual Studio Design-TimeFeaturesVisual Studio 2010

Updated: July 2010

The design-time experience for a custom control can be enhanced by authoring an associated customdesigner.

This walkthrough illustrates how to create a custom designer for a custom control. You will implementa MarqueeControl type and an associated designer class, called MarqueeControlRootDesigner.

The MarqueeControl type implements a display similar to a theater marquee, with animated lightsand flashing text.

The designer for this control interacts with the design environment to provide a custom design-timeexperience. With the custom designer, you can assemble a custom MarqueeControl implementationwith animated lights and flashing text in many combinations. You can use the assembled control on aform like any other Windows Forms control.

Tasks illustrated in this walkthrough include:

Creating the Project

Creating a Control Library Project

Referencing the Custom Control Project

Defining a Custom Control and Its Custom Designer

Creating an Instance of Your Custom Control

Setting Up the Project for Design-Time Debugging

Implementing Your Custom Control

Creating a Child Control for Your Custom Control

Create the MarqueeBorder Child Control

Creating a Custom Designer to Shadow and Filter Properties

Handling Component Changes

Adding Designer Verbs to your Custom Designer

Creating a Custom UITypeEditor

Testing your Custom Control in the Designer

When you are finished, your custom control will look something like the following:

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

1 of 36 5/25/2012 11:39 AM

Page 2: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Note

Prerequisites

Creating the Project

Creating a Control Library Project

For the complete code listing, see How to: Create a Windows Forms Control That Takes Advantage ofDesign-Time Features.

In order to complete this walkthrough, you will need:

Sufficient permissions to be able to create and run Windows Forms application projects on thecomputer where Visual Studio is installed.

The first step is to create the application project. You will use this project to build the applicationthat hosts the custom control.

To create the project

Create a Windows Forms Application project called "MarqueeControlTest." For moreinformation, see How to: Create a New Windows Forms Application Project.

The next step is to create the control library project. You will create a new custom control and itscorresponding custom designer.

To create the control library project

Add a Windows Forms Control Library project to the solution. Name the project"MarqueeControlLibrary."

1.

Using Solution Explorer, delete the project's default control by deleting the source file named"UserControl1.cs" or "UserControl1.vb", depending on your language of choice. For moreinformation, see How to: Remove, Delete, and Exclude Items.

2.

Add a new UserControl item to the MarqueeControlLibrary project. Give the new source filea base name of "MarqueeControl."

3.

Using Solution Explorer, create a new folder in the MarqueeControlLibrary project. Formore information, see How to: Add New Project Items. Name the new folder "Design."

4.

The dialog boxes and menu commands you see might differ from those described in Helpdepending on your active settings or edition. To change your settings, choose Import and ExportSettings on the Tools menu. For more information, see Working with Settings.

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

2 of 36 5/25/2012 11:39 AM

Page 3: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Note

Referencing the Custom Control Project

Defining a Custom Control and Its Custom Designer

Right-click the Design folder and add a new class. Give the source file a base name of"MarqueeControlRootDesigner."

5.

You will need to use types from the System.Design assembly, so add this reference to theMarqueeControlLibrary project.

6.

You will use the MarqueeControlTest project to test the custom control. The test project willbecome aware of the custom control when you add a project reference to theMarqueeControlLibrary assembly.

To reference the custom control project

In the MarqueeControlTest project, add a project reference to the MarqueeControlLibraryassembly. Be sure to use the Projects tab in the Add Reference dialog box instead ofreferencing the MarqueeControlLibrary assembly directly.

Your custom control will derive from the UserControl class. This allows your control to contain othercontrols, and it gives your control a great deal of default functionality.

Your custom control will have an associated custom designer. This allows you to create a uniquedesign experience tailored specifically for your custom control.

You associate the control with its designer by using the DesignerAttribute class. Because you aredeveloping the entire design-time behavior of your custom control, the custom designer willimplement the IRootDesigner interface.

To define a custom control and its custom designer

Open the MarqueeControl source file in the Code Editor. At the top of the file, import thefollowing namespaces:

1.

Add the DesignerAttribute to the MarqueeControl class declaration. This associates thecustom control with its designer.

2.

To use the System.Design assembly, your project must target the full version of the .NETFramework, not the .NET Framework Client Profile. To change the target framework, seeHow to: Target a Specific .NET Framework Version or Profile.

using System;using System.Collections;using System.ComponentModel;using System.ComponentModel.Design;using System.Drawing;using System.Windows.Forms;using System.Windows.Forms.Design;

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

3 of 36 5/25/2012 11:39 AM

Page 4: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Open the MarqueeControlRootDesigner source file in the Code Editor. At the top of thefile, import the following namespaces:

3.

Change the declaration of MarqueeControlRootDesigner to inherit from theDocumentDesigner class. Apply the ToolboxItemFilterAttribute to specify the designerinteraction with the Toolbox.

Note The definition for the MarqueeControlRootDesigner class has been enclosed in anamespace called "MarqueeControlLibrary.Design." This declaration places the designer in aspecial namespace reserved for design-related types.

4.

Define the constructor for the MarqueeControlRootDesigner class. Insert a WriteLinestatement in the constructor body. This will be useful for debugging purposes.

5.

[Designer( typeof( MarqueeControlLibrary.Design.MarqueeControlRootDesigner ), typeofpublic class MarqueeControl : UserControl

{

using System;using System.Collections;using System.ComponentModel;using System.ComponentModel.Design;using System.Diagnostics;using System.Drawing.Design;using System.Windows.Forms;using System.Windows.Forms.Design;

namespace MarqueeControlLibrary.Design{ [ToolboxItemFilter("MarqueeControlLibrary.MarqueeBorder", ToolboxItemFilterType.Require)] [ToolboxItemFilter("MarqueeControlLibrary.MarqueeText", ToolboxItemFilterType.Require)] [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name =

public class MarqueeControlRootDesigner : DocumentDesigner {

public MarqueeControlRootDesigner(){ Trace.WriteLine("MarqueeControlRootDesigner ctor");}

C#

C#

C#

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

4 of 36 5/25/2012 11:39 AM

Page 5: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Creating an Instance of Your Custom Control

Setting Up the Project for Design-Time Debugging

Checkpoint

To observe the custom design-time behavior of your control, you will place an instance of yourcontrol on the form in MarqueeControlTest project.

To create an instance of your custom control

Add a new UserControl item to the MarqueeControlTest project. Give the new source file abase name of "DemoMarqueeControl."

1.

Open the DemoMarqueeControl file in the Code Editor. At the top of the file, import theMarqueeControlLibrary namespace:

2.

Change the declaration of DemoMarqueeControl to inherit from the MarqueeControl class.1.

Build the project.2.

Open Form1 in the Windows Forms Designer.3.

Find the MarqueeControlTest Components tab in the Toolbox and open it. Drag aDemoMarqueeControl from the Toolbox onto your form.

4.

Build the project.5.

When you are developing a custom design-time experience, it will be necessary to debug yourcontrols and components. There is a simple way to set up your project to allow debugging at designtime. For more information, see Walkthrough: Debugging Custom Windows Forms Controls at DesignTime.

To set up the project for design-time debugging

Right-click the MarqueeControlLibrary project and select Properties.1.

In the "MarqueeControlLibrary Property Pages" dialog box, select the Debug page.2.

In the Start Action section, select Start External Program. You will be debugging aseparate instance of Visual Studio, so click the ellipsis ( ) button to browse for the VisualStudio IDE. The name of the executable file is devenv.exe, and if you installed to the defaultlocation, its path is %programfiles%\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe.

3.

Click OK to close the dialog box.4.

Right-click the MarqueeControlLibrary project and select "Set as StartUp Project" to enablethis debugging configuration.

5.

You are now ready to debug the design-time behavior of your custom control. Once you havedetermined that the debugging environment is set up correctly, you will test the association between

using MarqueeControlLibrary;

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

5 of 36 5/25/2012 11:39 AM

Page 6: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Implementing Your Custom Control

the custom control and the custom designer.

To test the debugging environment and the designer association

Open the MarqueeControlRootDesigner source file in the Code Editor and place abreakpoint on the WriteLine statement.

1.

Press F5 to start the debugging session. Note that a new instance of Visual Studio is created.2.

In the new instance of Visual Studio, open the "MarqueeControlTest" solution. You can easilyfind the solution by selecting Recent Projects from the File menu. The"MarqueeControlTest.sln" solution file will be listed as the most recently used file.

3.

Open the DemoMarqueeControl in the designer. Note that the debugging instance of VisualStudio acquires focus and execution stops at your breakpoint. Press F5 to continue thedebugging session.

4.

At this point, everything is in place for you to develop and debug your custom control and itsassociated custom designer. The remainder of this walkthrough will concentrate on the details ofimplementing features of the control and the designer.

The MarqueeControl is a UserControl with a little bit of customization. It exposes two methods:Start, which starts the marquee animation, and Stop, which stops the animation. Because theMarqueeControl contains child controls that implement the IMarqueeWidget interface, Start andStop enumerate each child control and call the StartMarquee and StopMarquee methods,respectively, on each child control that implements IMarqueeWidget.

The appearance of the MarqueeBorder and MarqueeText controls is dependent on the layout, soMarqueeControl overrides the OnLayout method and calls PerformLayout on child controls of thistype.

This is the extent of the MarqueeControl customizations. The run-time features are implementedby the MarqueeBorder and MarqueeText controls, and the design-time features are implementedby the MarqueeBorderDesigner and MarqueeControlRootDesigner classes.

To implement your custom control

Open the MarqueeControl source file in the Code Editor. Implement the Start and Stop

methods.1.

public void Start(){

// The MarqueeControl may contain any number of// controls that implement IMarqueeWidget, so// find each IMarqueeWidget child and call its// StartMarquee method.foreach( Control cntrl in this.Controls )

{if( cntrl is IMarqueeWidget )

{ IMarqueeWidget widget = cntrl as IMarqueeWidget; widget.StartMarquee();

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

6 of 36 5/25/2012 11:39 AM

Page 7: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Creating a Child Control for Your Custom Control

Override the OnLayout method.2.

The MarqueeControl will host two kinds of child control: the MarqueeBorder control and theMarqueeText control.

MarqueeBorder: This control paints a border of "lights" around its edges. The lights flash insequence, so they appear to be moving around the border. The speed at which the lights flashis controlled by a property called UpdatePeriod. Several other custom properties determineother aspects of the control's appearance. Two methods, called StartMarquee andStopMarquee, control when the animation starts and stops.

} }}

public void Stop(){

// The MarqueeControl may contain any number of// controls that implement IMarqueeWidget, so find// each IMarqueeWidget child and call its StopMarquee// method.foreach( Control cntrl in this.Controls )

{if( cntrl is IMarqueeWidget )

{ IMarqueeWidget widget = cntrl as IMarqueeWidget; widget.StopMarquee(); } }}

protected override void OnLayout(LayoutEventArgs levent){

base.OnLayout (levent);

// Repaint all IMarqueeWidget children if the layout// has changed.foreach( Control cntrl in this.Controls )

{if( cntrl is IMarqueeWidget )

{ Control control = cntrl as Control;

control.PerformLayout(); } }}

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

7 of 36 5/25/2012 11:39 AM

Page 8: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

MarqueeText: This control paints a flashing string. Like the MarqueeBorder control, thespeed at which the text flashes is controlled by the UpdatePeriod property. The MarqueeText

control also has the StartMarquee and StopMarquee methods in common with theMarqueeBorder control.

At design time, the MarqueeControlRootDesigner allows these two control types to be added to aMarqueeControl in any combination.

Common features of the two controls are factored into an interface called IMarqueeWidget. Thisallows the MarqueeControl to discover any Marquee-related child controls and give them specialtreatment.

To implement the periodic animation feature, you will use BackgroundWorker objects from theSystem.ComponentModel namespace. You could use Timer objects, but when manyIMarqueeWidget objects are present, the single UI thread may be unable to keep up with theanimation.

To create a child control for your custom control

Add a new class item to the MarqueeControlLibrary project. Give the new source file a basename of "IMarqueeWidget."

1.

Open the IMarqueeWidget source file in the Code Editor and change the declaration fromclass to interface:

2.

Add the following code to the IMarqueeWidget interface to expose two methods and aproperty that manipulate the marquee animation:

3.

// This interface defines the contract for any class that is to// be used in constructing a MarqueeControl.public interface IMarqueeWidget{

// This interface defines the contract for any class that is to// be used in constructing a MarqueeControl.public interface IMarqueeWidget{

// This method starts the animation. If the control can// contain other classes that implement IMarqueeWidget as// children, the control should call StartMarquee on all// its IMarqueeWidget child controls.void StartMarquee();

// This method stops the animation. If the control can// contain other classes that implement IMarqueeWidget as// children, the control should call StopMarquee on all// its IMarqueeWidget child controls.void StopMarquee();

// This method specifies the refresh rate for the animation,

C#

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

8 of 36 5/25/2012 11:39 AM

Page 9: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Add a new Custom Control item to the MarqueeControlLibrary project. Give the newsource file a base name of "MarqueeText."

4.

Drag a BackgroundWorker component from the Toolbox onto your MarqueeText control. Thiscomponent will allow the MarqueeText control to update itself asynchronously.

5.

In the Properties window, set the BackgroundWorker component's WorkerReportsProgessand WorkerSupportsCancellation properties to true. These settings allow theBackgroundWorker component to periodically raise the ProgressChanged event and to cancelasynchronous updates. For more information, see BackgroundWorker Component.

6.

Open the MarqueeText source file in the Code Editor. At the top of the file, import thefollowing namespaces:

7.

Change the declaration of MarqueeText to inherit from Label and to implement theIMarqueeWidget interface:

8.

Declare the instance variables that correspond to the exposed properties, and initialize them inthe constructor. The isLit field determines if the text is to be painted in the color given bythe LightColor property.

9.

// in milliseconds.int UpdatePeriod

{get;set;

}}

using System;using System.ComponentModel;using System.ComponentModel.Design;using System.Diagnostics;using System.Drawing;using System.Threading;using System.Windows.Forms;using System.Windows.Forms.Design;

[ToolboxItemFilter("MarqueeControlLibrary.MarqueeText", ToolboxItemFilterType.Require)]public partial class MarqueeText : Label, IMarqueeWidget{

C#

C#

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

9 of 36 5/25/2012 11:39 AM

Page 10: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Implement the IMarqueeWidget interface.

The StartMarquee and StopMarquee methods invoke the BackgroundWorker component'sRunWorkerAsync and CancelAsync methods to start and stop the animation.

The Category and Browsable attributes are applied to the UpdatePeriod property so itappears in a custom section of the Properties window called "Marquee."

10.

// When isLit is true, the text is painted in the light color;// When isLit is false, the text is painted in the dark color.// This value changes whenever the BackgroundWorker component// raises the ProgressChanged event.private bool isLit = true;

// These fields back the public properties.private int updatePeriodValue = 50;private Color lightColorValue;private Color darkColorValue;

// These brushes are used to paint the light and dark// colors of the text.private Brush lightBrush;private Brush darkBrush;

// This component updates the control asynchronously.private BackgroundWorker backgroundWorker1;

public MarqueeText(){

// This call is required by the Windows.Forms Form Designer. InitializeComponent();

// Initialize light and dark colors// to the control's default values.this.lightColorValue = this.ForeColor;this.darkColorValue = this.BackColor;this.lightBrush = new SolidBrush(this.lightColorValue);this.darkBrush = new SolidBrush(this.darkColorValue);

}

public virtual void StartMarquee(){

// Start the updating thread and pass it the UpdatePeriod.this.backgroundWorker1.RunWorkerAsync(this.UpdatePeriod);

}

public virtual void StopMarquee(){

// Stop the updating thread.this.backgroundWorker1.CancelAsync();

}

[Category("Marquee")]

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

10 of 36 5/25/2012 11:39 AM

Page 11: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Implement the property accessors. You will expose two properties to clients: LightColor andDarkColor. The Category and Browsable attributes are applied to these properties, so theproperties appear in a custom section of the Properties window called "Marquee."

11.

[Browsable(true)]public int UpdatePeriod{

get {

return this.updatePeriodValue; }

set {

if (value > 0) {

this.updatePeriodValue = value; }

else {

throw new ArgumentOutOfRangeException("UpdatePeriod", "must be > 0"); } }}

[Category("Marquee")][Browsable(true)]public Color LightColor{

get {

return this.lightColorValue; }

set {

// The LightColor property is only changed if the// client provides a different value. Comparing values// from the ToArgb method is the recommended test for// equality between Color structs.if (this.lightColorValue.ToArgb() != value.ToArgb())

{this.lightColorValue = value;this.lightBrush = new SolidBrush(value);

} }}

[Category("Marquee")][Browsable(true)]public Color DarkColor{

get

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

11 of 36 5/25/2012 11:39 AM

Page 12: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Implement the handlers for the BackgroundWorker component's DoWork andProgressChanged events.

The DoWork event handler sleeps for the number of milliseconds specified by UpdatePeriod

then raises the ProgressChanged event, until your code stops the animation by callingCancelAsync.

The ProgressChanged event handler toggles the text between its light and dark state to givethe appearance of flashing.

12.

{return this.darkColorValue;

}set

{// The DarkColor property is only changed if the// client provides a different value. Comparing values// from the ToArgb method is the recommended test for// equality between Color structs.if (this.darkColorValue.ToArgb() != value.ToArgb())

{this.darkColorValue = value;this.darkBrush = new SolidBrush(value);

} }}

// This method is called in the worker thread's context,// so it must not make any calls into the MarqueeText control.// Instead, it communicates to the control using the// ProgressChanged event.//// The only work done in this event handler is// to sleep for the number of milliseconds specified// by UpdatePeriod, then raise the ProgressChanged event.private void backgroundWorker1_DoWork(

object sender, System.ComponentModel.DoWorkEventArgs e) { BackgroundWorker worker = sender as BackgroundWorker;

// This event handler will run until the client cancels// the background task by calling CancelAsync.while (!worker.CancellationPending)

{// The Argument property of the DoWorkEventArgs// object holds the value of UpdatePeriod, which// was passed as the argument to the RunWorkerAsync// method.

Thread.Sleep((int)e.Argument);

// The DoWork eventhandler does not actually report// progress; the ReportProgress event is used to

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

12 of 36 5/25/2012 11:39 AM

Page 13: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Create the MarqueeBorder Child Control

Override the OnPaint method to enable the animation.13.

Press F6 to build the solution.14.

The MarqueeBorder control is slightly more sophisticated than the MarqueeText control. It hasmore properties and the animation in the OnPaint method is more involved. In principle, it is quitesimilar to the MarqueeText control.

Because the MarqueeBorder control can have child controls, it needs to be aware of Layout events.

To create the MarqueeBorder control

Add a new Custom Control item to the MarqueeControlLibrary project. Give the newsource file a base name of "MarqueeBorder."

1.

Drag a BackgroundWorker component from the Toolbox onto your MarqueeBorder control.This component will allow the MarqueeBorder control to update itself asynchronously.

2.

In the Properties window, set the BackgroundWorker component's WorkerReportsProgessand WorkerSupportsCancellation properties to true. These settings allow theBackgroundWorker component to periodically raise the ProgressChanged event and to cancel

3.

// periodically alert the control to update its state. worker.ReportProgress(0); } }

// The ProgressChanged event is raised by the DoWork method.// This event handler does work that is internal to the// control. In this case, the text is toggled between its// light and dark state, and the control is told to// repaint itself.private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChange

{this.isLit = !this.isLit;this.Refresh();

}

protected override void OnPaint(PaintEventArgs e){

// The text is painted in the light or dark color,// depending on the current value of isLit.this.ForeColor =

this.isLit ? this.lightColorValue : this.darkColorValue;

base.OnPaint(e);}

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

13 of 36 5/25/2012 11:39 AM

Page 14: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

asynchronous updates. For more information, see BackgroundWorker Component.

In the Properties window, click the Events button. Attach handlers for the DoWork andProgressChanged events.

4.

Open the MarqueeBorder source file in the Code Editor. At the top of the file, import thefollowing namespaces:

5.

Change the declaration of MarqueeBorder to inherit from Panel and to implement theIMarqueeWidget interface.

6.

Declare two enumerations for managing the MarqueeBorder control's state:MarqueeSpinDirection, which determines the direction in which the lights "spin" around theborder, and MarqueeLightShape, which determines the shape of the lights (square orcircular). Place these declarations before the MarqueeBorder class declaration.

7.

using System;using System.ComponentModel;using System.ComponentModel.Design;using System.Diagnostics;using System.Drawing;using System.Drawing.Design;using System.Threading;using System.Windows.Forms;using System.Windows.Forms.Design;

[Designer(typeof(MarqueeControlLibrary.Design.MarqueeBorderDesigner ))][ToolboxItemFilter("MarqueeControlLibrary.MarqueeBorder", ToolboxItemFilterType.Require)]public partial class MarqueeBorder : Panel, IMarqueeWidget{

// This defines the possible values for the MarqueeBorder// control's SpinDirection property.public enum MarqueeSpinDirection{ CW, CCW}

// This defines the possible values for the MarqueeBorder// control's LightShape property.public enum MarqueeLightShape{ Square,

C#

C#

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

14 of 36 5/25/2012 11:39 AM

Page 15: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Declare the instance variables that correspond to the exposed properties, and initialize them inthe constructor.

8.

Circle}

public static int MaxLightSize = 10;

// These fields back the public properties.private int updatePeriodValue = 50;private int lightSizeValue = 5;private int lightPeriodValue = 3;private int lightSpacingValue = 1;private Color lightColorValue;private Color darkColorValue;private MarqueeSpinDirection spinDirectionValue = MarqueeSpinDirection.CW;private MarqueeLightShape lightShapeValue = MarqueeLightShape.Square;

// These brushes are used to paint the light and dark// colors of the marquee lights.private Brush lightBrush;private Brush darkBrush;

// This field tracks the progress of the "first" light as it// "travels" around the marquee border.private int currentOffset = 0;

// This component updates the control asynchronously.private System.ComponentModel.BackgroundWorker backgroundWorker1;

public MarqueeBorder(){

// This call is required by the Windows.Forms Form Designer. InitializeComponent();

// Initialize light and dark colors// to the control's default values.this.lightColorValue = this.ForeColor;this.darkColorValue = this.BackColor;this.lightBrush = new SolidBrush(this.lightColorValue);this.darkBrush = new SolidBrush(this.darkColorValue);

// The MarqueeBorder control manages its own padding,// because it requires that any contained controls do// not overlap any of the marquee lights.int pad = 2 * (this.lightSizeValue + this.lightSpacingValue);this.Padding = new Padding(pad, pad, pad, pad);

SetStyle(ControlStyles.OptimizedDoubleBuffer, true);}

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

15 of 36 5/25/2012 11:39 AM

Page 16: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Implement the IMarqueeWidget interface.

The StartMarquee and StopMarquee methods invoke the BackgroundWorker component'sRunWorkerAsync and CancelAsync methods to start and stop the animation.

Because the MarqueeBorder control can contain child controls, the StartMarquee methodenumerates all child controls and calls StartMarquee on those that implementIMarqueeWidget. The StopMarquee method has a similar implementation.

9.

public virtual void StartMarquee() {

// The MarqueeBorder control may contain any number of// controls that implement IMarqueeWidget, so find// each IMarqueeWidget child and call its StartMarquee// method.foreach (Control cntrl in this.Controls)

{if (cntrl is IMarqueeWidget)

{ IMarqueeWidget widget = cntrl as IMarqueeWidget; widget.StartMarquee(); } }

// Start the updating thread and pass it the UpdatePeriod.this.backgroundWorker1.RunWorkerAsync(this.UpdatePeriod);

}

public virtual void StopMarquee() {

// The MarqueeBorder control may contain any number of// controls that implement IMarqueeWidget, so find// each IMarqueeWidget child and call its StopMarquee// method.foreach (Control cntrl in this.Controls)

{if (cntrl is IMarqueeWidget)

{ IMarqueeWidget widget = cntrl as IMarqueeWidget; widget.StopMarquee(); } }

// Stop the updating thread.this.backgroundWorker1.CancelAsync();

}

[Category("Marquee")] [Browsable(true)]

public virtual int UpdatePeriod {

get {

return this.updatePeriodValue; }

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

16 of 36 5/25/2012 11:39 AM

Page 17: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Implement the property accessors. The MarqueeBorder control has several properties forcontrolling its appearance.

10.

set {

if (value > 0) {

this.updatePeriodValue = value; }

else {

throw new ArgumentOutOfRangeException("UpdatePeriod", "must be > 0" } } }

[Category("Marquee")] [Browsable(true)]

public int LightSize {

get {

return this.lightSizeValue; }

set {

if (value > 0 && value <= MaxLightSize) {

this.lightSizeValue = value;this.DockPadding.All = 2 * value;

}else

{throw new ArgumentOutOfRangeException("LightSize", "must be > 0 and < MaxLightSize"

} } }

[Category("Marquee")] [Browsable(true)]

public int LightPeriod {

get {

return this.lightPeriodValue; }

set {

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

17 of 36 5/25/2012 11:39 AM

Page 18: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

if (value > 0) {

this.lightPeriodValue = value; }

else {

throw new ArgumentOutOfRangeException("LightPeriod", "must be > 0 " } } }

[Category("Marquee")] [Browsable(true)]

public Color LightColor {

get {

return this.lightColorValue; }

set {

// The LightColor property is only changed if the// client provides a different value. Comparing values// from the ToArgb method is the recommended test for// equality between Color structs.if (this.lightColorValue.ToArgb() != value.ToArgb())

{this.lightColorValue = value;this.lightBrush = new SolidBrush(value);

} } }

[Category("Marquee")] [Browsable(true)]

public Color DarkColor {

get {

return this.darkColorValue; }

set {

// The DarkColor property is only changed if the// client provides a different value. Comparing values// from the ToArgb method is the recommended test for// equality between Color structs.if (this.darkColorValue.ToArgb() != value.ToArgb())

{this.darkColorValue = value;this.darkBrush = new SolidBrush(value);

} } }

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

18 of 36 5/25/2012 11:39 AM

Page 19: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

[Category("Marquee")] [Browsable(true)]

public int LightSpacing {

get {

return this.lightSpacingValue; }

set {

if (value >= 0) {

this.lightSpacingValue = value; }

else {

throw new ArgumentOutOfRangeException("LightSpacing", "must be >= 0" } } }

[Category("Marquee")] [Browsable(true)] [EditorAttribute(typeof(LightShapeEditor),

typeof(System.Drawing.Design.UITypeEditor))]public MarqueeLightShape LightShape

{get

{return this.lightShapeValue;

}

set {

this.lightShapeValue = value; } }

[Category("Marquee")] [Browsable(true)]

public MarqueeSpinDirection SpinDirection {

get {

return this.spinDirectionValue; }

set {

this.spinDirectionValue = value; } }

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

19 of 36 5/25/2012 11:39 AM

Page 20: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Implement the handlers for the BackgroundWorker component's DoWork andProgressChanged events.

The DoWork event handler sleeps for the number of milliseconds specified by UpdatePeriod

then raises the ProgressChanged event, until your code stops the animation by callingCancelAsync.

The ProgressChanged event handler increments the position of the "base" light, from whichthe light/dark state of the other lights is determined, and calls the Refresh method to causethe control to repaint itself.

11.

Implement the helper methods, IsLit and DrawLight.12.

// This method is called in the worker thread's context,// so it must not make any calls into the MarqueeBorder// control. Instead, it communicates to the control using// the ProgressChanged event.//// The only work done in this event handler is// to sleep for the number of milliseconds specified// by UpdatePeriod, then raise the ProgressChanged event.private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e){ BackgroundWorker worker = sender as BackgroundWorker;

// This event handler will run until the client cancels// the background task by calling CancelAsync.while (!worker.CancellationPending)

{// The Argument property of the DoWorkEventArgs// object holds the value of UpdatePeriod, which// was passed as the argument to the RunWorkerAsync// method.

Thread.Sleep((int)e.Argument);

// The DoWork eventhandler does not actually report// progress; the ReportProgress event is used to// periodically alert the control to update its state.

worker.ReportProgress(0); }}

// The ProgressChanged event is raised by the DoWork method.// This event handler does work that is internal to the// control. In this case, the currentOffset is incremented,// and the control is told to repaint itself.private void backgroundWorker1_ProgressChanged(

object sender, System.ComponentModel.ProgressChangedEventArgs e){

this.currentOffset++;this.Refresh();

}

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

20 of 36 5/25/2012 11:39 AM

Page 21: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

The IsLit method determines the color of a light at a given position. Lights that are "lit" aredrawn in the color given by the LightColor property, and those that are "dark" are drawn inthe color given by the DarkColor property.

The DrawLight method draws a light using the appropriate color, shape, and position.

Override the OnLayout and OnPaint methods.

The OnPaint method draws the lights along the edges of the MarqueeBorder control.

13.

// This method determines if the marquee light at lightIndex// should be lit. The currentOffset field specifies where// the "first" light is located, and the "position" of the// light given by lightIndex is computed relative to this// offset. If this position modulo lightPeriodValue is zero,// the light is considered to be on, and it will be painted// with the control's lightBrush.protected virtual bool IsLit(int lightIndex){

int directionFactor = (this.spinDirectionValue == MarqueeSpinDirection.CW ? -1 : 1);

return ( (lightIndex + directionFactor * this.currentOffset) % this.lightPeriodValue == 0 );}

protected virtual void DrawLight( Graphics g, Brush brush,

int xPos,int yPos)

{switch (this.lightShapeValue)

{case MarqueeLightShape.Square:

{ g.FillRectangle(brush, xPos, yPos, this.lightSizeValue, this.lightSizeValue);

break; }

case MarqueeLightShape.Circle: { g.FillEllipse(brush, xPos, yPos, this.lightSizeValue, this.lightSizeValue);

break; }

default: { Trace.Assert(false, "Unknown value for light shape.");

break; } }}

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

21 of 36 5/25/2012 11:39 AM

Page 22: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Because the OnPaint method depends on the dimensions of the MarqueeBorder control, youneed to call it whenever the layout changes. To achieve this, override OnLayout and callRefresh.

protected override void OnLayout(LayoutEventArgs levent){

base.OnLayout(levent);

// Repaint when the layout has changed.this.Refresh();

}

// This method paints the lights around the border of the// control. It paints the top row first, followed by the// right side, the bottom row, and the left side. The color// of each light is determined by the IsLit method and// depends on the light's position relative to the value// of currentOffset.protected override void OnPaint(PaintEventArgs e){ Graphics g = e.Graphics; g.Clear(this.BackColor);

base.OnPaint(e);

// If the control is large enough, draw some lights.if (this.Width > MaxLightSize &&

this.Height > MaxLightSize) {

// The position of the next light will be incremented// by this value, which is equal to the sum of the// light size and the space between two lights.int increment =

this.lightSizeValue + this.lightSpacingValue;

// Compute the number of lights to be drawn along the// horizontal edges of the control.int horizontalLights =

(this.Width - increment) / increment;

// Compute the number of lights to be drawn along the// vertical edges of the control.int verticalLights =

(this.Height - increment) / increment;

// These local variables will be used to position and// paint each light.int xPos = 0;int yPos = 0;int lightCounter = 0;

Brush brush;

// Draw the top row of lights.for (int i = 0; i < horizontalLights; i++)

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

22 of 36 5/25/2012 11:39 AM

Page 23: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Creating a Custom Designer to Shadow and Filter Properties

{ brush = IsLit(lightCounter) ? this.lightBrush : this.darkBrush;

DrawLight(g, brush, xPos, yPos);

xPos += increment; lightCounter++; }

// Draw the lights flush with the right edge of the control. xPos = this.Width - this.lightSizeValue;

// Draw the right column of lights.for (int i = 0; i < verticalLights; i++)

{ brush = IsLit(lightCounter) ? this.lightBrush : this.darkBrush;

DrawLight(g, brush, xPos, yPos);

yPos += increment; lightCounter++; }

// Draw the lights flush with the bottom edge of the control. yPos = this.Height - this.lightSizeValue;

// Draw the bottom row of lights.for (int i = 0; i < horizontalLights; i++)

{ brush = IsLit(lightCounter) ? this.lightBrush : this.darkBrush;

DrawLight(g, brush, xPos, yPos);

xPos -= increment; lightCounter++; }

// Draw the lights flush with the left edge of the control. xPos = 0;

// Draw the left column of lights.for (int i = 0; i < verticalLights; i++)

{ brush = IsLit(lightCounter) ? this.lightBrush : this.darkBrush;

DrawLight(g, brush, xPos, yPos);

yPos -= increment; lightCounter++; } }}

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

23 of 36 5/25/2012 11:39 AM

Page 24: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

The MarqueeControlRootDesigner class provides the implementation for the root designer. Inaddition to this designer, which operates on the MarqueeControl, you will need a custom designerthat is specifically associated with the MarqueeBorder control. This designer provides custombehavior that is appropriate in the context of the custom root designer.

Specifically, the MarqueeBorderDesigner will "shadow" and filter certain properties on theMarqueeBorder control, changing their interaction with the design environment.

Intercepting calls to a component's property accessor is known as "shadowing." It allows a designerto track the value set by the user and optionally pass that value to the component being designed.

For this example, the Visible and Enabled properties will be shadowed by theMarqueeBorderDesigner, which prevents the user from making the MarqueeBorder controlinvisible or disabled during design time.

Designers can also add and remove properties. For this example, the Padding property will beremoved at design time, because the MarqueeBorder control programmatically sets the paddingbased on the size of the lights specified by the LightSize property.

The base class for MarqueeBorderDesigner is ComponentDesigner, which has methods that canchange the attributes, properties, and events exposed by a control at design time:

PreFilterProperties

PostFilterProperties

PreFilterAttributes

PostFilterAttributes

PreFilterEvents

PostFilterEvents

When changing the public interface of a component using these methods, you must follow theserules:

Add or remove items in the PreFilter methods only

Modify existing items in the PostFilter methods only

Always call the base implementation first in the PreFilter methods

Always call the base implementation last in the PostFilter methods

Adhering to these rules ensures that all designers in the design-time environment have a consistentview of all components being designed.

The ComponentDesigner class provides a dictionary for managing the values of shadowedproperties, which relieves you of the need to create specific instance variables.

To create a custom designer to shadow and filter properties

Right-click the Design folder and add a new class. Give the source file a base name of"MarqueeBorderDesigner."

1.

Open the MarqueeBorderDesigner source file in the Code Editor. At the top of the file,import the following namespaces:

2.

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

24 of 36 5/25/2012 11:39 AM

Page 25: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Change the declaration of MarqueeBorderDesigner to inherit from ParentControlDesigner.

Because the MarqueeBorder control can contain child controls, MarqueeBorderDesignerinherits from ParentControlDesigner, which handles the parent-child interaction.

3.

Override the base implementation of PreFilterProperties.4.

Implement the Enabled and Visible properties. These implementations shadow the control'sproperties.

5.

using System;using System.Collections;using System.ComponentModel;using System.ComponentModel.Design;using System.Diagnostics;using System.Windows.Forms;using System.Windows.Forms.Design;

namespace MarqueeControlLibrary.Design{ [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name =

public class MarqueeBorderDesigner : ParentControlDesigner {

protected override void PreFilterProperties(IDictionary properties){

base.PreFilterProperties(properties);

if (properties.Contains("Padding")) { properties.Remove("Padding"); }

properties["Visible"] = TypeDescriptor.CreateProperty(typeof(MarqueeBorderDesigner),

(PropertyDescriptor)properties["Visible"],new Attribute[0]);

properties["Enabled"] = TypeDescriptor.CreateProperty(typeof(MarqueeBorderDesigner),

(PropertyDescriptor)properties["Enabled"],new Attribute[0]);

}

C#

C#

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

25 of 36 5/25/2012 11:39 AM

Page 26: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Handling Component ChangesThe MarqueeControlRootDesigner class provides the custom design-time experience for yourMarqueeControl instances. Most of the design-time functionality is inherited from theDocumentDesigner class; your code will implement two specific customizations: handling componentchanges, and adding designer verbs.

As users design their MarqueeControl instances, your root designer will track changes to theMarqueeControl and its child controls. The design-time environment offers a convenient service,IComponentChangeService, for tracking changes to component state.

You acquire a reference to this service by querying the environment with the GetService method. Ifthe query is successful, your designer can attach a handler for the ComponentChanged event andperform whatever tasks are required to maintain a consistent state at design time.

In the case of the MarqueeControlRootDesigner class, you will call the Refresh method on eachIMarqueeWidget object contained by the MarqueeControl. This will cause the IMarqueeWidget

object to repaint itself appropriately when properties like its parent's Size are changed.

To handle component changes

Open the MarqueeControlRootDesigner source file in the Code Editor and override theInitialize method. Call the base implementation of Initialize and query for theIComponentChangeService.

1.

public bool Visible{

get {

return (bool)ShadowProperties["Visible"]; }

set {

this.ShadowProperties["Visible"] = value; }}

public bool Enabled{

get {

return (bool)ShadowProperties["Enabled"]; }

set {

this.ShadowProperties["Enabled"] = value; }}

base.Initialize(component);

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

26 of 36 5/25/2012 11:39 AM

Page 27: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Adding Designer Verbs to your Custom Designer

Implement the OnComponentChanged event handler. Test the sending component's type, andif it is an IMarqueeWidget, call its Refresh method.

2.

A designer verb is a menu command linked to an event handler. Designer verbs are added to acomponent's shortcut menu at design time. For more information, see DesignerVerb.

You will add two designer verbs to your designers: Run Test and Stop Test. These verbs will allowyou to view the run-time behavior of the MarqueeControl at design time. These verbs will be addedto the MarqueeControlRootDesigner.

When Run Test is invoked, the verb event handler will call the StartMarquee method on theMarqueeControl. When Stop Test is invoked, the verb event handler will call the StopMarquee

method on the MarqueeControl. The implementation of the StartMarquee and StopMarquee

methods call these methods on contained controls that implement IMarqueeWidget, so anycontained IMarqueeWidget controls will also participate in the test.

To add designer verbs to your custom designers

In the MarqueeControlRootDesigner class, add event handlers named OnVerbRunTest andOnVerbStopTest.

1.

IComponentChangeService cs = GetService(typeof(IComponentChangeService))

as IComponentChangeService;

if (cs != null){ cs.ComponentChanged +=

new ComponentChangedEventHandler(OnComponentChanged);}

private void OnComponentChanged(object sender,

ComponentChangedEventArgs e){

if (e.Component is IMarqueeWidget) {

this.Control.Refresh(); }}

private void OnVerbRunTest(object sender, EventArgs e){ MarqueeControl c = this.Control as MarqueeControl;

C#

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

27 of 36 5/25/2012 11:39 AM

Page 28: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Creating a Custom UITypeEditor

Connect these event handlers to their corresponding designer verbs.MarqueeControlRootDesigner inherits a DesignerVerbCollection from its base class. You willcreate two new DesignerVerb objects and add them to this collection in the Initialize method.

2.

When you create a custom design-time experience for users, it is often desirable to create a custominteraction with the Properties window. You can accomplish this by creating a UITypeEditor. Formore information, see How to: Create a UI Type Editor.

The MarqueeBorder control exposes several properties in the Properties window. Two of theseproperties, MarqueeSpinDirection and MarqueeLightShape are represented by enumerations. Toillustrate the use of a UI type editor, the MarqueeLightShape property will have an associatedUITypeEditor class.

To create a custom UI type editor

Open the MarqueeBorder source file in the Code Editor.1.

In the definition of the MarqueeBorder class, declare a class called LightShapeEditor thatderives from UITypeEditor.

2.

c.Start();}

private void OnVerbStopTest(object sender, EventArgs e){ MarqueeControl c = this.Control as MarqueeControl;

c.Stop();}

this.Verbs.Add(new DesignerVerb("Run Test",new EventHandler(OnVerbRunTest))

);

this.Verbs.Add(new DesignerVerb("Stop Test",new EventHandler(OnVerbStopTest))

);

// This class demonstrates the use of a custom UITypeEditor.// It allows the MarqueeBorder control's LightShape property// to be changed at design time using a customized UI element// that is invoked by the Properties window. The UI is provided// by the LightShapeSelectionControl class.

C#

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

28 of 36 5/25/2012 11:39 AM

Page 29: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Declare an IWindowsFormsEditorService instance variable called editorService.3.

Override the GetEditStyle method. This implementation returns DropDown, which tells thedesign environment how to display the LightShapeEditor.

4.

Override the EditValue method. This implementation queries the design environment for anIWindowsFormsEditorService object. If successful, it creates aLightShapeSelectionControl. The DropDownControl method is invoked to start theLightShapeEditor. The return value from this invocation is returned to the designenvironment.

5.

internal class LightShapeEditor : UITypeEditor{

private IWindowsFormsEditorService editorService = null;

public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context){

return UITypeEditorEditStyle.DropDown;}

public override object EditValue( ITypeDescriptorContext context, IServiceProvider provider,

object value){

if (provider != null) { editorService = provider.GetService(

typeof(IWindowsFormsEditorService))as IWindowsFormsEditorService;

}

if (editorService != null) { LightShapeSelectionControl selectionControl =

new LightShapeSelectionControl( (MarqueeLightShape)value, editorService);

C#

C#

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

29 of 36 5/25/2012 11:39 AM

Page 30: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Creating a View Control for your Custom UITypeEditorThe MarqueeLightShape property supports two types of light shapes: Square and Circle.You will create a custom control used solely for the purpose of graphically displaying thesevalues in the Properties window. This custom control will be used by your UITypeEditor tointeract with the Properties window.

1.

To create a view control for your custom UI type editor

Add a new UserControl item to the MarqueeControlLibrary project. Give the new source filea base name of "LightShapeSelectionControl."

1.

Drag two Panel controls from the Toolbox onto the LightShapeSelectionControl. Namethem squarePanel and circlePanel. Arrange them side by side. Set the Size property ofboth Panel controls to (60, 60). Set the Location property of the squarePanel control to (8,10). Set the Location property of the circlePanel control to (80, 10). Finally, set the Sizeproperty of the LightShapeSelectionControl to (150, 80).

2.

Open the LightShapeSelectionControl source file in the Code Editor. At the top of thefile, import the System.Windows.Forms.Design namespace:

3.

Implement Click event handlers for the squarePanel and circlePanel controls. Thesemethods invoke CloseDropDown to end the custom UITypeEditor editing session.

1.

editorService.DropDownControl(selectionControl);

value = selectionControl.LightShape; }

return value;}

using System.Windows.Forms.Design;

private void squarePanel_Click(object sender, EventArgs e){

this.lightShapeValue = MarqueeLightShape.Square;

this.Invalidate( false );

this.editorService.CloseDropDown();}

private void circlePanel_Click(object sender, EventArgs e){

this.lightShapeValue = MarqueeLightShape.Circle;

this.Invalidate( false );

C#

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

30 of 36 5/25/2012 11:39 AM

Page 31: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Declare an IWindowsFormsEditorService instance variable called editorService.2.

Declare a MarqueeLightShape instance variable called lightShapeValue.1.

In the LightShapeSelectionControl constructor, attach the Click event handlers to thesquarePanel and circlePanel controls' Click events. Also, define a constructor overload thatassigns the MarqueeLightShape value from the design environment to the lightShapeValue

field.

2.

In the Dispose method, detach the Click event handlers.3.

this.editorService.CloseDropDown();}

private IWindowsFormsEditorService editorService;

private MarqueeLightShape lightShapeValue = MarqueeLightShape.Square;

// This constructor takes a MarqueeLightShape value from the// design-time environment, which will be used to display// the initial state.

public LightShapeSelectionControl( MarqueeLightShape lightShape, IWindowsFormsEditorService editorService )

{// This call is required by the designer.InitializeComponent();

// Cache the light shape value provided by the// design-time environment.

this.lightShapeValue = lightShape;

// Cache the reference to the editor service.this.editorService = editorService;

// Handle the Click event for the two panels.this.squarePanel.Click += new EventHandler(squarePanel_Click);this.circlePanel.Click += new EventHandler(circlePanel_Click);

}

C#

C#

C#

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

31 of 36 5/25/2012 11:39 AM

Page 32: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

In Solution Explorer, click the Show All Files button. Open theLightShapeSelectionControl.Designer.cs or LightShapeSelectionControl.Designer.vb file, andremove the default definition of the Dispose method.

4.

Implement the LightShape property.5.

Override the OnPaint method. This implementation will draw a filled square and circle. It willalso highlight the selected value by drawing a border around one shape or the other.

6.

protected override void Dispose( bool disposing ){

if( disposing ){

// Be sure to unhook event handlers// to prevent "lapsed listener" leaks.

this.squarePanel.Click -=new EventHandler(squarePanel_Click);

this.circlePanel.Click -=new EventHandler(circlePanel_Click);

if(components != null){

components.Dispose();}

}base.Dispose( disposing );

}

// LightShape is the property for which this control provides// a custom user interface in the Properties window.

public MarqueeLightShape LightShape{

get{

return this.lightShapeValue;}

set{

if( this.lightShapeValue != value ){

this.lightShapeValue = value;}

}}

protected override void OnPaint(PaintEventArgs e)

C#

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

32 of 36 5/25/2012 11:39 AM

Page 33: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

{base.OnPaint (e);

using(Graphics gSquare = this.squarePanel.CreateGraphics(),gCircle = this.circlePanel.CreateGraphics() )

{// Draw a filled square in the client area of// the squarePanel control.

gSquare.FillRectangle( Brushes.Red, 0, 0,

this.squarePanel.Width,this.squarePanel.Height

);

// If the Square option has been selected, draw a// border inside the squarePanel.

if( this.lightShapeValue == MarqueeLightShape.Square ){

gSquare.DrawRectangle(Pens.Black,0,0,this.squarePanel.Width-1,this.squarePanel.Height-1);

}

// Draw a filled circle in the client area of// the circlePanel control.

gCircle.Clear( this.circlePanel.BackColor );gCircle.FillEllipse(

Brushes.Blue, 0, 0,

this.circlePanel.Width,this.circlePanel.Height

);

// If the Circle option has been selected, draw a// border inside the circlePanel.

if( this.lightShapeValue == MarqueeLightShape.Circle ){

gCircle.DrawRectangle(Pens.Black,0,0,this.circlePanel.Width-1,this.circlePanel.Height-1);

}}

}

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

33 of 36 5/25/2012 11:39 AM

Page 34: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

Testing your Custom Control in the Designer

Next Steps

At this point, you can build the MarqueeControlLibrary project. Test your implementation bycreating a control that inherits from the MarqueeControl class and using it on a form.

To create a custom MarqueeControl implementation

Open DemoMarqueeControl in the Windows Forms Designer. This creates an instance of theDemoMarqueeControl type and displays it in an instance of theMarqueeControlRootDesigner type.

1.

In the Toolbox, open the MarqueeControlLibrary Components tab. You will see theMarqueeBorder and MarqueeText controls available for selection.

2.

Drag an instance of the MarqueeBorder control onto the DemoMarqueeControl designsurface. Dock this MarqueeBorder control to the parent control.

3.

Drag an instance of the MarqueeText control onto the DemoMarqueeControl design surface.4.

Build the solution.5.

Right-click the DemoMarqueeControl and from the shortcut menu select the Run Test optionto start the animation. Click Stop Test to stop the animation.

6.

Open Form1 in Design view.7.

Place two Button controls on the form. Name them startButton and stopButton, andchange the Text property values to Start and Stop, respectively.

8.

Implement Click event handlers for both Button controls.9.

In the Toolbox, open the MarqueeControlTest Components tab. You will see theDemoMarqueeControl available for selection.

10.

Drag an instance of DemoMarqueeControl onto the Form1 design surface.11.

In the Click event handlers, invoke the Start and Stop methods on theDemoMarqueeControl.

12.

Set the MarqueeControlTest project as the startup project and run it. You will see the formdisplaying your DemoMarqueeControl. Click the Start button to start the animation. Youshould see the text flashing and the lights moving around the border.

1.

The MarqueeControlLibrary demonstrates a simple implementation of custom controls and

private void startButton_Click(object sender, System.EventArgs e){

this.demoMarqueeControl1.Start();}

private void stopButton_Click(object sender, System.EventArgs e){

this.demoMarqueeControl1.Stop();}

C#

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

34 of 36 5/25/2012 11:39 AM

Page 35: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

See Also

Change History

associated designers. You can make this sample more sophisticated in several ways:

Change the property values for the DemoMarqueeControl in the designer. Add moreMarqueBorder controls and dock them within their parent instances to create a nested effect.Experiment with different settings for the UpdatePeriod and the light-related properties.

Author your own implementations of IMarqueeWidget. You could, for example, create aflashing "neon sign" or an animated sign with multiple images.

Further customize the design-time experience. You could try shadowing more properties thanEnabled and Visible, and you could add new properties. Add new designer verbs to simplifycommon tasks like docking child controls.

License the MarqueeControl. For more information, see How to: License Components andControls.

Control how your controls are serialized and how code is generated for them. For moreinformation, see Dynamic Source Code Generation and Compilation.

Tasks

How to: Create a Windows Forms Control That Takes Advantage of Design-Time Features

Reference

UserControlParentControlDesignerDocumentDesignerIRootDesignerDesignerVerbUITypeEditorBackgroundWorker

Other Resources

Extending Design-Time SupportCustom Designers.NET Shape Library: A Sample Designer

Date History Reason

Did you find this helpful? Yes No

July 2010 Added a note about the .NET Framework Client Profile.Customer feedback.

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

35 of 36 5/25/2012 11:39 AM

Page 36: Creating a Windows Forms Control That Takes Advantage of Visual Studio Design-Time Features

8/30/2011Donny101

11/9/2011Thomas Lee

5/23/2010lkjjlasdf

11/9/2011Thomas Lee

9/12/2011MtEvans

11/9/2011Thomas Lee

© 2012 Microsoft. All rights reserved.

Community Content

system.design

at first this stumpped me for about 5 minif you right click on the second from top most item (which will be your first project you will have two) inyour solution explorerand select properties, on the first tab on the left make sure Application is selected and then make sureTarget Framework is set to .NET Framework 4 not.NET Framework 4 client profilesame for 3.5 and etc.. no client profilethen close this tab and do the same for the second project under your solutionthe system.design will be available

now im stuck on another part

Did anyone actually try this?

As a walkthrough, it needs a lot of tweaking. For instance, where is "System.Design"? There is no suchreference in my copy of VS.

A "walkthrough" should be just that. Everything spelled out, no steps missing. A deaf, dumb, and blindperson should be able to follow it.

This one in many places is ambiguous or unclear, and pieces are missing. I am unable to complete it. Awaste of time.

As tutorials go it might have been a bit more

I hate it when someone develops a tutorial only so I can debug it. Locate my control... Tool box doeshave the control

Walkthrough: Creating a Windows Forms Control That Takes Advantage ... http://msdn.microsoft.com/en-us/library/35ea88wb

36 of 36 5/25/2012 11:39 AM