With RIA Services, it is easy to use your own business objects in your Silverlight application… once you have the basic plumbing in place. However, there are quite a few steps required to set up that plumbing. This post details the process of hooking up your business objects, RIA Services, and Silverlight.
So … you follow best practices and build business objects for all of the entities involved in your application. Or maybe you generate those business objects with something like Entity Framework (EF), Linq to SQL or other similar tool. In any case, you now want to use those business objects from a Silverlight application.
Seems like it should be easy, right? Just define a reference from your Silverlight application to your business object component and proceed just like with your WinForms or ASP.NET application. But no.
Silverlight does not allow you to set a reference to a non-Silverlight component. There are a number of ways you can deal with this:
- Use a Silverlight class library project type and build your business objects in there. Not a good solution if you are using those same business objects with other user interfaces.
- Build a WCF service that provides your business objects to your Silverlight application. You can find out more about this option here.
- Use Rich Internet Application (RIA) Services. This is a new Microsoft technology that is currently out in preview.
This post demonstrates option #3: Using RIA Services. The example presented in this post uses business objects you build yourself. These "home made" business objects are often referred to as POCO, or plain old CLR objects. Use the techniques presented in this post any time you start a new Silverlight application and want to access your POCOs from that application.
[To use RIA with Entity Framework, there is video walkthrough here.]
The basic idea behind RIA Services is to use an ASP.NET application between your business object component and your Silverlight application to provide the communication between the two as shown below.
Starting right to left, you build your business objects in a Class Library component. This example uses a Customer class to define a customer and a Customers class to provide the list of customers.
The ASP.NET application has a standard project reference to the POCO class library. The ASP.NET application includes a Domain Service class, called CustomerService in this example, that calls the desired methods in the POCO class library.
The Silverlight application has an RIA Services link to the ASP.NET Web application. When the Silverlight application is compiled, it generates a client-side copy of the entity referenced by the ASP.NET application. In this case, it generates a Customer class. It also generates a entity context (CustomerContext in this case) that can be used for Silverlight data binding.
The remainder of this post walks through this process one step at a time.
Prerequisites
Before you can begin, there are some prerequisite steps:
- If you don't have it, download and install Silverlight 3 using the information provided here.
- Download and install RIA Services using the information provided here. (You may have already done this if you followed all of the instructions in step #1)
- Create a new Visual Studio Solution.
- Create a new Class Library project in that solution and build your business objects. This example uses the Customer and Customers classes defined below.
In C#:
public class Customer
{
public int CustomerId { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string EmailAddress { get; set; }
}
public class Customers
{
public static List<Customer> Retrieve()
{
List<Customer> custList = new List<Customer>
{new Customer()
{ CustomerId = 1,
FirstName="Bilbo",
LastName = "Baggins",
EmailAddress = "bb@hob.me"},
new Customer()
{ CustomerId = 2,
FirstName="Frodo",
LastName = "Baggins",
EmailAddress = "fb@hob.me"},
new Customer()
{ CustomerId = 3,
FirstName="Samwise",
LastName = "Gamgee",
EmailAddress = "sg@hob.me"},
new Customer()
{ CustomerId = 4,
FirstName="Rosie",
LastName = "Cotton",
EmailAddress = "rc@hob.me"}};
return custList;
}
}
In VB:
Public Class Customer
Private _CustomerId As Integer
Public Property CustomerId() As Integer
Get
Return _CustomerId
End Get
Set(ByVal value As Integer)
_CustomerId = value
End Set
End Property
Private _FirstName As String
Public Property FirstName() As String
Get
Return _FirstName
End Get
Set(ByVal value As String)
_FirstName = value
End Set
End Property
Private _LastName As String
Public Property LastName() As String
Get
Return _LastName
End Get
Set(ByVal value As String)
_LastName = value
End Set
End Property
Private _EmailAddress As String
Public Property EmailAddress () As String
Get
Return _EmailAddress
End Get
Set(ByVal value As String)
_EmailAddress = value
End Set
End Property
End Class
Public Class Customers
Public Shared Function Retrieve() As List(Of Customer)
Dim custList As New List(Of Customer)
custList.Add(New Customer With {.CustomerId = 1, _
.LastName = "Baggins", _
.FirstName = "Bilbo", _
.EmailAddress = "bb@hob.me"})
custList.Add(New Customer With {.CustomerId = 2, _
.LastName = "Baggins", _
.FirstName = "Frodo", _
.EmailAddress = "fb@hob.me"})
custList.Add(New Customer With {.CustomerId = 3, _
.LastName = "Gamgee", _
.FirstName = "Samwise", _
.EmailAddress = "sg@hob.me"})
custList.Add(New Customer With {.CustomerId = 4, _
.LastName = "Cotton", _
.FirstName = "Rosie", _
.EmailAddress = "rc@hob.me"})
Return custList
End Function
End Class
The C# code here uses auto-implemented properties to shorten the property syntax. The VB code uses the full property syntax.
In a real application, the Retrieve method would collect the data from the database. This example uses hard-coded values to make it easier for you to try this code without having to set up data access.
Decorating your Business Objects
Once you have the prerequisites complete, you need to add some attributes to your business objects so they are recognized by RIA Services when it generates the Silverlight entity.
1. Open the solution containing your business objects.
2. Open the Class Library project properties window for the project containing your business objects.
3. Add a reference to System.ComponentModel.DataAnnotations.
I had two of these. Be sure to pick the one from the Microsoft SDKs\RIA Services directory.
This namespace contains the attributes you need to annotate your business objects for RIA Services.
4. Add the Key attribute on the property that represents the unique key of the business object.
In C#:
[System.ComponentModel.DataAnnotations.Key()]
public int CustomerId { get; set; }
In VB:
Private _CustomerId As Integer
<System.ComponentModel.DataAnnotations.Key()> _
Public Property CustomerId() As Integer
Get
Return _CustomerId
End Get
Set(ByVal value As Integer)
_CustomerId = value
End Set
End Property
In this example, CustomerId is the unique key, so it is marked with the Key attribute.
5. Optionally, add RIA attributes for validation as desired. (More on this in a future post.)
Adding the Silverlight Project
Now that the business objects are ready, you can add the Silverlight project to your solution. This will automatically generate the associated ASP.NET project as well.
1. Add a new Silverlight Application to your solution.
You can create your Silverlight project in VB or in C#.
2. Be sure to enable RIA Services.
3. Click OK.
Visual Studio creates both the Silverlight project and the associated ASP.NET project. At runtime, the ASP.NET project launches the Silverlight project. The ASP.NET project also provides access to your business objects through RIA services.
NOTE: If you already have a Silverlight project that you wish to use with RIA Services, you can enable .NET RIA Services in the Silverlight project properties window:
Adding the Domain Service Classes
The ASP.NET application provides the communication between your business objects and the Silverlight application. This is accomplished with RIA Services by creating a set of Domain Service classes in the ASP.NET application.
1. Add a Domain Service class to the ASP.NET application.
2. Be sure to enable client access.
Notice that the bottom of this dialog is empty. If you used Entity Framework to generate your entities, they would appear in this dialog. But since this example uses POCOs, there won't be any entities displayed.
3. Click OK.
Visual Studio creates the basic structure of your Domain Service class as shown below.
In C#:
namespace SLCSharp.Web
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Ria;
using System.Web.Ria.Data;
using System.Web.DomainServices;
// TODO: Create methods containing your application logic.
[EnableClientAccess()]
public class CustomerService : DomainService
{
}
}
In VB:
Option Strict Off
Option Explicit On
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.ComponentModel.DataAnnotations
Imports System.Linq
Imports System.Web.DomainServices
Imports System.Web.Ria
Imports System.Web.Ria.Data
'TODO: Create methods containing your application logic.
<EnableClientAccess()> _
Public Class CustomerService
Inherits DomainService
End Class
NOTE: IMMEDIATELY change the Option Strict Off to Option Strict ON OR remove the lines entirely if you have them both on by default in your Compile options.
You can also remove any import statements for namespaces you already import through the References tab of the Properties window.
Accessing Your Business Objects From the Domain Service Class
The code to access your business objects goes into the Domain Service class created above. You can think of the Domain Service class as a wrapper around your business object members that provides a way for Silverlight to access the object properties and methods.
Any time you need to access any properties or call any methods on your business objects, you need to write a wrapper for that access in the Domain Service class.
Normally, you create one Domain Service class for each entity. So if your business objects included Customer/Customers, Purchase/Purchases, Invoice/Invoices, for example, you would create a CustomerService, PurchaseService, and InvoiceService class.
1. In your ASP.NET project containing your Domain Service class, set a reference to your business object component.
My sample project has two sets of business objects, one in VB and one in C#. You can access business objects in either language.
2. In the Domain Service class, import the namespace for the business object component.
In C#:
using BoCSharp;
In VB:
Imports BoVB
Or if you are using VB, import this namespace using the References tab of the Properties window:
3. Add the code that wraps the functionality of your business object.
For the purposes of this post, the code retrieves the set of customers.
In C#:
public IEnumerable<Customer> GetCustomers()
{
return Customers.Retrieve();
}
In VB:
Public Function GetCustomers() As IEnumerable(Of Customer)
Return Customers.Retrieve()
End Function
Note that this must be a method and not a property. If you attempt to use a property here, the compiler won't generate the required code.
The GetCustomers method simply calls the static/shared Retrieve method of the Customers class (defined at the beginning of this post).
Accessing the Domain Service Class from Silverlight
Finally! You are ready to use your business object from Silverlight by way of the Domain Service class.
1. Open the Silverlight Application project.
2. This example uses a grid to display the customer data, so set a reference to System.windows.Controls.Data.
3. To use the RIA Service controls, set a reference to System.Windows.Ria.Controls.
3. Open the MainPage.xaml file that was created for you in the Silverlight Application project.
4. Set up the XML namespaces.
<UserControl x:Class="SLCSharp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
xmlns:d=http://schemas.microsoft.com/expression/blend/2008
xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Ria.Controls"
xmlns:domain="clr-namespace:SLCSharp.Web"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
NOTE: If you copy and paste these namespaces into your application, be sure that you change the values shown in red. The x:Class is the name of the associated code behind class file. the xmlns:domain is the name of the associated ASP.Net application namespace.
These namespaces are as follows:
- xmlns - Default for Silverlight and WPF.
- xmlns:x – XAML-defined language elements for Silverlight and WPF, required for even basic features such as mapping a XAML file to its code behind file using x:Class.
- xmlns:data – XAML data controls, such as the DataGrid.
- xmlns:riaControls – RIA Service controls, such as the DomainDataSource
- xmlns:domain – Defines the associated ASP.NET namespace, required when using RIA services.
5. Add code to display a bound grid.
<Grid x:Name="LayoutRoot">
<riaControls:DomainDataSource x:Name="CustomerSource"
QueryName="GetCustomers" AutoLoad="True">
<riaControls:DomainDataSource.DomainContext>
<domain:CustomerContext/>
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
<data:DataGrid x:Name="CustomerList"
ItemsSource="{Binding Data, ElementName=CustomerSource}">
</data:DataGrid>
</Grid>
This code sets up an RIA Services DomainDataSource defining the source of the data for this UserControl. It defines a name (CustomerSource) and a QueryName (GetCustomers). The query name must match the name of the method to call in the Domain Service class.
It also sets a DomainContext, which associates the DomainDataSource with the Domain Service. This must match the name of the DomainContext in the generated code. Intellisense should help you define the correct name.
The DataGrid element uses the ItemsSource attribute to define the binding source. In this case, it is CustomerSource. This name must match the name given to the DomainDataSource.
6. Run it.
If everything works, it should appear as follows:
Now you can use your mad skills with styles and other Silverlight features to make this look nice.
Wow! That seemed like a lot of work.
The good news is that once you set this up, adding more features is easy:
- Add appropriate wrappers to the ASP.Net project using the Domain Service classes.
- Use the wrappers as needed from your Silverlight application.
Enjoy!
Gradients are a good way to make your application more visually interesting. They turn a flat solid color into something more natural and appealing to the eye by creating an illusion of light and shadow.
For example, compare this image which uses flat colors:
to this image that uses gradient colors:
For some great uses of gradient effects in user interface designs, see this link.
If you are not familiar with the terminology, a gradient is basically a blending of colors with an even graduation from one set of color values to another set of color values. Notice in the second image above, the white gradually blends into blue from the upper left corner to the lower right corner.
In Silverlight and WPF, you can set colors for just about anything, and wherever you can set a color you can often set a gradient. These examples color the background of the Canvas, but you could also paint Buttons or Rectangles or whatever.
In XAML, there are two primary types of gradients: Linear and Radial.
Linear Gradient
A linear gradient defines the graduation of colors along a line. The example below shows a linear gradient following a line from white at the top to blue at the bottom:

The XAML code required to set the linear gradient shown above is as follows:
<Canvas>
<Canvas.Background>
<LinearGradientBrush StartPoint=".5,0" EndPoint=".5,1">
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="LightSteelBlue" Offset="1"/>
</LinearGradientBrush>
</Canvas.Background>
</Canvas>
This specific code sets the gradient for a Canvas background, but you could use it anywhere a gradient is allowed.
The first properties you need to consider when defining your gradient are the StartPoint and EndPoint properties. These properties define where the gradient line begins and where it ends.
Think of the canvas as a rectangle with the (0,0) point in the upper left corner and the (1,1) point in the lower right corner as shown below:
If you set the StartPoint to 0,0 and the EndPoint to 1,1, the gradient will start in the upper left and end in the lower right as shown in the Address dialog example shown at the top of this post. (This is the default value, so if you don't set the StartPoint and EndPoint properties, this is the gradient you will get.)
By setting the StartPoint to .5,0 and EndPoint to .5,1, the gradient line begins in the middle top of the rectangle and ends in the middle bottom, creating the affect shown above.
If you want the gradient to appear from left to right, set the StartPoint to 0,.5 and the EndPoint to 1,.5. For right to left, set the StartPoint to 1,.5 and the EndPoint to 0,.5.
You can use any point in the rectangle as the StartPoint and EndPoint to create different effects. For example, you could set the StartPoint to .2,.2 and the EndPoint to .8,.8 to create this effect:
Notice the upper left corner is completely white and the lower right corner is completely blue. The gradient does not begin until .2,.2 and then ends at .8,.8.
The other important property to use when working with a linear gradient is the GradientStop. It defines the colors and where they start. The first GradientStop in this example is set to white and starts at an Offset of 0. The second GradientStop is set to LightSteelBlue at an Offset of 1.
Think of the Offset as the point on the gradient line where 0 is the origin of the line and 1 is the termination of the line. Note that if your StartPoint and EndPoint properties are not at a point of origin (such as .2,.2 and .8,.8), the Offset will still begin at the origin and end at the termination of the gradient line.
You can use any number of GradientStops (with a minimum of two) to include multiple colors in your gradient. For example, this gradient changes from White, to LightSteelBlue, to SteelBlue, back to LightSteelBlue and then White:
<Canvas>
<Canvas.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="LightSteelBlue" Offset=".2"/>
<GradientStop Color="SteelBlue" Offset=".4"/>
<GradientStop Color="LightSteelBlue" Offset=".8"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Canvas.Background>
</Canvas>
And the effect is as follows:
Radial Gradient
A radial gradient defines the graduation of colors that radiate outward from an origin. The example below shows a radial gradient radiating out from the center:
The XAML code required to set a radial gradient is as follows:
<Canvas>
<Canvas.Background>
<RadialGradientBrush GradientOrigin=".5,.5">
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="LightSteelBlue" Offset="1"/>
</RadialGradientBrush>
</Canvas.Background> This specific code sets the gradient for a Canvas background, but you could use it anywhere a gradient is allowed.
The first property you need to consider when defining your radial gradient is the GradientOrigin. It defines where the gradient begins.
Think of the canvas as a rectangle with the (0,0) point in the upper left corner and the (1,1) point in the lower right corner as shown below:
In this example, the gradient radiates out from the center point, which is .5,.5. (This is the default value, so if you don't set the GradientOrigin property, this is the gradient origin you will get.)
The other important property to use when working with a radial gradient is the GradientStop. It defines the colors and where they start. The first GradientStop in this example is set to white and starts at an Offset of 0. The second GradientStop is set to LightSteelBlue at an Offset of 1.
This GradientStop property in the radial gradient is similar to the linear gradient. The primary difference is that the gradient line begins at the GradientOrigin and radiates outward.
You can use any number of GradientStops (with a minimum of two) to include multiple colors in your gradient. For example, this gradient has an origin of .2,.2. It then changes from White, to LightSteelBlue, to SteelBlue, back to LightSteelBlue and then White:
<Canvas>
<Canvas.Background>
<RadialGradientBrush GradientOrigin=".2,.2">
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="LightSteelBlue" Offset=".2"/>
<GradientStop Color="SteelBlue" Offset=".4"/>
<GradientStop Color="LightSteelBlue" Offset=".8"/>
<GradientStop Color="White" Offset="1"/>
</RadialGradientBrush>
</Canvas.Background>
</Canvas>
And the effect is as follows:
Feel free to experiment with both types of gradients to produce interesting visual effects.
Enjoy!
If you are building a WinForms application and want to style your text, you may want to use the RichTextBox control instead of the standard TextBox control. This post provides some of the common techniques required to style text in a RichTextBox control.
To try out the examples in this post, build a new WinForms application. If desired, change the name of the form to "RichTextBoxSampleWin". Add a RichTextBox and two buttons to the form.
Setting Fonts/Colors
To set the fonts and colors of a RichTextBox, always select the text to style first, then set its font and color.
To try out setting fonts and colors, add this code to the Load event for the form:
In C#:
richTextBox1.Text = "That that is, is. That that is not, is not. "
+ "Is that it? It is.";
// Set the style of the text
richTextBox1.SelectionLength = richTextBox1.Text.Length;
richTextBox1.SelectionFont = new Font("Arial", 12, FontStyle.Bold);
richTextBox1.SelectionColor = Color.DarkSlateBlue;
richTextBox1.SelectionStart = richTextBox1.Text.Length;
In VB:
richTextBox1.Text = "That that is, is. That that is not, is not. " & _
"Is that it? It is."
' Set the style of the text
richTextBox1.SelectionLength = richTextBox1.Text.Length
richTextBox1.SelectionFont = New Font("Arial", 12, FontStyle.Bold)
richTextBox1.SelectionColor = Color.DarkSlateBlue
richTextBox1.SelectionStart = richTextBox1.Text.Length
The first line of code sets text into the RichTextBox.
The most important step here is to select the text that you want to style. Use the SelectionStart property to set the location in the text string to start the selection. If you don't specify a selection start, it is assumed to start at the first character of the text. Use the SelectionLength property to specify the length of the selection. In this case, the entire length of text is selected to be styled.
NOTE: Instead of setting the SelectionStart and SelectionLength properties, you can use the Select method to set both the selection start and selection length at one time.
The next two lines set the font and color for the selected text. The last line resets the SelectionStart to the end of the text. This allows the user to type in further text.
If you run the application at this point, it should look like this:
If the user types in more text, it will follow the given style.
Setting Multiple Fonts/Colors
There are two basic ways to set multiple fonts and colors within the text:
- Add the text by appending to the Text property and then use SelectionStart and SelectionLength to select the appended text. Then style the selected text. This is similar to the approach used above.
- Set the styles and then use the AppendText property.
To try out technique #1, add the following code to the button click event for one of the buttons on the form:
In C#:
// Add another set of text in a different style
string addedText = Environment.NewLine + Environment.NewLine
+ "This famous quote was from what movie?";
int len = richTextBox1.Text.Length;
richTextBox1.Text += addedText;
richTextBox1.SelectionStart = len;
richTextBox1.SelectionLength = addedText.Length;
richTextBox1.SelectionFont = new Font("Verdana", 10,
FontStyle.Regular);
richTextBox1.SelectionColor = Color.DarkSlateGray;
In VB:
Dim addedText As String = Environment.NewLine & Environment.NewLine & _
"This famous quote was from what movie?"
Dim len As Integer = richTextBox1.Text.Length
richTextBox1.Text &= addedText
richTextBox1.SelectionStart = len
richTextBox1.SelectionLength = addedText.Length
richTextBox1.SelectionFont = New Font("Verdana", 10, FontStyle.Regular)
richTextBox1.SelectionColor = Color.DarkSlateGray
This code first stores the length of the current text. This will be the selection start value. The additional text is then appended to the Text property of the RichTextBox. The SelectionStart and SelectionLength are then set as in the prior example. Finally, the font and color are set.
NOTE: You must set the SelectionStart and SelectionLength after you append the text.
To try out technique #2, replace the code in the button click event with this code instead:
In C#:
// Add another set of text in a different style
string addedText = Environment.NewLine + Environment.NewLine
+ "This famous quote was from what movie?";
richTextBox1.SelectionFont = new Font("Verdana", 10,
FontStyle.Regular);
richTextBox1.SelectionColor = Color.DarkSlateGray;
richTextBox1.AppendText(addedText);
In VB:
' Add another set of text in a different style
Dim addedText As String = Environment.NewLine & Environment.NewLine & _
"This famous quote was from what movie?"
richTextBox1.SelectionFont = New Font("Verdana", 10, FontStyle.Regular)
richTextBox1.SelectionColor = Color.DarkSlateGray
richTextBox1.AppendText(addedText)
Notice how much shorter this option is. This technique sets the SelectionFont and SelectionColor and then uses the AppendText method to add the styled text to the RichTextBox.
Regardless of which technique you choose, the result will appear as follows:
Highlighting Words
Another common requirement when working with a RichTextBox is to highlight multiple occurrences of a specific word.
To try out this technique, add this code to the other button click event:
In C#:
string wordToFind = "is";
int startIndex = 0;
while (startIndex > -1)
{
startIndex = richTextBox1.Find(wordToFind, startIndex + 1,
richTextBox1.Text.Length,
RichTextBoxFinds.WholeWord);
if (startIndex > -1 )
{
richTextBox1.Select(startIndex, wordToFind.Length);
richTextBox1.SelectionFont = new Font("Verdana", 12,
FontStyle.Bold | FontStyle.Italic);
richTextBox1.SelectionColor = Color.Red;
}
}
In VB:
Dim wordToFind As String = "is"
Dim startIndex As Integer = 0
Do While startIndex > -1
startIndex = richTextBox1.Find(wordToFind, startIndex + 1, _
richTextBox1.Text.Length, _
RichTextBoxFinds.WholeWord)
If startIndex > -1 Then
richTextBox1.Select(startIndex, wordToFind.Length)
richTextBox1.SelectionFont = New Font("Verdana", 12, _
FontStyle.Bold Or FontStyle.Italic)
richTextBox1.SelectionColor = Color.Red
End If
Loop
The code first defines the word to find. If this code is contained in a method instead of an event, the word to find could be passed in as a parameter.
The code then loops through the text in the RichTextBox using the Find method of the RichTextBox to find the next occurrence. The Find method will return –1 when it does not find any matches.
If a match is found, the code uses the Select method to select the found text. It then sets the font and color. This example also demonstrates how to bold AND italicize the text by Or'ing the style flags.
The result appears as follows:
Enjoy!
Way back when we were using Visual Studio 2005, there was a Clipboard Ring tab in the Toolbox. I loved that tab!
When I am doing a bunch of copy/pastes, I sometimes find that I hit Ctrl+C when I meant to hit Ctrl+V, and poof! my Clipboard was kindly wiped out for me.
With VS 2005, I could just open that Clipboard Ring tab of the Toolbox and there it would be ... the last several sets of Clipboard contents just waiting for me to reuse.
I was bummed when I did not see this feature in VS 2008. But behold, there are alternatives.
Accessing the Internal Clipboard Ring
Visual Studio still keeps the last sets of items you copied to the Clipboard. I heard the number was 20: that it keeps the contents from the last 20 times you used the copy function. But I did not test out that limit.
You can no longer see these last 20 clipboard items, but you can access them using keystrokes:
Ctrl+Shift+V
Keep holding down the Ctrl+Shift and pressing V to loop through the last set of clipboard items until you find the one you want.
This has saved me much frustration, knowing I can get back to my prior Clipboard contents.
Using the Toolbox
When you are using a code editor, the Toolbox displays a General tab. You can copy and paste or drag and drop code to this tab. This allows you to readily access these bits of code any time you are in a code editor.
Say I have a standard Try/Catch block that I want to use in several methods. If I plan to reuse this code often, I could create a code snippet as described here. But in this case, I just want to use this code today while I am doing some editing.
So I write the code I want, and drag it onto the General tab of the toolbox. It looks like this:
NOTE: I dragged some VB code, but this works the same in C#. It even allows me to have both VB and C# code on this tab at the same time.
If I hover over the entry, I can see the complete set of code as follows:
I can also rename the entry if I want to give it a name I can more readily recognize:
Note, however, that if the entry is renamed, hovering over the entry displays the name and not the set of code that the name represents.
I can then copy and paste from the toolbox, or just drag and drop the entry into the code editor.
If I want to manage a large set of these, I can add additional tabs to the toolbox and organize these pieces of code however I want.
If you are presenting or training, this technique is good for keeping longer code pieces so that your attendees don't need to watch you type quite so much.
Enjoy!
Visual Studio 2008 (Professional Edition and above) provides a really nice set of tools for development and execution of unit tests. It is, of course, easy for your tests to access the public properties and methods of your classes. But what about those private members?
[To begin with an overview of unit testing, start here.]
[To expose internal (C#) or friend (VB) members, see this post.]
You may have properties or methods in your class defined to be private. This post details how to test those methods using the unit testing features in Visual Studio.
NOTE: There are some testing philosophies that recommend you never test your private members; rather you test the public/internal/friend members and assume that those will provide coverage for all of your private members as well. Regardless of your point of view on this topic, this post provides the how-to so you can decide for yourself whether you want to or not.
Let's say your Customer class has a CustomerId property that looks like this:
In C#:
private int? _CustomerId;
public int? CustomerId
{
get { return _CustomerId; }
private set
{
if (_CustomerId == null || !_CustomerId.Equals(value))
{
string propertyName = "CustomerId";
if (!_CustomerId.Equals(value))
{
_CustomerId = value;
}
}
}
}
In VB:
Private _CustomerId As Integer?
Public Property CustomerId() As Integer?
Get
Return _CustomerId
End Get
Private Set(ByVal value As Integer?)
If _CustomerId Is Nothing OrElse _
Not _CustomerId.Equals(value) Then
Dim propertyName As String = "CustomerId"
If Not _CustomerId.Equals(value) Then
_CustomerId = value
End If
End If
End Set
End Property
Notice in both cases, the setter is private. The expectation is that the business object will set this value. However, you can you unit test it if you cannot set it?
The answer is PrivateObject.
PrivateObject is a class that allows test code to call class members that are not public. You PrivateObject to access private members of your class in your unit tests.
NOTE: You can also use PrivateObject for other non-public class members.
The following demonstrates how to use PrivateObject.
In C#:
/// <summary>
///A test for CustomerId
///</summary>
[TestMethod()]
public void CustomerIdTest()
{
Customer target;
int? expected;
int? actual;
// Null to Value
target = new Customer();
expected = 42;
PrivateObject po = new PrivateObject(target);
po.SetProperty("CustomerId", expected);
actual = target.CustomerId;
Assert.AreEqual(expected, actual, "Values are not equal");
}
In VB:
'''<summary>
'''A test for CustomerId
'''</summary>
<TestMethod()> _
Public Sub CustomerIdTest()
Dim target As Customer
Dim expected As Integer?
Dim actual As Integer?
' Null to value
target = New Customer
expected = 42
Dim po As PrivateObject = New PrivateObject(target)
po.SetProperty("CustomerId", expected)
actual = target.CustomerId
Assert.AreEqual(expected, actual, "Values are not equal")
End Sub
NOTE: This is only part of the code you would need to fully test the CustomerId property. Only one testing scenario was covered to instead focus on the PrivateObject syntax.
The code creates a new instance of PrivateObject, passing the instance of the class that has the private member you wish to access.
PrivateObject has methods such as GetProperty, SetProperty, GetField, SetField, and Invoke. These methods provide access to the private or other non-public members of your class.
Use PrivateObject whenever you need to access a private member in your class from your unit testing code.
Enjoy!
Visual Studio 2008 (Professional Edition and above) provides a really nice set of tools for development and execution of unit tests. It is, of course, easy for your tests to access the public properties and methods of your classes. But what about those internal/friend members?
[To begin with an overview of unit testing, start here.]
[To expose private members, see this post.]
You may have properties or methods in your class defined to be internal (C#) or friend (VB). This post details how to test those methods using the unit testing features in Visual Studio.
Well, it is easy. You just need to use this line of code:
In C#:
[assembly: InternalsVisibleTo("BoTest")]
In VB:
<Assembly: InternalsVisibleTo("BoTest")>
Where BoTest is the name of your unit testing project.
The hard part is finding where you put this line of code. It should reside in your AssemblyInfo file.
This file is relatively easy to find in your C# project; not so easy to find in your VB project. Here are the steps for both.
In C#:
- Find the project you want to test in Solution Explorer.
- Open the Properties node.
- Double-click on the AssemblyInfo.cs file.
- Set the InternalsVisibleTo attribute into the AssemblyInfo.cs file.
- Rebuild the project.
In VB:
- Find the project you want to test in Solution Explorer.
- Click on the Show All Files button in the Solution Explorer toolbar.
- Open the My Project node
- Double-click on the AssemblyInfo.vb file.
- Set the InternalsVisibleTo attribute into the AssemblyInfo.vb file.
Use this technique whenever you have internal/friend members in a class that you wish to access with your unit testing code.
Enjoy!
Visual Studio 2008 (Professional Edition and above) provides a really nice set of tools for development and execution of unit tests. This post provides suggestions for testing your property getters and setters.
[To begin with an overview of unit testing, start here.]
Let's say your Customer class has a LastName property that looks like this:
In C#:
private string _LastName;
public string LastName
{
get { return _LastName; }
set
{
if (_LastName == null || _LastName != value)
{
string propertyName = "LastName";
// Perform any validation here
if (_LastName != value)
{
_LastName = value;
SetEntityState(EntityStateType.Modified,
propertyName);
}
}
}
}
(Someone just mentioned how all of those ending braces look like a flock of sea gulls! LOL!)
In VB:
Private _LastName As String
Public Property LastName() As String
Get
Return _LastName
End Get
Set(ByVal value As String)
If _LastName Is Nothing OrElse _
_LastName IsNot value Then
Dim propertyName As String = "LastName"
' Perform any validation
If _LastName IsNot value Then
_LastName = value
SetEntityState(EntityStateType.Modified, _
propertyName)
End If
End If
End Set
End Property
NOTE: The SetEntityState method used in this code is coming from the business object base class provided in this prior post.
The key step for developing a good unit test is to define the test scenarios.
Looking at the requirements, the following testing scenarios are required for the LastName property:
- Initial null value; set to null value (should perform validation but not set the dirty flag)
- Initial null value; set to valid string (should perform validation and set the dirty flag)
- Initial null value; set to empty string (should perform validation and set the dirty flag)
- Initial string value; set to null value (should perform validation and set the dirty flag)
- Initial string value, set to different string value (should perform validation and set the dirty flag)
- Initial string value, set to same string value (should not perform validation and not set the dirty flag)
- Initial string value, set to empty value (should perform validation and set the dirty flag)
And if you have validation code, you will have more scenarios to test valid and invalid values. But this is enough to give you the general idea.
If you are building the unit test from existing code, you can generate the basic structure of the unit test for the property following the techniques detailed in this prior post.
But the test generation only gives you the basic template for testing your properties. This post focuses on how to update that template to perform the required unit testing.
Visual Studio will generate the following unit test template for the LastName property that was shown at the beginning of this post:
In C#:
/// <summary>
///A test for LastName
///</summary>
[TestMethod()]
public void LastNameTest()
{
Customer target = new Customer(); // TODO: Initialize to an appropriate value
string expected = string.Empty; // TODO: Initialize to an appropriate value
string actual;
target.LastName = expected;
actual = target.LastName;
Assert.AreEqual(expected, actual);
Assert.Inconclusive("Verify the correctness of this test method.");
}
In VB:
'''<summary>
'''A test for LastName
'''</summary>
<TestMethod()> _
Public Sub LastNameTest()
Dim target As Customer = New Customer ' TODO: Initialize to an appropriate value
Dim expected As String = String.Empty ' TODO: Initialize to an appropriate value
Dim actual As String
target.LastName = expected
actual = target.LastName
Assert.AreEqual(expected, actual)
Assert.Inconclusive("Verify the correctness of this test method.")
End Sub
To cover the defined testing scenarios, this code needs to be enhanced as follows:
In C#:
/// <summary>
///A test for LastName
///</summary>
[TestMethod()]
public void LastNameTest()
{
Customer target;
string expected;
string actual;
// Null to Null
target = new Customer();
expected = null;
target.LastName = expected;
actual = target.LastName;
Assert.AreEqual(expected, actual, "Values are not equal");
Assert.AreEqual(false, target.IsDirty,
"Object not marked as dirty");
// Null to value
target = new Customer();
expected = "Johnson";
target.LastName = expected;
actual = target.LastName;
Assert.AreEqual(expected, actual, "Values are not equal");
Assert.AreEqual(true, target.IsDirty, _
"Object not marked as dirty");
// Null to Empty
target = new Customer();
expected = string.Empty;
target.LastName = expected;
actual = target.LastName;
Assert.AreEqual(expected, actual, "Values are not equal");
Assert.AreEqual(true, target.IsDirty,
"Object not marked as dirty"); // Value to Null
target = new Customer() {LastName = "Johnson"};
target.SetEntityState(BoBase.EntityStateType.Unchanged);
expected = null;
target.LastName = expected;
actual = target.LastName;
Assert.AreEqual(expected, actual, "Values are not equal");
Assert.AreEqual(true, target.IsDirty,
"Object not marked as dirty");
// Value to new Value
target = new Customer() {LastName = "Johnson"};
target.SetEntityState(BoBase.EntityStateType.Unchanged);
expected = "Jones";
target.LastName = expected;
actual = target.LastName;
Assert.AreEqual(expected, actual, "Values are not equal");
Assert.AreEqual(true, target.IsDirty,
"Object not marked as dirty");
// Value to same Value
target = new Customer() {LastName = "Johnson"};
target.SetEntityState(BoBase.EntityStateType.Unchanged);
expected = "Johnson";
target.LastName = expected;
actual = target.LastName;
Assert.AreEqual(expected, actual, "Values are not equal");
Assert.AreEqual(false, target.IsDirty,
"Object not marked as dirty");
// Value to Empty
target = new Customer() {LastName = "Johnson"};
target.SetEntityState(BoBase.EntityStateType.Unchanged);
expected = string.Empty;
target.LastName = expected;
actual = target.LastName;
Assert.AreEqual(expected, actual, "Values are not equal");
Assert.AreEqual(true, target.IsDirty,
"Object not marked as dirty");
} In VB:
'''<summary>
'''A test for LastName
'''</summary>
<TestMethod()> _
Public Sub LastNameTest()
Dim target As Customer
Dim expected As String
Dim actual As String
' Null to Null
target = New Customer
expected = Nothing
target.LastName = expected
actual = target.LastName
Assert.AreEqual(expected, actual, "Values are not equal")
Assert.AreEqual(False, target.IsDirty, _
"Object not marked as dirty")
' Null to value
target = New Customer
expected = "Johnson"
target.LastName = expected
actual = target.LastName
Assert.AreEqual(expected, actual, "Values are not equal")
Assert.AreEqual(True, target.IsDirty, _
"Object not marked as dirty")
' Null to Empty
target = New Customer
expected = String.Empty
target.LastName = expected
actual = target.LastName
Assert.AreEqual(expected, actual, "Values are not equal")
Assert.AreEqual(True, target.IsDirty, _
"Object not marked as dirty") ' Value to Null
target = New Customer With {.LastName = "Johnson"}
target.SetEntityState(BOBase.EntityStateType.Unchanged)
expected = Nothing
target.LastName = expected
actual = target.LastName
Assert.AreEqual(expected, actual, "Values are not equal")
Assert.AreEqual(True, target.IsDirty, _
"Object not marked as dirty")
' Value to new Value
target = New Customer With {.LastName = "Johnson"}
target.SetEntityState(BOBase.EntityStateType.Unchanged)
expected = "Jones"
target.LastName = expected
actual = target.LastName
Assert.AreEqual(expected, actual, "Values are not equal")
Assert.AreEqual(True, target.IsDirty, _
"Object not marked as dirty")
' Value to same Value
target = New Customer With {.LastName = "Johnson"}
target.SetEntityState(BOBase.EntityStateType.Unchanged)
expected = "Johnson"
target.LastName = expected
actual = target.LastName
Assert.AreEqual(expected, actual, "Values are not equal")
Assert.AreEqual(False, target.IsDirty, _
"Object not marked as dirty")
' Value to Empty
target = New Customer With {.LastName = "Johnson"}
expected = String.Empty
target.LastName = expected
actual = target.LastName
Assert.AreEqual(expected, actual, "Values are not equal")
Assert.AreEqual(True, target.IsDirty, _
"Object not marked as dirty")
End Sub NOTE: The SetEntityState method and IsDirty property used in this code are coming from the business object base class provided in this prior post.
NOTE: You may get an error when calling SetEntityState because in the business object base class is defined to be protected internal (protected friend in VB), not public. If so, you need to use the technique presented here to allow your tests to access internal/friend properties and methods.
WOW! That is a LOT of test code! Some experts have said that every line of code needs at least 3 - 5 lines of test code.
We have 17 lines of C# code and 15 lines of VB code in our property procedure. If I counted correctly, there are 51 lines of C# test code and 50 lines of VB test code. So that is about 3x the number of code lines.
Let's walk through what this test code is doing, following through with the testing scenarios provided earlier in this post.
Scenario 1: The code creates a new instance of the Customer class. By default, a new instance sets any string values to null/nothing. So the test code simply sets the property to null/nothing, gets the value, confirms that the value is as expected, and ensures that it did not get marked as dirty.
Scenario 2: The code again creates a new instance of the Customer class. By default a new instance sets any string values to null/nothing. So the test code sets the property to a value, gets the value, confirms that the value is as expected, and ensures that the object was marked as dirty.
Scenario 3: The code again creates a new instance of the Customer class. By default a new instance sets any string values to null/nothing. So the test code sets the property to an empty string, gets the value, confirms that the value is as expected, and ensures that the object was marked as dirty.
Now for the harder scenarios. There is no easy way to set a non-null initial value for a property. One option is to set the private backing variable to the desired initial value. But with the backing variable being private, there is extra code to write to make it work.
Another option is to set the property using the setter. But this marks the object as dirty, adversely interfering with the test. So if you use this technique, you then need to call SetEntityState to clear the entity state and ensure it is not marked as dirty. The sample code used this technique.
Scenario 4: The code creates a new instance of the customer class, setting the initial value of the property to a valid value. It then calls SetEntityState to clear the dirty flag. Then the test code sets the property to a null, gets the value, confirms that the value is as expected, and ensures that the object was marked as dirty.
Scenario 5: The code creates a new instance of the customer class, setting the initial value of the property to a valid value. It then calls SetEntityState to clear the dirty flag. Then the test code sets the property to another valid value, gets the value, confirms that the value is as expected, and ensures that the object was marked as dirty.
Scenario 6: The code creates a new instance of the customer class, setting the initial value of the property to a valid value. It then calls SetEntityState to clear the dirty flag. Then the test code sets the property to the same value, gets the value, confirms that the value is as expected, and ensures that the object was not marked as dirty.
Scenario 7: The code creates a new instance of the customer class, setting the initial value of the property to a valid value. It then calls SetEntityState to clear the dirty flag. Then the test code sets the property to an empty string, gets the value, confirms that the value is as expected, and ensures that the object was marked as dirty.
If the field was validated, such as required field validation or a maximum length check, additional scenarios and associated test code would be required.
So for every business object property in your application, define the appropriate set of test scenarios and build the test code to support each scenario.
Or build a test base class that performs the basic set of tests for each of your properties. But that is left for a future post.
Enjoy!
Visual Studio 2008 (Team System ONLY) provides a really nice set of tools for viewing the code coverage of your unit tests.
NOTE: While Visual Studio 2008 Professional Edition has tools for building, executing, and debugging unit tests, it does NOT include the code coverage tools.
[To begin with an overview of unit testing, start here.]
Code coverage illustrates how much of the code was executed (or covered) by the unit tests.
NOTE: This post assumes you have already generated or created at least one unit test.
To view the code coverage for your unit tests:
1) Enable code coverage in the test run configuration file.
When you create your first unit test, Visual Studio adds a LocalTestRun.testrunconfig file to your solution under the Solution Items folder. Double-click on this file to open it:
Select Code Coverage from the left list:
Select the files on the right that you wish to view code coverage. Don't pick your test projects; rather pick the projects containing the code that is being tested. Then click Apply and Close.
2) Run your unit tests. The Test Results dialog appears.
See this prior post for more information on executing unit tests.
Your results should appear similar to the following:

3) If the tests pass, click the Show Code Coverage Results button in the far upper right corner of the Test Results dialog. The Code Coverage Results dialog appears.
This dialog displays all of the code in all of the files you selected for code coverage instrumentation. Drill down as needed to find the desired code.
In this case, the unit test is testing the getter and setter for the LastName. Notice that the covered percentage for both the getter and setter is 100%. That means that the unit test is executing every line of code in the getter and setter.
4) Double click on any item in the Code Coverage dialog to open the associated code window.
Notice how the code is color-coded. Blue shows code that was executed by the unit test. Red shows code that was not executed.
Use this feature to ensure you have unit tests for each unit of your code.
Enjoy!
EDITED 10/27/09: While Visual Studio 2008 Professional Edition has tools for building, executing, and debugging unit tests, it does NOT include the code coverage tools. In the original version of this post, I incorrectly stated that code coverage tools were available in the Professional Edition. This post has been corrected.
Visual Studio 2008 (Professional Edition and above) provides a really nice set of tools for development and execution of unit tests.
[To begin with an overview of unit testing, start here.]
This prior post demonstrates how to build a unit test using the "Create Unit Tests..." feature of the Code Editor. This post demonstrates how to execute a unit test.
NOTE: This post assumes you have already generated or created at least one unit test.
To execute one or more unit tests:
1) Open your solution in Visual Studio.
The solution should include both the project(s) to test and the test project(s).
2) Select Test | Windows | Test View from the menu to view the Test View window. This window contains every method marked with the TestMethod attribute.
The solution used for the screenshot above has two LastNameTest unit tests: One for the VB example and one for the C# example. If you coded along from the prior unit testing post, you will only have one for whichever language you selected. If you have been creating unit tests for one of your projects, you may have hundreds of tests in this list.
To execute unit tests:
1) Select one or more tests from the list of tests in the Test View window.
You can add columns and sort the list or use the filter feature to make it easier to locate and select the desired tests to execute.
2) Click the Run Selection button in the upper left corner of the Test View window or right-click on any selected test and select "Run Selection" from the context menu.
The selected test(s) will then execute, displaying their status in the Test Results window:
When the test is complete, the Test Results window will look something like this:
Both of the tests shown in the above screenshot are marked as Inconclusive because the generated unit testing code used the Assert class Inconclusive method. The generated unit testing template is designed to prevent a false positive. It generates an inconclusive result until you update the unit test with correct valid and invalid values and remove the Inconclusive method call.
To see more information on the result of the test, double-click on a test result.
To run the test again, use the Run or Debug buttons at the top of the Test Results window.
If any of the tests don't pass, they are marked as Failed in the Test Results window as shown below.
Double click on any of the failed tests to view the test results:
The Error Stack Trace at the bottom of this window gives you further information on the source of the failure. Click on any link in the stack trace to jump to the associated location in the code.
You can also debug the code as the test is executing if you "Debug Selection" option instead of the "Run Selection" option.
After you update the unit tests with valid code and the tests pass, the Test Results will appear as follows:
Notice the color-coded green passing indicator.
Enjoy!
If you have Visual Studio 2008 or later and have the Professional Edition or better (NOT the Express Editions), you have some very nice unit testing tools within your Visual Studio environment. These tools help you write, execute, and track your unit tests and code coverage. This post provides an introduction to using these tools.
If you are new to unit testing, the idea is to test the smallest possible units of your code. In most cases, the smallest units of code are the property procedures and methods of your classes.
For more general information about the purpose of unit testing, see this link.
NOTE: Unit testing is not meant to replace integration testing, system testing, or user testing.
In some development methodologies, such as Test Driven Development (TDD), unit tests are written before the code is written. You capture the basic requirements in the unit test and then write the code. The code is complete when the unit tests pass. Visual Studio 2010 has features to assist with this "unit test first" approach.
But this introduction demonstrates how to write unit tests for existing code. This technique is helpful if you follow a code-first approach or if you received code from another source or have old code that did not originally have unit tests.
Build the Code
The business object tested in this post is a simplified Customer class that uses the business object base class defined in this post.
The Customer class is shown below.
In C#:
public class Customer: BoBase
{
private int? _CustomerId;
public int? CustomerId
{
get { return _CustomerId; }
internal set
{
if (_CustomerId == null || !_CustomerId.Equals(value))
{
string propertyName = "CustomerId";
// Perform any validation here
if (!_CustomerId.Equals(value))
{
_CustomerId = value;
SetEntityState(EntityStateType.Modified,
propertyName);
}
}
}
}
private string _LastName;
public string LastName
{
get { return _LastName; }
set
{
if (_LastName == null || _LastName != value)
{
string propertyName = "LastName";
// Perform any validation here
if (_LastName != value)
{
_LastName = value;
SetEntityState(EntityStateType.Modified,
propertyName);
}
}
}
}
private string _FirstName;
public string FirstName
{
get { return _FirstName; }
set
{
if (_FirstName == null || _FirstName != value)
{
string propertyName = "FirstName";
// Perform any validation here
if (_FirstName != value)
{
_FirstName = value;
SetEntityState(EntityStateType.Modified,
propertyName);
}
}
}
}
private string _EmailAddress;
public string EmailAddress
{
get { return _EmailAddress; }
set
{
if (_EmailAddress == null || _EmailAddress != value)
{
string propertyName = "EmailAddress";
// Perform any validation here
if (_EmailAddress != value)
{
_EmailAddress = value;
SetEntityState(EntityStateType.Modified,
propertyName);
}
}
}
}
}
In VB:
Public Class Customer
Inherits BOBase
Private _CustomerId As Integer?
Public Property CustomerId() As Integer?
Get
Return _CustomerId
End Get
Friend Set(ByVal value As Integer?)
If _CustomerId Is Nothing OrElse _
Not _CustomerId.Equals(value) Then
Dim propertyName As String = "CustomerId"
' Perform any validation
If Not _CustomerId.Equals(value) Then
_CustomerId = value
SetEntityState(EntityStateType.Modified, propertyName)
End If
End If
End Set
End Property
Private _FirstName As String
Public Property FirstName() As String
Get
Return _FirstName
End Get
Set(ByVal value As String)
If _FirstName Is Nothing OrElse _
_FirstName IsNot value Then
Dim propertyName As String = "FirstName"
' Perform any validation
If _FirstName IsNot value Then
_FirstName = value
SetEntityState(EntityStateType.Modified, _
propertyName)
End If
End If
End Set
End Property
Private _LastName As String
Public Property LastName() As String
Get
Return _LastName
End Get
Set(ByVal value As String)
If _LastName Is Nothing OrElse _
_LastName IsNot value Then
Dim propertyName As String = "LastName"
' Perform any validation
If _LastName IsNot value Then
_LastName = value
SetEntityState(EntityStateType.Modified, _
propertyName)
End If
End If
End Set
End Property
Private _EmailAddress As String
Public Property EmailAddress() As String
Get
Return _EmailAddress
End Get
Set(ByVal value As String)
If _EmailAddress Is Nothing OrElse _
_EmailAddress IsNot value Then
Dim propertyName As String = "EmailAddress"
' Perform any validation
If _EmailAddress IsNot value Then
_EmailAddress = value
SetEntityState(EntityStateType.Modified, _
propertyName)
End If
End If
End Set
End Property
End Class
The first if statement in each of the property procedures for the Customer class checks whether the current value is null or was changed. If the property is changed, you want to revalidate it, set it as modified, and generate a PropertyChanged event (which is handled in the SetEntityState method).
NOTE: C# uses a != operator to judge whether the value was changed. VB cannot use the <> operator because VB propagates null values. So if either value is null (nothing) the result is false. (See this msdn entry for more information.) To prevent this problem, IsNot is used in the VB code to determine if the value was changed.
The null check allows for possible validation of required fields (that is, fields that cannot be null or empty). If you know you will never need a null validation check, you can leave the null check off the first if statement.
The propertyName variable defines a name that you can use in any validation error messages and it is the name used in the PropertyChanged event.
You can then perform any necessary validation. In this simple example, no validation was added. If you want to see an example of some validation, check out this post.
Finally, if the value was changed, the backing variable is set to the new value and the SetEntityState method is called to mark the business object as "dirty" and to generate the PropertyChanged event.
Define the Testing Scenarios
So let's start with the test of the LastName property. Looking at the requirements, the following testing scenarios are required:
- Initial null value; set to null value (should perform validation but not set the dirty flag)
- Initial null value; set to valid string (should perform validation and set the dirty flag)
- Initial null value; set to empty string (should perform validation and set the dirty flag)
- Initial string value; set to null value (should perform validation and set the dirty flag)
- Initial string value, set to different string value (should perform validation and set the dirty flag)
- Initial string value, set to same string value (should not perform validation and not set the dirty flag)
- Initial string value, set to empty value (should perform validation and set the dirty flag)
And if you have validation code, you will have more scenarios to test valid and invalid values. But this is enough to give you the general idea.
So now let's generate the unit test for the LastName property using the tools provided in Visual Studio (Professional Edition or above).
Generate the Unit Test
The following are the steps for generating the unit test for a particular property procedure or method:
1) Open the Code Editor for the code you want to test.
2) Right-click and select Create Unit Tests... from the context menu.
The following dialog will appear:
3) Select the properties, methods, or constructors you wish to test.
If you were in a specific property procedure or method, that procedure or method is automatically checked in this dialog. You can select to generate tests for any properties, methods, or constructors using this dialog.
Notice the Output project combobox on this dialog. Using this combobox, you can create a new C# unit test, new VB unit test, or select any existing unit test project if you already have some in your solution. This allows you to add unit tests to existing unit testing projects at any point in the development process.
4) Click OK.
5) If you are creating a new C# or VB project, enter the project name and click Create.
6) The test project is then added to your Solution Explorer.
If you created a VB test project, the result is the same, but with a CustomerTest.vb file within the BoTest project.
View the Generated Code
Visual Studio automatically creates an first cut of your unit testing code.
In C#:
Double-click on CustomerTest.cs to view the code.
/// <summary>
///A test for LastName
///</summary>
[TestMethod()]
public void LastNameTest()
{
Customer target = new Customer(); // TODO: Initialize to an appropriate value
string expected = string.Empty; // TODO: Initialize to an appropriate value
string actual;
target.LastName = expected;
actual = target.LastName;
Assert.AreEqual(expected, actual);
Assert.Inconclusive("Verify the correctness of this test method.");
}
In VB:
Double-click on CustomerTest.vb to view the code.
'''<summary>
'''A test for LastName
'''</summary>
<TestMethod()> _
Public Sub LastNameTest()
Dim target As Customer = New Customer ' TODO: Initialize to an appropriate value
Dim expected As String = String.Empty ' TODO: Initialize to an appropriate value
Dim actual As String
target.LastName = expected
actual = target.LastName
Assert.AreEqual(expected, actual)
Assert.Inconclusive("Verify the correctness of this test method.")
End Sub
The TestMethod attribute defines this method as a unit test. It is then picked up by the other unit testing tools within Visual Studio.
The generated code includes some ToDo notes, defining where you should change the code.
The Assert class is a key aspect of your unit tests. It provides many methods that you can use to assert whether your test produced expected results.
The generated code uses two of the Assert class methods. The AreEqual method determines whether the expected and actual values are equal. If not, it fails the test.
The Inconclusive method always causes the test to fail. This is added to all generated code to ensure that the test will fail until you modify the test with valid values.
At this point, you can try to execute this unit test, or update it first and then execute it.
See the following posts for more information:
Enjoy!
If you are using XML in a WinForms application you may find the need to display the XML data in a DataGridView.
Let's take this XML:
<states>
<state name="California">
<abbreviation>CA</abbreviation>
<year>1850</year>
<governor>Schwarzenegger</governor>
</state>
<state name="Wisconsin">
<abbreviation>WI</abbreviation>
<year>1848</year>
<governor>Doyle</governor>
</state>
</states>
Displaying XML in a DataGridView sounds easy, but if you just set the DataGridView DataSource to the XML data, you will get something like this:
Notice how it has lots of yuck in it: attribute details, node properties, and so on for every node in the XML. So how do you get something more like this:
The trick is to use anonymous types.
The code is provided here in VB and C# and then described in detail below.
NOTE: Be sure to set a reference to System.Core and System.Xml.Linq
In C#:
XElement statesXml = XElement.Parse("<states>" +
"<state name='California'>" +
"<abbreviation>CA</abbreviation>" +
"<year>1850</year>" +
"<governor>Schwarzenegger</governor>" +
"</state>" +
"<state name='Wisconsin'>" +
"<abbreviation>WI</abbreviation>" +
"<year>1848</year>" +
"<governor>Doyle</governor>" +
"</state>" +
"</states>");
var query = from st in statesXml.Descendants("state")
select new
{
Name = st.Attribute("name").Value,
Abbrev = st.Element("abbreviation").Value,
Year = st.Element("year").Value,
Governor = st.Element("governor").Value
};
DataGridView1.DataSource = query.ToList();
In VB:
Dim statesXml As XElement = _
<states>
<state name="California">
<abbreviation>CA</abbreviation>
<year>1850</year>
<governor>Schwarzenegger</governor>
</state>
<state name="Wisconsin">
<abbreviation>WI</abbreviation>
<year>1848</year>
<governor>Doyle</governor>
</state>
</states>
Dim query = From st In statesXml...<state> _
Select New With { _
.Name = st.@name, _
.Abbrev = st.<abbreviation>.Value, _
.Year = st.<year>.Value, _
.Governor = st.<governor>.Value}
DataGridView1.DataSource = query.ToList
The first part of this code builds the XML. The C# code uses the XElement.Parse function to build the XML; VB uses XML literals. This part of the code is not necessary if you are reading the XML from another source, such as a file.
The second part of the code leverages Linq to XML to process the set of state XML elements. For each element, it uses the Select New syntax to create an anonymous type. The syntax defines an unnamed (anonymous) type with properties Name, Abbrev, Year, and Governor.
[To view an overview of anonymous types, start here.]
The last line converts the results of the query to a generic list and assigns it to the DataSource property of the DataGridView. Visual Studio uses the anonymous type property names as the text for the column titles and populates the rows with each state element.
Use this technique any time you have XML that you want to display in a DataGridView.
Enjoy!
Lambda expressions can be assigned to a delegate variable. The lambda expression is then executed when the delegate is called.
[To begin with an overview of lambda expressions, start here.]
In the following example, a lambda expression is assigned to a variable (f).
In C#:
Func<int,string> f = x => (x + x).ToString();
Debug.WriteLine(f(5));
Debug.WriteLine(f(10));
In VB:
Dim f = Function(x as Integer) (x + x).ToString()
Debug.WriteLine(f(5))
Debug.WriteLine(f(10))
The lambda expression in this example is a Func<int, string> [Func(Of Integer, String) in VB] meaning it takes one integer input parameter and returns a string. The lambda expression simply takes the input value, adds it to itself, and returns the result as a string.
[For more information on Func delegates, see this post.]
When the expression is defined, it is not executed. It is not executed until it is called.
The first Debug.WriteLine statement calls the lambda expression, passing in a 5. The result displays "10" in the debug window.
The second Debug.WriteLine statement calls the lambda expression again, passing in a 10. The result displays "20" in the debug window.
Lambda expressions are executed when they are called, not when they are constructed. This is important to consider, especially when the lambda expression contains local variables.
Local variables used in a lambda expression are “captured” or “lifted”. The variable value used is the value at execution time. The variable lifetime extends to the lifetime of the delegate.
The following code updates the original example to use a local variable.
In C#:
int y = 0;
Func<int,string> f = x => (x + y).ToString();
y = 10;
Debug.WriteLine(f(5));
In VB:
Dim y As Integer = 0
Dim f = Function(x) (x + y).ToString()
y = 10
Debug.WriteLine(f(5))
The lambda expression in this example takes the input value, adds it to the current value of the local variable (y), and returns the result as a string.
The Debug.WriteLine statement in this example calls the lambda expression, passing in a 5. At the point of executing the Debug statement, y is 10, so the result displays "15" in the debug window.
For another example of using lambda expressions with local variables, see this post.
Enjoy!
The same several questions often come up in the forums regarding the basics of building a user control with VB.NET or C#. The goal of this post is to answer those questions.
There are three basic types of WinForms user controls that you can create:
- Extended control
- Composite control
- Custom control
Each of these are discussed below.
Extended Control
Use an extended control whenever you want to extend the behavior of one particular control. Say for example that you want to build your own TextBox that only allows alphabetic characters. Or you want to build your own Button that has specific behaviors.
The best thing about extended controls is that you automatically get all of the intrinsic behavior of the original control. All you need to do is add any extended functionality that you want for the control.
To create this type of user control, follow these steps.
In C#:
- Right-click on the project and select Add | User Control.
- Name the user control and click Add.
- Do NOT put anything on the design surface of the user control.
- Open the code behind file (UserControl1.cs).
- Modify the code to inherit from the control you are extending.
public partial class UserControl1 : TextBox
This example extends a TextBox control. Replace TextBox above with whatever WinForm control you want to extend.
NOTE: After changing the Inherits statement, you may get an error on a line that begins with this.AutoScaleMode. If so, just delete that line. It is no longer needed now that you are inheriting from a control other than UserControl.
In VB:
- Right-click on the project and select Add | User Control.
- Name the user control and click Add.
- Do NOT put anything on the design surface of the user control.
- Select the project in the Solution Explorer and click the Show All Files button in the Solution Explorer toolbar.
- Click on the plus sign to the left of the user control in Solution Explorer to view the nodes below it.
- Double-click on the designer file to open it. (UserControl1.Designer.vb)
- Modify the code to inherit from the control you are extending.
Partial Class UserControl1
Inherits TextBox
This example extends a TextBox control. Replace TextBox above with whatever WinForm control you want to extend.
NOTE: After changing the Inherits statement, you may get an error on a line that begins with Me.AutoScaleMode. If so, just delete that line. It is no longer needed now that you are inheriting from a control other than UserControl.
Then add any additional behavior or functionality that you want in the extended control.
The MSDN documentation provides an example of building an extended control using VB.NET here and C# here.
Composite Control
A composite controls is so named because it is composed of multiple controls. Use this type of user control any time you want to build a control that combines a set of other controls. For example, you want to build a search control that contains a Textbox for entry of the text to search, Button to click to perform the search, and ListBox for the results of the search.
The best thing about composite controls is that you can easily add any controls to the composite control using the design surface.
However, because it is a composite control that inherits from UserControl, no properties, methods, or events from any of the underlying controls are exposed. This means that when you use the user control, you cannot set the Text property of the TextBox or respond to Button click events without writing some code.
You basically have to write code to expose any property, method, or event that you need.
To create this type of user control, follow these steps:
- Right-click on the project and select Add | User Control.
- Name the user control and click Add.
- Put the controls you want onto the design surface.
- Expose any properties, methods, or events that you need.
An example of generating events from a user control is provided in this post.
The MSDN documentation provides an example of building a composite control using VB.NET here and C# here.
Custom Control
A custom control is a control you create from the ground up including all control drawing and any unique behavior.
To build a custom control, inherit from Control to get the basic behavior of a WinForms control. Then use the OnPaint event to render your custom user interface.
The MSDN documentation provides an example of building a simple custom control here.
Enjoy!
A Func delegate encapsulates a method that returns a value. It takes up to four parameters (and this number is increased in .NET 4.0) plus the return value.
[To begin with an overview of lambda expressions, start here.]
The following signature is a Func delegate that takes two integer parameters and returns a string.
In C#:
Func<int, int, string>
In VB:
Func(Of Integer, Integer, String)
There are many examples of Func delegates.
The following code demonstrates the Sum function that sums the sales total for all customers in the list (and assumes that a Customer object has a SalesTotal property).
In C#:
var total = custList.Sum(c =>
c.SalesTotal);
In VB:
Dim total = custList.Sum(Function(c) _
c.SalesTotal)
Enjoy!
Just as the name implies, an action delegate encapsulates a method that performs an action and has no return value. It takes up to four parameters (and this number is increased in .NET 4.0).
[To begin with an overview of lambda expressions, start here.]
The ForEach method of the List<T> is an example of an action delegate. It takes an action delegate as a parameter.
One of the common uses of ForEach is to display all of the elements in a list using one line of code.
In C#:
custList.ForEach(c =>
Debug.WriteLine(c.LastName));
In VB:
custList.ForEach(AddressOf WriteToDebug)
NOTE: VB lambda expressions do not currently support action delegates. In the above example, the code uses a named method as the action delegate. VB 10 lambda expressions will support action delegates using the Sub keyword instead of the Function keyword.
Enjoy!
According to Wikipedia, a predicate is “a function which returns a Boolean value”.
[To begin with an overview of lambda expressions, start here.]
A predicate delegate encapsulates a method that evaluates to True or False. It takes a single parameter.
The Array class Find method is an example of a predicate delegate. It takes an array as a first parameter and a predicate delegate as its second parameter.
In C#:
var foundCustomer = Array.Find(custArray, c =>
c.LastName.StartsWith("K"));
In VB:
Dim foundCustomer = Array.Find(custArray, Function(c) _
c.LastName.StartsWith("K"))
This code iterates through the array, checking each entry and evaluating the expression as true or false. If the expression is false, it continues. If the expression is true, it returns the entry. Basically, this code finds the first customer in the array with a last name that starts with the defined letter.
Enjoy!
This post covers the syntax for lambda expressions. It uses the customer list defined in this prior post.
[To begin with an overview of lambda expressions, start here.]
The first example below uses the FirstOrDefault extension method on the Enumerable object to find the first customer that matches the defined expression. The FirstOrDefault method takes a delegate as a parameter and that delegate is defined with a lambda expression.
In C#:
' General syntax:
Customer foundCustomer =
custList.FirstOrDefault((Customer c) =>
c.CustomerId == 4);)
' With inferred typing:
var foundCustomer =
custList.FirstOrDefault(c => c.CustomerId == 4);)
The lambda expression in this example is as follows:
c => c.CustomerId == 4
The code begins with the set of parameters to the lambda expression. In this example, there is one parameter (c). The => is the “goes to” or lambda operator. The remainder of the code is the expression itself. In this case, checking for the item in the list where CustomerId is 4.
In VB:
' General syntax:
Dim foundCustomer as Customer = _
custList.FirstOrDefault(Function(c as Customer) _
c.CustomerId = 4)
' With inferred typing:
Dim foundCustomer = _
custList.FirstOrDefault(Function(c) _
c.CustomerId = 4)
The lambda expression in this example is as follows:
Function(c) c.CustomerId = 4
The code begins with the word “Function” along with the set of parameters to the lambda expression. In this example, there is one parameter (c). The remainder of the code is the expression itself. In this case, checking the item in the list where CustomerId is 4.
In either language, notice the shorter syntax with inferred typing. The compiler recognizes that the list contains customers, so it can infer the type of the parameter and the type of return value.
You can combine some of the extension methods to form more complex statements.
In C#:
var query = custList.FindAll(c =>
c.LastName.StartsWith(“K”)).OrderBy(c => c.FirstName));
In VB:
Dim query = custList.FindAll(Function(c) _
c.LastName.StartsWith(“K”)). _
OrderBy(Function(c) c.FirstName))
This code finds all of the entries that match the first lambda expression, basically all customers with a last name that begins with “K”. The code then performs an OrderBy using the second lambda expression, basically sorting the resulting list by first name.
The above examples demonstrate single-line lambdas. You can also use multi-line lambdas as shown in the example below.
In C#:
var foundCustomer =
custList.FirstOrDefault(c =>
{
Debug.WriteLine(c.LastName);
if (c.CustomerId == 4)
return true;
else
return false;
});
In VB:
Not available in VB9, coming in VB10.
Multi-line lambda expressions require the standard {} syntax to define the statement block. Whereas single-line lambda expressions automatically handle the return value for you, you have to handle it yourself in multi-line lambda expressions.
Enjoy!
A delegate is an object that holds a reference to a method with a particular parameter list and return type.
It is basically like an object-oriented, type-safe function pointer.
Delegates basically make it possible to treat methods as entities. You can then assign a delegate to a variable or pass it as a parameter.
The classic delegate example uses events.
In C#:
HelloButton.Click += new EventHandler(HelloButton_Click);
Or the short-cut version of this code:
HelloButton.Click += HelloButton_Click;
This passes the HelloButton_Click method to a new EventHandler delegate.
In VB:
AddHandler HelloButton.Click, AddressOf HelloButton_Click
In VB, the AddressOf assigns the address of the HelloButton_Click method to the delegate.
Instead of using a named method for the delegate (in this example, a HelloButton_Click method), you can use a lambda expression.
In C#:
HelloButton.Click += (s, ev) =>
MessageBox.Show("Hello World");
In VB:
AddHandler HelloButton.Click, Function(s, ev) _
MessageBox.Show("Hello World")
In this case the lambda expression has two parameters: s (sender) and ev (eventArgs). When the Click event is generated on the HelloButton, the code displays the MessageBox.
You can use a lambda expression (inline function) anywhere a delegate is required. However, if the function requires more than a few lines of code, a named method is the preferred and recommended technique.
Enjoy!
In this prior post, I detailed how to build lists of things using a generic List<T>. Once you have a list, you may need to find items in the list. There are several ways to accomplish this, but using lambda expressions is the most concise.
[To begin with an overview of lambda expressions, start here.]
For example, here is how you find an item in a generic list using a for/each statement.
In C#:
Customer foundCustomer = null;
foreach (var c in custList)
{
if (c.CustomerId == 4)
{
foundCustomer = c;
break;
}
}
Debug.WriteLine(foundCustomer);
In VB:
Dim foundCustomer As Customer = Nothing
For Each c As Customer In custList
If c.CustomerId = 4 Then
foundCustomer = c
Exit For
End If
Next
Debug.WriteLine(foundCustomer)
Notice the amount of code required to loop through each item in the list and find the one with a particular customer Id.
You may have heard about language integrated query (LINQ) and how you can use it to search a list.
In C#:
Customer foundCustomer = null;
var query = from c in custList
where c.CustomerId == 4
select c;
foundCustomer = query.FirstOrDefault();
Debug.WriteLine(foundCustomer);
In VB:
Dim foundCustomer As Customer = Nothing
Dim query = From c As Customer In custList _
Where c.CustomerId = 4 _
Select c
foundCustomer = query.FirstOrDefault()
Debug.WriteLine(foundCustomer)
So LINQ is cool, but the code does not seem much shorter.
Now let’s look at using lambda expressions to find the item in the list.
In C#:
Customer foundCustomer = null;
foundCustomer = custList.FirstOrDefault(c =>
c.CustomerId == 4);
Debug.WriteLine(foundCustomer); The lambda expression syntax in C# looks like this:
c => c.CustomerId == 4
The code begins with the set of parameters to the lambda expression. The => is the “goes to” or lambda operator. The remainder of the code is the expression itself. In this case, checking for the item in the list where CustomerId is 4.
In VB:
Dim foundCustomer As Customer = Nothing
foundCustomer = custList.FirstOrDefault(Function(c)
c.CustomerId = 4)
Debug.WriteLine(foundCustomer)
The lambda expression syntax in VB looks like this:
Function(c) c.CustomerId = 4
The code begins with the word “Function” along with the set of parameters to the lambda expression. The remainder of the code is the expression itself. In this case, checking the item in the list where CustomerId is 4.
.NET 3.5 added a large list of extension methods on the Enumerable class. Any object that implements IEnumerable or IEnumerable<T> (basically any object you can do a for/each over) can use these methods. Many of these extension methods (such as the FirstOrDefault method shown in the above example) support lambda expressions.
The FirstOrDefault extension method of the Enumerable class returns the first item in the list or the default value for the object. If you pass it a lambda expression, it returns the first item in the list that matches the Boolean expression.
Enjoy!
My presentation at our local Code Camp was fun. I covered a lot of material and had a GREAT audience. Several people have asked for the slide information in my blog. So this is the start of several posts on lambda expressions.
In addition, I wrote an article on lambda expressions that should appear in the Jan/Feb 2010 issue of Code Magazine. I’ll post the link as soon as its published.
Lambda expressions are unnamed, inline functions. They are new in Visual Basic 9 and C# 3.0 (VS 2008). You can use a lambda expression anywhere a delegate is required. For more information on delegates, see this post.
Here are an additional set of posts that cover the slides and information from my talk:
Enjoy!
More Posts
Next page »