To create your new component, start Visual Studio .NET and create a new Class Library application called myComponent_vb or myComponent_cs, depending on what language you''''re writing in.
In the myComponent application, you''''re going to write simple methods and properties that are exposed to consumers of the component. You are also going to create a namespace for your component. By default, the namespace name is normally the name of the application. You''''re going to change this to implement your own namespace.
To implement the functionality of your component, type the code in Listing 14.3 in the default Class1 class that''''s added to the Class Library application.
As you''''re entering the code, read the comments for each item to understand how it''''s being used. You''''re going to add methods that return a dataset; two methods that have the same name, but have different in and out parameters, and you''''re going to implement read/write and read-only properties. The functionality you implement here is common to what you would need to do in real-world scenarios.
'''' You are using SQL Server, so you must import the '''' SqlClient namespace Imports System.Data.SqlClient '''' This is your top-level namespace Namespace Sams '''' This is the child namespace for the Sams namespace Namespace Day14 '''' The name of the class, NewClass Public Class NewClass '''' These are private variables to be used when '''' setting and retrieving the Properties Private m_Fname As String Private m_LName As String '''' A function that returns a DataSet to the caller Function GetAuthors(ByVal ConnectionString As String) _ As DataSet Dim cn As SqlConnection = New SqlConnection(ConnectionString) Dim cmd As New SqlCommand("Select * from Authors", cn) Dim adp As New SqlDataAdapter() adp.SelectCommand = cmd Dim ds As DataSet adp.Fill(ds, "Authors") Return ds End Function '''' Generic Math Function with Integer as return value Function DoMath(ByVal num1 As Integer, _ ByVal num2 As Integer) As Integer Return num1 * num2 End Function '''' Generic Math Function with Integer as return value Function DoMath(ByVal num1 As Integer, _ ByVal num2 As Integer, ByVal num3 as Integer) As Integer Return num1 * num2 End Function '''' Read/Write property for FirstName Property FirstName() Get Return m_Fname End Get Set(ByVal Value) m_LName = Value End Set End Property ''''Read/Write property for LastName Property LastName() Get Return m_Fname End Get Set(ByVal Value) m_Fname = Value End Set End Property '''' Read-only property to return the full name ReadOnly Property FullName() Get Return m_Fname & " " & m_LName End Get End Property End Class End Namespace End Namespace
using System; using System.Data; using System.Data.SqlClient; namespace Sams { namespace Day14 { public class NewClass { public NewClass() { } // These are private variables to be used when // setting and retrieving the Properties string m_Fname; string m_Lname; // A function that returns a DataSet to the caller public System.Data.DataSet getCustomers(string ConnectionString) { SqlConnection cn = new SqlConnection (ConnectionString); SqlDataAdapter da = new SqlDataAdapter ("SELECT * from Authors", cn); DataSet ds = new DataSet(); da.Fill(ds, "Authors"); return ds; } // Generic Math Function with Integer as return value public int doMath(int num1, int num2) { return num1 * num2; } // Generic Math Function with Decimal as return value public int doMath(int num1, int num2, int num3) { return num1 * num2 * num3; } // Read/Write property for FirstName public string firstName { get { return m_Fname; } set { m_Fname =value; } } // Read/Write property for LastName public string lastName { get { return m_Lname; } set { m_Lname = value; } } // Return the Fullname value public string FullName { get { return m_Fname + " " + m_Lname; } } } } }
As you''''re writing components, remember that the Class view gives you a bird''''s-eye view of what your classes contain. If you''''re coding in C#, you can use the Class view to add types to your class very easily. Figure 14.2 shows the right-click power of the Class view to add a new property to a C# class file.
After you select New Property from the contextual menu, the Add Property Wizard screen enables you to easily add a type name, data type, return value, and any comments that you would like to with the type, as Figure 14.3 demonstrates. Using the Class view in C# to add types to your classes makes doing so fast and simple.
Now that you''''ve written the code for the class, you need to compile the application into an assembly. But before you do that, you might want to update the AssemblyInfo file in your solution. The AssemblyInfo file contains attributes that describe your component. By specifying the correct data in the attribute, those properties are compiled into the assembly, and they can be viewed by consumers of the assembly.
If you double-click the AssemblyInfo.vb or AssemblyInfo.cs file in your solution, you should see something like Figure 14.4. Figure 14.4 is the AssemblyInfo.vb for a Visual Basic .NET project.
Change the following assembly attributes to the listed values:
AssemblyTitle myComponent
AssemblyDescription My first .NET component
AssemblyProduct Made with Visual Studio .NET
Next, you need to modify the root namespace of the component. If you''''re coding in C#, you don''''t have to worry about it: C# takes the namespace information from the class file itself. In Visual Basic .NET, you must right-click on the project name in the Solution Explorer, and select Properties from the contextual menu to get to the Project Properties dialog.
In the myComponent_vb Property Pages dialog, the root namespace is set to myComponent. Delete this value and leave the Root namespace box blank, as demonstrated in Figure 14.5.
By removing the root namespace property from the project, the namespace defined in your class file can be used by other applications. This makes it easy to create namespaces that span multiple projects.
Because C# takes the namespace name from the class file itself, there''''s still a useful property you can change in the properties for the project. If you''''re coding in C#, right-click the project name in the Solution Explorer and select Properties from the contextual menu. When the MyComponent_cs Property Pages dialog pops up, change the default namespace to Sams (see Figure 14.6). Now, each class file added to your application has the default namespace of Sams.
Now you''''re ready to build the component. If you right-click the project name in the Solution Explorer and select Build from the contextual menu, your component will be compiled into a managed DLL.
The next step is to consume the DLL from a client application.
To consume the DLL you just created from another application, you can simply add another project to your solution. Adding multiple projects to a single solution makes it very easy to debug. You can set breakpoints in any of the projects, and as they''''re hit, the code execution stops. This even works if the components are written in a different language from the consumer of the component.
To test this, right-click the myComponent solution in the Solution Explorer, and select Add, New Project from the contextual menu. When the Add New Project dialog pops up, select a new Windows Forms application, and name it TestConsumer_vb or TestConsumer_cs, depending on the language you''''re writing in. Figure 14.7 demonstrates this. You now have two projects in your solution.
Next, you need to tell the solution that the TestConsumer project is the startup project. That means when you press the F5 key to run the application, the Windows Forms application starts, not the Class Library application.
To do this, you can right-click the TestConsumer project name in either the Solution Explorer or the Class view, and select Set As StartUp Project from the contextual menu, as Figure 14.8 shows.
After you set the startup project, it appears in bold in the Solution Explorer.
To consume the component, you must add a reference to it in the TestConsumer project. To do so, right-click the References node in the Solution Explorer and select Add Reference from the contextual menu. As you learned a few days ago when we discussed namespaces, you can add three types of references to an application:
.NET component
COM component
Project
Because you have a component in your solution, you can click the Projects tab, and you''''ll see the myComponent project in the list. Select the myComponent project, click the Select button, and click the OK button, as Figure 14.9 demonstrates.
Now you can reference the component in the Windows Forms application as you would any other assembly.
To set up your form, do the following:
Drag a TextBox from the Toolbox to the form.
Drag another TextBox control from the Toolbox to the form.
Drag a CommandButton control from the Toolbox to the form, and set its Text property to DoMath and set its Name property to DoMath.
Drag another CommandButton control from the Toolbox to the form, and set its Text property to DoName and set its Name property to DoName.
Drag a DataGrid control from the Toolbox to the form.
Arrange the controls so that they look something like Figure 14.10.
Next, double-click the form to get to the code-behind for Form1.
At the top of the class file, alias your component with the Imports statement in Visual Basic .NET or the using statement in C#. Your code should look like the following:
Imports Sams.Day14 using Sams.Day14;
By adding the component as a reference, it''''s available to your application. And by correctly setting up the namespace, you avoid using the name of the physical file as you did in Visual Basic 6, and can use the metadata from the assembly to determine the correct namespace.
Now, you need to add code to the DoMath and DoName click events.
If you double-click on the DoMath button, add the code in Listing 14.4.
Private Sub DoMath_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles DoMath.Click Dim x As New NewClass() MessageBox.Show(x.DoMath(TextBox1.Text, TextBox2.Text)) End Sub
private void DoMath_Click(object sender, System.EventArgs e) { NewClass x = new NewClass(); int retVal; retVal = (x.doMath(Convert.ToInt32(textBox1.Text), Convert.ToInt32(textBox2.Text))); MessageBox.Show(retVal.ToString()); }
When you were typing along, you probably noticed the auto-list members and autocomplete available to you. After you create a new instance of the component class, all the properties, methods, and events are available to the application consuming the component.
You were also introduced to a very cool object-oriented feature in .NET called overloading. When a method is overloaded, it means there are multiple methods with the same name, but they have different data types for the input parameters or return values. They also can have a different number of input parameters. In the DoMath method you created in your component, there were two DoMath methods: one had two input parameters and the other had three. Depending on the data you pass to the method, .NET correctly figures out the correct method to use with the least amount of overhead.
Note
The input parameters and return values of a method are known as the method''''s signature.
Figure 14.11 shows the power of the Visual Studio .NET integrated development environment (IDE) when using components. Notice that the methods and properties for your component are listed, as well as a tooltip indicating that the method is overloaded and how many overloaded methods it has.
Now if you press F5 to run your application and click the DoMath button, you get a MessageBox back with the value.
Another extremely powerful tool is the Project Build Order property. Let''''s say that you have more than one component, and certain components depend on other components being successfully built before they can be built. If you have a bunch of projects in your Solution Explorer, you can set the order in which they''''re built by right-clicking on the solution name and selecting Project Build Order from the contextual menu. You get a dialog like the one in Figure 14.12 that enables you to specify the order in which the components should be built.
If you have multiple projects in a solution and a component in one of the projects is giving you problems, and nothing else is dependent on it, you can right-click on the project name of the component and select Remove from the contextual menu. Doing so removes the project form the solution. You can always add the project back by right-clicking the solution and selecting Add, Add Day 7, "Exceptions, Debugging, and Tracing" you learned that errors bubble up to the first method in the calling chain that has an error handler. If you''''re writing the components and consuming them in your own applications, you can implement error handling wherever you want because you''''re the only one using the component. If you plan to distribute the component for others to use, you can''''t assume that they''''ll implement error handling. That means you should handle errors in the component itself by using the Throw statement if an error occurs. The following snippet should refresh your memory regarding what you learned about handling errors on Day 7:
Try Catch e as Exception Throw e Finally
By throwing the exception to the caller, you''''re passing the correct error information and you''''re making sure that your code isn''''t causing the system to crash.
Note
You write code to consume the rest of the methods and properties in your component in the exercises at the end of the day.
Now you know how to create a component in .NET using the Class Library template and consume that component from a client application. You can see that creating and debugging components in the .NET IDE is very simple by adding another project to your solution. The Class Library template makes up most of the component development that you''''ll do. Creating components using the design surfaces is a great Visual Studio .NET feature, but you''''re normally encapsulating specific application functionality into separate pieces, so you don''''t necessarily need a designer to do that.
In the future of the mobile world, you might implement most of your components as Web services, so the functionality can be exposed outside of your organization.