[Home]
[Edit this page]
[Recent Changes]
[Special Pages]
[Help]
CustomControls
Custom Controls. An overview
Once you understand the custom collection you can think about writing a Custom Component.
There are a number of reasons you would want to write a Custom Component like:
System.ComponentModel.Component is the base class for an array of components available to you as a Framework programmer. To clarify: If you were to open a new project and add-->add new item-->
Let's quickly get a holistic view of these three. The Component class will inherit from “System.ComponentModel.Component”. Like I said this is the base class for the other components. You will be able to use this Component both on the web and on the Windows form.
The Custom Control will inherit from “System.Windows.Forms.Control” witch in turn inherits from “System.ComponentModel.Component”. You won’t be able to use the Custom control on the web.
The Web Custom Control will inherit from “System.Web.UI.WebControls.WebControl” witch in turn inherits from “System.ComponentModel.Component” and you won’t be able to use the Web custom control on a Windows form.
Now before you start making up your mind about witch control to use, think. The web custom control is great if you want to go for the web, but like I said no Windows form will work with it and so in reverse with the Custom Control. My advice to anyone attempting to write controls is to have a good planning session and take a layered approach.
By this I mean: Follow the Object Orientation approuch. Microsoft made great effort in following through on OO techniques by separating the business logic from the User interface Code. (Known as Code Behind.) This is in accord to The OO approach of low coupling and High cohesion. Take a look at http://www.cs.colorado.edu/~kena/classes/5828/s99/comments/nathanryan/01-29-1999.html
Code in a logically grouped manor. If for instance your Human class with properties like HairColor, Gender and Language needs a Translator to talk to another Human with a different Language assigned, write the translator code separate from the human class, by creating a translator class. This approach will ensure you only have to fix a bug in one project and replace the dll where it is used in other projects.
You have to remember that you will want to use that logic in another place especially if you working in a multiple protocol environment, and low coupling will lend itself to this.
You can always start at the more General point of inheritance and specialize downwards through inheritance, but if you start at the specialized end you will find yourself falling short when the environment changes and this is the beauty about OO and it’s proficiency for changing environments. All you do is identify the general level in your Inheritance hierarchy and specialize from there and you will retain all functionality from that from that point up.
Plan your work and work your plan.
A basic Custom Control
Now let’s get some basics
The control will only be an interface to your real object(s) This means that you logic will reside in another location and only logic that will validate and modify client input will reside in the component code. This logic will concern only Control related logic. You should keep the logic in the right place. Basic validation resides with the object, extended validation resides in the control or where ever else.
With this I mean to say that the control will inevitably provide you with design-time support on the actual object you want to manipulate. The control itself consists mainly of Properties.
For those of you who don’t know the difference between a field (like name or hairColor of the Human class) and a Property, a Property stores and retrieves it’s value in and from a field by using field assessors (get() and set() methods) and thereby encapsulating logic for storage and retrieval of the field values.
Let’s look at the way Object Orientation intended it to work.
A few notes to clarity.
Now you would ask what is the use? We just added 5 lines of code for a simple operation. This is true in the case, but once you want to add some logic to make sure the name starts with an upper case for instance, where do you add that logic?
Now when you add a Property to a component, keyword-like descriptive declarations, called attributes, needs to be added for the designer to understand.
The destructor is quite simple in deed. The destructor is indicated by the ~ sign followed by the class name.
Let’s say the first name sits in a file, so we going to select a file name rather than type in a name ourselves and let the set() Method handle the rest. To do this we will have to add an attribute to the Property in order to tell the designer that we want a FileNameEditor instead of a simple text box.
First we will have to add
[Edit this page] [Page history] [What links here] [Discuss this topic] [Printer Friendly]
CustomControls
Custom Controls. An overview
Once you understand the custom collection you can think about writing a Custom Component.
There are a number of reasons you would want to write a Custom Component like:
- You’re sick of writing similar constructor code in every page load section of your code behind pages or initialize part of your windows app.
- You want to standardize a piece of logic, making it accessible to more junior programmers on your team.
- You want to minimize cut-and-past errors and save some time in later development.
System.ComponentModel.Component is the base class for an array of components available to you as a Framework programmer. To clarify: If you were to open a new project and add-->add new item-->
- You will find the Component class first.
- A couple of items down you will find the Custom Control witch is a windows control. I.e. you won’t be able to use it on the web.
- A bit further down you will find the Web Custom Control.
Let's quickly get a holistic view of these three. The Component class will inherit from “System.ComponentModel.Component”. Like I said this is the base class for the other components. You will be able to use this Component both on the web and on the Windows form.
The Custom Control will inherit from “System.Windows.Forms.Control” witch in turn inherits from “System.ComponentModel.Component”. You won’t be able to use the Custom control on the web.
The Web Custom Control will inherit from “System.Web.UI.WebControls.WebControl” witch in turn inherits from “System.ComponentModel.Component” and you won’t be able to use the Web custom control on a Windows form.
Now before you start making up your mind about witch control to use, think. The web custom control is great if you want to go for the web, but like I said no Windows form will work with it and so in reverse with the Custom Control. My advice to anyone attempting to write controls is to have a good planning session and take a layered approach.
By this I mean: Follow the Object Orientation approuch. Microsoft made great effort in following through on OO techniques by separating the business logic from the User interface Code. (Known as Code Behind.) This is in accord to The OO approach of low coupling and High cohesion. Take a look at http://www.cs.colorado.edu/~kena/classes/5828/s99/comments/nathanryan/01-29-1999.html
Code in a logically grouped manor. If for instance your Human class with properties like HairColor, Gender and Language needs a Translator to talk to another Human with a different Language assigned, write the translator code separate from the human class, by creating a translator class. This approach will ensure you only have to fix a bug in one project and replace the dll where it is used in other projects.
You have to remember that you will want to use that logic in another place especially if you working in a multiple protocol environment, and low coupling will lend itself to this.
You can always start at the more General point of inheritance and specialize downwards through inheritance, but if you start at the specialized end you will find yourself falling short when the environment changes and this is the beauty about OO and it’s proficiency for changing environments. All you do is identify the general level in your Inheritance hierarchy and specialize from there and you will retain all functionality from that from that point up.
Plan your work and work your plan.
A basic Custom Control
Now let’s get some basics
The control will only be an interface to your real object(s) This means that you logic will reside in another location and only logic that will validate and modify client input will reside in the component code. This logic will concern only Control related logic. You should keep the logic in the right place. Basic validation resides with the object, extended validation resides in the control or where ever else.
With this I mean to say that the control will inevitably provide you with design-time support on the actual object you want to manipulate. The control itself consists mainly of Properties.
For those of you who don’t know the difference between a field (like name or hairColor of the Human class) and a Property, a Property stores and retrieves it’s value in and from a field by using field assessors (get() and set() methods) and thereby encapsulating logic for storage and retrieval of the field values.
Let’s look at the way Object Orientation intended it to work.
//The field declaration.
private string personName;
//The Property declaration
public string PersonName
{
get{return personName;}
set{personName = value;}
}
By doing this we follow the Principal of encapsulation.
http://www-2.cs.cmu.edu/People/clamen/OODBMS/Manifesto/htManifesto/node5.htmlA few notes to clarity.
- The field has a private modifier and you will not be able to access it from anywhere outside the particular class. This is known as Scope. (Private in this case).
- When using the Property the notation will be the same as with a field, the upper case first letter will indicate that you using the property instead of the field.
PersonName = “Brutes”; txtName.Text = PersonName;
Now you would ask what is the use? We just added 5 lines of code for a simple operation. This is true in the case, but once you want to add some logic to make sure the name starts with an upper case for instance, where do you add that logic?
//The field declaration.
private string personName;
//The Property declaration
public string PersonName
{
get{return personName;}
set
{
System.Text.RegularExpressions.Regex regEx =
new System.Text.RegularExpressions.Regex(@"^[A-Z][a-z]+$");
personName = regEx.IsMatch(myName)?myName:Char.ToUpper(myName[0]) +
myName.Substring(1, myName.Length-1);
}
}
Note. This way you do it once and in the right place.Now when you add a Property to a component, keyword-like descriptive declarations, called attributes, needs to be added for the designer to understand.
[Category("Detail"),
Browsable(true),
Description("The Person’s Name"),
DefaultValue("")]
Are but a few. You can consult you MSDN for a list of these. I will explain as we go along.
Make a new project.
In the new project dialog select the Class Library Project
and name it PersonComp.
Delete Class1.cs from the project.
Right-click on the project name in the solution explorer and add a new Item.
Add a Component Class and name it PersonComponent.
View the code for you Component.
You will see that the class inherits from System.ComponentModel.Component.
This is the base-class for all components.
It’s very basic and you will have to write destructor code to free all the resources you used.The destructor is quite simple in deed. The destructor is indicated by the ~ sign followed by the class name.
~ PersonComponent()
{
//this is a custom method where you will set the used resources
//to null
close();
base.Dispose();
}
private void close()
{
if (personName != null)
{
personName = null;
}
}
But what resources did personName take that I have to free you might ask. Nothing is the answer, nothing yet. So let’s add something.Let’s say the first name sits in a file, so we going to select a file name rather than type in a name ourselves and let the set() Method handle the rest. To do this we will have to add an attribute to the Property in order to tell the designer that we want a FileNameEditor instead of a simple text box.
First we will have to add
- System.Windows.Forms.dll
- System.Design.dll
- System.Drawing.dll
private string personName;
//No indicate to the designer that we want a FileNameEditor
[Editor(typeof(System.Windows.Forms.Design.FileNameEditor),
typeof(System.Drawing.Design.UITypeEditor))]
public string PersonName
{
get{return personName;}
set
{
System.IO.FileInfo aTextFile =
new System.IO.FileInfo(value);
System.IO.FileStream fileRead = aTextFile.OpenRead();
System.IO.StreamReader fileStreamReader =
new System.IO.StreamReader(fileRead);
personName = fileStreamReader.ReadLine();
}
}
This is probably still not enough to use a destructor, but it’s definitely safer to set the field to null on dispose than to try and figure out the bizarre behaviors related to memory leaks.To add an icon identifying your component
Add a Bitmap file from the Resource folder in the Add new dialog box.
Name it PersonComponent (Same as the Component).
Change the width and height in the properties window of the Bitmap file
to 16 pixels respectively.
Draw a distinctive design with the colors supplied.
Save the bitmap and close it.
Select it in the Solution Explorer and in the Properties window change
it’s Build Action to Embedded Resource.
Save all your work.
Compile your project.
Now add another Project to your Solution.
Select the Windows Application project from the new project dialog.
Go to Form1.cs Design view.
Go to your Toolbox and select the General tab and right-click and
select Customize Toolbox.
In the Customize Toolbox dialog make sure you select the
.NET Framework Components tab and click browse.
Go to the location to where you compiled the component dll in your
first project and select it.
You should now see your component named PersonComponent in the list
with a check in the checkbox next to it.
Click Ok.
You should now see your component PersonComponent in the Toolbox under
the General Tab.
Double click on it.
Note. Now a bar appears at the bottom in the Design view and
your component appears within.
A couple of things happened now.
- The dll containing your component logic has been added to the current project.
- A Private property has been added to the form class. (Form1 in this case)
- And if you were to view the InitializeComponent()method of the form you will see that a container reference has been sent to the component construct.
- The PersonName property has also been set to null.
In Design mode click on your component and take a look at the properties
window.
Select PersonName.
You see the ellipse button on the right?
Click it and the open file dialog should appear. Neat hey?
Now you will have to create a file that contains the name of your person.
Open Windows explorer and go to your Windows Application disk Location
and create a new text file.
Open it and type your name on the first line.
Save the file and close it. Go back to the IDE.
Select the text file you have created and click open.
You should see your name in the PersonName Field.
If you go back to the form code, specifically to the
InitializeComponent() method you will see that the Components
PersonName property has now been set to your name.
Now if you were to close the form and open it again, you will get
a FileNotFoundException. This is obvious, but I did this for a reason.
Let’s fix it quick with some safety code.
First of all we need to distinguish between Design-time and run-time.
So add a check to the set() method of PersonName for
System.ComponentModel.Component.DesignTime
Then trap the FileNotFoundException in design time.
Here is the code then.
set
{
if (this.DesignMode)
{
try
{
System.IO.FileInfo aTextFile =
new System.IO.FileInfo(value);
System.IO.FileStream fileRead =
aTextFile.OpenRead();
System.IO.StreamReader fileStreamReader =
new System.IO.StreamReader(fileRead);
personName = fileStreamReader.ReadLine();
}
catch(System.IO.FileNotFoundException)
{
personName = value;
}
}
else
{
personName = value;
}
}
Re-compile the Component.
Delete the Component dll in the references of the Windows app and re-add
it as a .NET reference.
Now close and re-open the form again. You shouldn’t get the error now.
To Finish of, drag a textbox onto the form.
Select the form again and Go to its events in the Properties window.
Double click on the Load event and add the following line
textBox1.Text = personComponent1.PersonName;
Don’t forget to set the Windows app as the Start-up Project in the
Solution Explorer by right clicking on it and selecting Set as StartUp Project.
Now run the app.
If you see your name in the textbox, Well done.
You have been successful.
You will of course be able to use this type of control in a
Web Application too.
You do however not have UI capabilities with this control.
It is therefore a non visual type control and will mostly be the
choice for Data access components like The SQLConnection object.
[Edit this page] [Page history] [What links here] [Discuss this topic] [Printer Friendly]
