DJ's Blog

David Jeavons' Blog at vbCity

vbCity Blogs moved to:
http://cs.vbcity.com/blogs
  Home :: Syndication  :: Login

OctNovember 2009Dec
SMTWTFS
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

Archives

Blogs I read

Monday, January 21, 2008 #

I have only just recently had the time to play with the new features available in VS 2008 and one of the first things that I thought I would take a look at were Extension Methods.

In a nutshell, extension methods allow you to attach a method onto any .NET type and utilise that method as if it was part of the type out of the box. If you consider the String type, there are many methods attached to the String type that allow you to retrieve it's length, convert the string to upper or lower case, determine if it contains a specific value and so on. However, as with most things in life, there is always something missing. For example, it would be nice if we could proper case the string or determine if the string contained a valid value such as an email address. In the past, this type of functionality would be left to a helper class that we as developers would create ourselves.

However, with the introduction of extension methods, we can now turn our helper class methods into extension methods of the necessary type and use those methods in the same way that we would any method of the native .NET type.

To create an extension method in VB 9 we must use a Module as all extension methods must be shared, also the method must be decorated with the Extension attribute. So taking the two examples above (proper casing a string and determining if a string is a valid email address format) we might create a module called "StringExtensions" as follows:

Option Strict On
 
Imports System.Runtime.CompilerServices
 
Namespace MyExtensions
 
    Module StringExtensions
 
         _
        Public Function ToProperCase(ByVal s As String) As String
 
            Dim titleCase As System.Globalization.TextInfo = New System.Globalization.CultureInfo("en-GB", False).TextInfo
            Return titleCase.ToTitleCase(s)
 
        End Function
 
         _
        Public Function IsValidEmailAddress(ByVal s As String) As Boolean
 
            Dim regEx As New System.Text.RegularExpressions.Regex( _
                "^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$", _
                Text.RegularExpressions.RegexOptions.IgnoreCase)
            Return regEx.IsMatch(s)
 
        End Function
 
    End Module
 
End Namespace
 

Note that in the two method examples above, the first argument (and only argument in these examples) is of type string, this is because the first argument of any extension method must be of the type that you are extending.

Now that we have this extension method module, all that we need to do in order to utilise it is import the necessary namespace into our declaring code and utilise the new methods:

Option Strict On
 
Imports ConsoleApplication1.MyExtensions.StringExtensions
 
Module Module1
 
    Sub Main()
 
        'Output a proper case string
        Console.WriteLine("joe bloggs".ToProperCase)
 
        'Test for valid email address
        Console.WriteLine("joe.bloggs@somedomain.com".IsValidEmailAddress.ToString) 'Returns True
        Console.WriteLine("joe.bloggs-somedomain.com".IsValidEmailAddress.ToString) 'Returns False
 
        Console.ReadLine()
 
    End Sub
 
End Module
 

Note also that these extension methods appear in Intellisense just as any other method of a type would, which makes this easier for developers of a team to discover new type methods:

 


Intellisense showing new Extension Methods

Another area where I think extension methods will prove extremely useful is when wishing to extend a custom class without creating a new version or inheriting from an existing version in order to add extra functionality.

posted @ 8:36 PM | Feedback (0)

I am not sure if this is old hat or not, but I regularly use the Copy Source As HTML addin in Visual Studio 2005 to post nicely formatted code samples. However, I have now got a new laptop loaded with Vista and VS 2008 and to my horror, my old install package of this great tool would not install as I did not have VS 2005 installed. I checked out Google and saw a number of articles that explained how you can get your VS 2005 addins to work with VS 2008 but they seemed like a bit of an effort. However, I then came across this post which has a link to a zip file that contains the necessary files to get this great tool working in VS 2008. Simply extract to the correct folder, restart VS 2008 and voila. Nice and simple :)

posted @ 8:11 PM | Feedback (1)

Tuesday, July 10, 2007 #

I was very lucky to attend the Metallica "Sick of the Studio Tour" on Sunday 8th July 2007 at Wembley Stadium, I was even luckier to be watching it from the comfort of Microsoft's Executive Box. There were a number of people there ranging from Microsoft Marketing people to Microsoft Student Partners. I also got to meet Tony Rogerson (a fellow MVP) and Daniel Moth.

It was the first time that I have been to Wembley since it has been rebuilt and I was extremely impressed. I had been a couple of times when I was younger and it still hasn't lost that feeling of grandeur when you are walking up to it.

Metallica were awesome (as I expected) and the support bands (Mastodon, HIM and Bullet For My Valentine) were pretty good, although to be honest, it was the first time that I had heard their music. Below are some photos that I took, click to view a larger version.

 

posted @ 9:00 AM | Feedback (6)

Friday, June 22, 2007 #

I have recently been trimming down View State from some pages in an ASP.NET application and was looking around for tools that could help me decide where the majority of the View State was coming from. I have found some Gems and figured I would list them here in one place:
 
 
ASP.NET ViewState Helper Homepage
 
This application can be downloaded either as a seperate Windows Application or as a Fiddler extension and is by far the better tool that I came across. The reason I like this tool the most is that it only concerns itself with aiding you in cutting down your page size, it doesn't come with any other bells and whistles. It simply displays a grid showing you the total page size, total view state size and then a percentage of both the view state and markup sizes that constitue the overall page size. You can then double click on a row in the grid that contains view state in order to see the view state decoded or in it's hierarchical state. This is an excellent tool and one that I would recommend.
 
ViewStateAnalyzer Homepage
 
When I first came across this via Scott Guthrie's Blog I thought that this would the tool I was looking for, unfortunately I didn't get on so well with this tool as it is a bit fiddly to use and does not give me the information that I require in an easy to understand format. Don't get me wrong, I am only basing my opinions on what my requirements were at the time and this tool may well be very useful for others so I certainly recommend checking it out. However, the big downside for me is that this tool only seems to work when your ASP.NET applications are running using the built-in web server (formerly known as Cassini) and not from applications running on IIS as it navigates to an address which is similar to the page you are looking at only with a ".vsax" extension and of course IIS spits out a 404.
 
Nikhil's Web Development Helper Homepage
 
I have used this tool quite a lot in the past and it is a great all purpose tool allowing you to do many things such as inspect the DOM of the page and view tracing and view state information. In order to use this tool to view ASP.NET information it must be installed as an HTTP Module (done by configuring the web.config file). The only problem I had with this tool is that sometimes the ASP.NET specific tools would stop working, I am not sure why and when it does work it is very useful but this is what led me to search for other view state tools.
 
View State Decoder 2.1 Homepage
 
This tool is similar to the ASP.NET ViewState Helper application in that it is an external Windows Application and it only concerns itself with View State, showing you the raw, decoded and hierarchical views. However, I could not get this tool to decode any view state I pointed it too so needless to say I cannot really comment on how good it is although I do like the fact that it is not bloated with loads of functionality.
posted @ 8:44 AM | Feedback (1)

Tuesday, September 26, 2006 #

I have been experiencing a bit of a problem with Visual Studio 2005 lately which has had me perplexed for some time. When I create a new Windows or Console Application, Visual Studio goes through its motions and I am presented with either the forms designer or the standard module based on the type of project I chose. However, as soon as I hit the F5 button (no code modifications made) the project builds and then does absolutely nothing. The strange thing is that my main Web Site project is not affected by this behaviour, nor indeed is any other new web site projects. Yesterday, I finally got around to looking into this problem more thoroughly and found the darndest thing. The problem appears to be related to my Kensington Mouse (yes, you heard right), my mouse drivers were stopping my Windows or Console applications from building! So after uninstalling the mouse drivers, installing the standard Microsoft drivers and a reboot later, Visual Studio 2005 started to behave itself again.

Who would have thought...?

posted @ 9:04 AM

Thursday, July 13, 2006 #

I am currently working on converting my Companies website from Classic ASP and ASP.NET 1.1 to ASP.NET 2.0. We originally started converting most of our Administrative products from Classic ASP to ASP.NET 1.1 and this went very smoothly and worked fine. The reason we chose the Administrative products first is that it was less risky as users would not be faced with any code that may be broken and it is easier to talk with our staff than it is with clients in relation to technical problems.

As soon as ASP.NET 2.0 was released we decided to convert from ASP.NET 1.1 to 2.0 and then continue the rest of the conversion in ASP.NET 2.0. Again, this was fine and everything was working smoothly. Now that we were more confident, we shipped a new product on our Website which was for use by our clients. This product is simply a Media Gallery where our clients can view photos and other media content of interest to them and uses some sophisticated searching mechanisms to make the product more unique. This is when problems started to arise as our staff upload images very frequently. We had in place a system whereby folders would be created for every "n" number of images to keep the number of files within a single folder to a reasonable amount. Once this product had been deployed and was being used more and more regularly, our Administrative users started getting session timeouts at irregular intervals and we simply didn't know what was causing the problem.

Originally we thought that it was to do with our refresher technique (the refresher simply keeps the session alive) but this seemed to be working fine. So I started doing some research (still believing the problem to be with session timeouts) and couldn't find anything that explained the problem. I did however find other people that had experienced the same problem but answers to their posts seemed rather vague. One thing that I did learn however from this research is that ASP.NET 2.0 uses a "File Change Notification" (FCN) technique to determine when files have changed and then re-compiles the changed files when they are next hit by a user and serves the previous file from it's cache to those users still using the original file. I thought that this was it, and looked at how I can overcome this problem, but after more research I found that ASP.NET 2.0 only restarts the application after 15 files have been changed (this can be modified in the machine.config file using the numRecompilesBeforeAppRestart setting) and this didn't really fit the problems that we were experiencing.

Now that I knew about the FCN I decided to implement some debugging techniques that would hopefully help me out in finding the real cause of the problem. The first thing I did was to add a small piece of code to the Global.Asax's Application_End event that would e-mail me each time the application restarted. Then I also used a program that would monitor the website directory for any changes and log them to a list box and text file. I used my FileSystemWatcher demo program from a FAQ I wrote awhile ago. When I received the first e-mail notifying me that the application had restarted, I used the date and time value I had put in the body of the e-mail and tried to match it to an entry in my monitoring program, and lo and behold, there was indeed an entry. However, the entry was a little confusing at first as it wasn't a file change, instead it was a folder that had been renamed. I left this going for a day and each e-mail I got back matched to entries in my monitoring program showing folders either being renamed or deleted. I then ran some tests on my development server and each time I created and then deleted a folder, my development server would restart the application. To make things worse, we use Macromedia Dreamweaver for Classic ASP and when synchronising files between the development server and the live server, Macromedia Dreamweaver creates a temporary folder, read's it's timestamp and then deletes the folder hence another application restart (it does this as it has no way of reading the timestamp on the server for synchronisation purposes). This certainly explained why the restarts were so irregular.

At least now I knew why it was happening, but I still didn't know how to fix it, until I stumbled on this blog entry by Todd Carter. It explains the problem in detail and also a workaround (not pretty but effective) using the Linkd command line utility to create an NTFS Junction folder. Apparently Junction folders do not alert the FCN to changes so you can create, rename and delete folders to your heart's content without having your application restart. I originally thought however that I would just create a Junction folder for the entire website folder, but alas, you can't do that as the application will still restart, instead, you need to create Junctions for each folder that you expect to change frequently, which probably won't be many and in my case ended up being four folders at the moment. The technique appears to work great as I haven't had an application restart for a few days now on a live server hit thousands of times a day. 

Hope this information proves useful.

posted @ 9:21 AM

Monday, July 03, 2006 #

Well, I must have spent about an hour today trying to figure out something that I assumed would be pretty trivial, in fact it was in the end but you know how it goes.

I was creating a simple registration page for a website which requires that the user agrees to the Terms and Conditions of the site before they can submit their registration details. To begin with, I had a check box that the user would have to tick in order to state that they agreed and only when this check box was checked would the submit button be enabled, however, as I had disabled the submit button on the load of the page, all other required field validators stopped working. I assume as the submit button was disabled, ASP.NET didn't feel the need to continue wiring up the validation code necessary. So I thought that I would use one of the validation controls to ensure that the check box was checked thus no need to disable the submit button.

After a little research, I found that the CustomValidator control would do the job for me, but nearly all of the examples I found seemed to either suggest that you had to write code in your code behind/beside file to register the necessary javascript on the page which I thought was a bit odd, or they just seemed overly complex. After a little playing around with various code snippets, I came up with what I thought was rather simple and not overly complex. Shame I didn't find it in the first place, it would have saved me a fair bit of time.

To test this out, create a new web form file and add a check box to the page named "chkTandCs", then add a CustomValidator control next to it and finally a button. In the source of the web form, add the following javascript function to the head section:

<script language="javascript" type="text/javascript">
    function
ValidateTandCs(source, args)

    {

        args.IsValid = document.getElementById(
'<%= chkTandCs.ClientID %><%= chkTandCs.ClientID %>').checked;

    }

script>

Now, modify your CustomValidator control so that it reads:

<asp:CustomValidator ID="valTandCs" ClientValidationFunction="ValidateTandCs" runat="server" ErrorMessage="Please accept Terms and Conditions before submitting.">asp:CustomValidator>

Note the ClientValidationFunction property is set to the javascript function ValidateTandCs. If the check box is checked then the function in effect returns True and the page is posted, otherwise, the ErrorMessage property of the CustomValidator is displayed and the page is not posted. This works in exactly the same way as a normal RequiredFieldValidator but allows you to validate a check box. In essence, you could use this technique to validate any server side control.

To prove that it definitely worked, I added the following code to the click event of the button:

Response.Write("Page posted back")

Which only writes out to the page once it is posted to the server.

I certainly learnt something new today :)

posted @ 11:10 PM

Wednesday, June 21, 2006 #

This may be old hat to some, but I only found out about this neat little feature of VS 2005 yesterday and thought it was absolutely the best thing since sliced bread.

When you are debugging your code and you want to see the contents of a DataSet or a DataTable, one way is to use the Immediate Window and start entering commands such as "?myDataTable.Rows(0)(0).ToString" to read the first field in the first row etc. at least this is the way that I have been debugging programs in the past.

Yesterday I was having a small problem getting some code to work and was using my normal debugging techniques when my colleague said to me "I'm sure theres a function in 2005 that shows you the contents of a DataSet or DataTable". I of course laughed at him and called him a Liar (actually, I said worse than that but it has no place here), but he swore it was true and so I added a breakpoint on my DataTable variable and when the breakpoint hit, I hovered my mouse over the DataTable ready to prove that I was indeed right and he obviously had no idea what he was talking about when he then triumphantly pointed at the little magnifying glass in the quick watch tooltip:

 

So I clicked on this magnifying glass thinking that it probably didn't do much (I had never noticed it before) when it came up with the menu option "DataSet Visualiser":

 

Then clicking on the menu option produced the following window:

which as you can see, shows the entire contents of the DataTable that I was working with. The other cool feature is that if you are using a DataSet that contains many tables, then the Table drop down will contain the names of all tables within the DataSet and you only need change the Table for it to then refresh the grid and show the contents of the selected table. Neat.

You also have the same functionality when performing a Quick Watch or when adding your variable to the Watch Window.

So after my initial "Wow" moment, I was left with only one thing to do, apologise profusely to my colleague and promise to listen to him in the future.

posted @ 9:15 AM

Thursday, March 09, 2006 #

There are many times when you need to display a large amount of data to a user. When this need arises, you could of course use a DataGrid and make use of the in-built paging mechanism which makes paging a breeze. However, what if you can't use a DataGrid? Maybe the data you are displaying does not fit the structure of a DataGrid. Fortunately, we can borrow the DataGrid's paging mechanism and use it to create our own paging control which will allow us to add paging capabilities to a wider range of controls.

This post aims to give you an alternative that will allow you to create your own custom paging control which can be bound to any control that supports the IEnumerable Interface. Another goal of this control is to allow for the paging of any data that again supports the IEnumerable interface. So rather than only paging data from a Database (through the use of a DataTable or DataView), you can also bind an ArrayList for example to the paging control and page through the contents of the ArrayList or even create your own specialised class' that implements the IEnumerable interface and page through that.

Create the User Control

First, we need to create the user control, so add a new User Control item to your project and name it "Paging". Then add the following controls (you may want to add them to a table or div, the choice is yours):

Control TypeIDText
LinkButtonlkbMoveFirstMove First
LinkButtonlkbMovePreviousMove Previous
LabellblPageInformation 
LinkButtonlkbMoveNextMove Next
LinkButtonlkbMoveLastMove Last

Add the Paging Code

Copy the following code into the code-behind file of the Paging control:

Option Strict On

 

Partial Class paging

Inherits System.Web.UI.UserControl

 

'Member variables

Private _dataSource As IEnumerable

Private _pageSize As Int32 = 10

Private _pageNumber As Int32 = 0

Private _allowPaging As Boolean = True

Private _pageCount As Int32 = 0

 

Private pageSource As PagedDataSource 'Provides the paging functionality.

 

'An event that is raised each time the page is changed.

Public Event PageIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)

 

Public Property DataSource() As IEnumerable

    Get

        Return _dataSource

    End Get

    Set(ByVal value As IEnumerable)

        _dataSource = value

    End Set

End Property

 

Public Property PageSize() As Int32

    Get

        Return _pageSize

    End Get

    Set(ByVal value As Int32)

        _pageSize = value

        'Store the _pageSize value in ViewState

        ViewState("PageSize") = _pageSize

    End Set

End Property

 

Public Property PageNumber() As Int32

    Get

        Return _pageNumber

    End Get

    Set(ByVal value As Int32)

        _pageNumber = value

        'Store the _pageNumber value in ViewState

        ViewState("PageNumber") = _pageNumber

    End Set

End Property

 

Public ReadOnly Property PageCount() As Int32

    Get

        Return _pageCount

    End Get

End Property

 

Public Property AllowPaging() As Boolean

    Get

        Return _allowPaging

    End Get

    Set(ByVal value As Boolean)

        _allowPaging = value

        'Store the _allowPaging value in ViewState

        ViewState("AllowPaging") = _allowPaging

    End Set

End Property

 

Private Sub Paging()

 

    'Create a new instance of the pageSource if required

    If pageSource Is Nothing Then pageSource = New PagedDataSource

 

    'Setup the pageSource

    With pageSource

 

        .DataSource = _dataSource

        .PageSize = _pageSize

        .AllowPaging = _allowPaging

 

        If _pageNumber > .PageCount Then

            Throw New ArgumentOutOfRangeException

        Else

            .CurrentPageIndex = _pageNumber

        End If

 

        'Display page information

        lblPageInformation.Text = "Page " & (.CurrentPageIndex + 1).ToString & " of " & .PageCount.ToString

 

        'Enable/Disable the navigation buttons based on where we are in the paging source.

        lkbMoveFirst.Enabled = Not .IsFirstPage

        lkbMovePrevious.Enabled = Not .IsFirstPage

        lkbMoveNext.Enabled = Not .IsLastPage

        lkbMoveLast.Enabled = Not .IsLastPage

 

        'Store the current page count in ViewState

        ViewState("PageCount") = .PageCount - 1

 

    End With

 

End Sub

 

Private Sub Navigation_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles _

 lkbMoveFirst.Click, lkbMovePrevious.Click, lkbMoveNext.Click, lkbMoveLast.Click

 

    'Retrieve instance data from ViewState if available

        If ViewState("PageSize") IsNot Nothing Then _pageSize = Int32.Parse(ViewState("PageSize").ToString)

        If ViewState("PageNumber") IsNot Nothing Then _pageNumber = Int32.Parse(ViewState("PageNumber").ToString)

        If ViewState("PageCount") IsNot Nothing Then _pageCount = Int32.Parse(ViewState("PageCount").ToString)

        If ViewState("AllowPaging") IsNot Nothing Then _allowPaging = Boolean.Parse(ViewState("AllowPaging").ToString)

 

                    'Determine which control initiated the Navigation_Click

                    Select Case CType(sender, LinkButton).ID.ToLower

                        Case "lkbmovefirst"

                            _pageNumber = 0

                        Case "lkbmoveprevious"

                            _pageNumber -= 1

                        Case "lkbmovenext"

                            _pageNumber += 1

                        Case "lkbmovelast"

                            _pageNumber = pageCount

                    End Select

 

                    'Update the ViewState values

                    ViewState("PageNumber") = _pageNumber

 

                    'Raise the PageIndexedChanged event

                    RaiseEvent PageIndexChanged(Me, Nothing)

 

End Sub

 

Public Function GetPage() As IEnumerable

 

    Paging()

    Return pageSource

 

End Function

 

End Class

Now to test the control.

Add a new web form and drop the paging control onto the page. You may need to wire up the paging control to your code-behind file using:

Protected WithEvents Paging1 As paging

This first test will show how you can page through data from a database using the Paging control and display that data in a ListBox. I have used the Northwind database in SQL Server for this example. Add the following code to your code-behind file:

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

 

    Dim connection As New System.Data.SqlClient.SqlConnection("Data Source=(local);Initial Catalog=Northwind;UID=xxx;Password=xxx")

    Dim adapter As New System.Data.SqlClient.SqlDataAdapter("SELECT * FROM Customers", connection)

    Dim dt As New System.Data.DataTable

 

    adapter.Fill(dt)

 

    'You can set your desired page size here or accept the default of 10 records.

    Me.Paging1.DataSource = dt.DefaultView

 

    ListBox1.Items.Clear()

 

    'Populate with first n items (n = page size)

    If Not Page.IsPostBack Then

 

        ListBox1.DataSource = Paging1.GetPage

        ListBox1.DataTextField = "ContactName"

        ListBox1.DataValueField = "CustomerID"

        ListBox1.DataBind()

 

    End If

 

End Sub

 

Protected Sub Paging1_PageIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Paging1.PageIndexChanged

 

    ListBox1.DataSource = Paging1.GetPage

    ListBox1.DataTextField = "ContactName"

    ListBox1.DataValueField = "CustomerID"

    ListBox1.DataBind()

 

End Sub

In the above example, you will see that the DataSource of the paging control is set on Page Load and if the page is not a post back then the DataSource of the ListBox is set to the GetPage method of the paging control which returns the IEnumerable interface. Each time the page is changed, the PageIndexChanged event is raised and again, the DataSource of the ListBox is set to the GetPage method of the paging control.

The next example shows how you can perform the same paging but using an ArrayList instead of a DataTable. The same concept applies as in the first example:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

 

    Dim myData As New ArrayList

 

    For i As Int32 = 1 To 100

        myData.Add(i)

    Next

 

    Paging1.DataSource = myData

 

    If Not Page.IsPostBack Then

 

        ListBox1.DataSource = Paging1.GetPage

        ListBox1.DataBind()

 

    End If

 

End Sub

 

Protected Sub Paging1_PageIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Paging1.PageIndexChanged

 

    ListBox1.DataSource = Paging1.GetPage

    ListBox1.DataBind()

 

End Sub

In the above examples, the data has been bound to a ListBox, but as mentioned earlier, you can use the Paging control to bind to any control that supports the IEnumerable interface. Another thing to bear in mind is that you could also request an enumerator from the GetPage method and enumerate the page's data programatically without binding the Paging control to a web control. For example, if the Paging controls DataSource was set to a DataView then the following example, would enumerate through the current page data:

Dim myEnumerator As IEnumerator = Paging1.GetPage.GetEnumerator

Dim dv As Data.DataRowView = Nothing

 

Do While myEnumerator.MoveNext = True

 

    dv = CType(myEnumerator.Current, Data.DataRowView)

 

Loop

I hope this proves useful to somebody.

posted @ 10:39 AM

Wednesday, March 08, 2006 #

Well, having spent the last few days trying to migrate our website from Classic ASP and ASP.NET 1.1 to ASP.NET 2.0, I had just about given up.

A little background. The website I am talking of was written using classic ASP and is the backbone of the company I work for. Now, this website, does not actually need to be upgraded in order to suceed but the development costs and turnaround times of new features would be better served by using ASP.NET. So, about eight months ago, we decided to write all new products for the website in ASP.NET 1.1 with a view to upgrading these products and also classic ASP products to ASP.NET 2.0 when Visual Studio 2005 was released. So far so good. The path we chose was to have a single web project for each product which meant that if a product required updating, we would only need to update the .aspx pages and code behind files and then compile to a single DLL for that product and then upload those changes along with the DLL and the rest would be untouched and therefore, no chance of breaking something unintentionally. This has now worked fine for around five months.

Now came the time for upgrading these products into VS 2005 and I was more than perplexed to find that VS 2005 does not allow the same web project model as VS 2003 meaning that we would have to use the new Website Model which didn't really fit our needs, as most pages would be compiled into a single DLL with possibly support class' being compiled into seperate DLLs, but still not really following the structure that we had implemented and become comfortable with.

Now, you may be wondering where I am going with this ;-) I did a little research (and no doubt most of you would have found the same resources, but to save you the heartache...) and found a great blog entry from Scott Guthrie which details the excellent work that Microsoft has done to correct the issue of omitting this project template from VS 2005 in the first place. There is now a downloadable (albeit, still in beta stage) project template that gives you the same ASP.NET project template that you had in VS 2003 while still benefiting from all of the great enhancements in VS 2005 and the .NET Framework 2.0. I encourage anybody faced with the same problem to check out the First Preview Download of VS 2005 Web Application Project Model Now Available and the download and tutorial links available at Visual Studio 2005 Web Application Project Preview.

I still have some testing to do, but I have successfully migrated the project over to ASP.NET 2.0 in around 3 hours and there is quite a bit of code so I was quite pleased with the time it took, but I am not happy with the fact that I now have ASP.NET 1.1 .aspx and .vb pages that don't make use of partial classes and such sitting in an ASP.NET 2.0 project. You can of course choose to upgrade each project to a Web Application but I found that this didn't work quite so well as you would end up with some page declaration code in your code behind file and some in the .designer file which I am not too happy about. Instead, I have decided to take a longer approach to the migration in that I have created the same structure as I had in VS 2003 and will manually copy the code over bit by bit (admittedly, this should be quite quick due to the fact that of the 11 current products, 4 are support products with no interface and the rest will only require that I create the pages manually) and then copy the markup and code over. I do think I will be turning the XHTML checking off though for this stage of the migration as I don't know that I can face being told that I have hundreds of lines of code that are deprecated or not surrounded in quotes etc. ;)

posted @ 10:32 PM

Monday, February 27, 2006 #

I was looking at the ListView control in VS 2005 today and noticed the new addition of the ListViewGroup object. I didn't immediately know what this was but intellisense's tooltip states that it "Represents a group of items displayed within a ListView control" and this was enough to peak my interest (I'm easily pleased). For those like myself that are unaware of what a ListView group is, the following screen shot from Windows Explorer shows ListViewGroup's in action:


Example of the ListViewGroup in Windows Explorer

So I thought I would have a quick go at adding these ListViewGroup's to a ListView control to see how easy it was. Well, it certainly wasn't quick and I must admit, not very intuitive. Being one of those people that expect something to work in a pre-defined way, I didn't bother looking at the documentation and went straight to coding. I created a ListView control, set it's view mode to details and commenced to add some columns to it. I then declared a new ListViewGroup and then started adding ListViewItem objects to the ListViewGroups Items collection (seemed reasonable enough to me). Once I had added all of the items I wanted to the group, I then added the group to the ListView control using the ListView.Groups.Add method. Rubbing my hands eagerly, I pressed F5 and hey presto, empty ListView :-(

Returning to the code, I checked to ensure I hadn't done anything stupid, like create the ListViewItem's but forget to add them to the Group (never done that before ;)) but the code looked fine. So I gave in and pressed F1 on the ListViewGroup and was surprised at how complex the example in the help documentation seemed. After all, I only wanted to add a couple of groups to a ListView and add some items to each group. So then I decided to create a new project and add the groups and items to the ListView control through the properties window and then looked at the .designer file to see how it had been done and to my surprise, it is relatively simple. The problem I had was in thinking of the ListViewGroup as a collection of ListViewItems and that each ListViewGroup would then be added to the ListView Control when in fact, you simply add the ListViewItem's like you normally would to the ListView control but if you want them to be in a group, you then set the Group property of the ListViewItem to the group that you want the item to be associated to.

So after all of that, I finally had a working example of using ListViewGroup's. Below is the code that I created to give me a similar output to that in the above screen shot. Just copy it into the Form_Load event. Also, beware that the code only works for Windows XP and Windows 2003 (this is what I ascertained from the help documentation).



  'Create the ListView control and add it to the Form's controls collection.
Dim lv As New ListView
lv.Dock = DockStyle.Fill

Me.Controls.Add(lv)

'Setup the ListView control.
With lv
    'Add column headers to the ListView.
    .Columns.Add("Name", 200, HorizontalAlignment.Left)
    .Columns.Add("Type", 150, HorizontalAlignment.Left)
    .Columns.Add("Total Size", 100, HorizontalAlignment.Right)
    .Columns.Add("Free Space", 100, HorizontalAlignment.Right)

    'Allow the columns to be re-ordered at run time
    .AllowColumnReorder = True

    'Set the initial display mode to Details
    .View = View.Details
End With

'Create the "Hard Disk Drives" group
Dim hddGroup As New ListViewGroup("Hard Disk Drives", HorizontalAlignment.Left)
hddGroup.Name = "HDDGroup"

'Create the "Devices with Removable Storage" group
Dim removableGroup As New ListViewGroup("Devices with Removable Storage", HorizontalAlignment.Left)
removableGroup.Name = "RemovableStorage"

'Add the hddGroup and removableGroup ListViewGroups to the ListView control
lv.Groups.Add(hddGroup)
lv.Groups.Add(removableGroup)

'Create a ListViewItem for each drive and add to the ListView control
Dim li As ListViewItem
Dim volumeLabel As String = String.Empty

'Enumerate through the drives collection and add each drive name, type, total size and free space
'to the ListView control. A check is made to determine the type of drive which then determines
'which group to assign to the ListViewItem.
For Each driveName As System.IO.DriveInfo In My.Computer.FileSystem.Drives

    li = New ListViewItem

    If driveName.IsReady = False OrElse driveName.VolumeLabel.Length = 0 _
     Then volumeLabel = driveName.DriveType.ToString Else volumeLabel = driveName.VolumeLabel

    li.Text = volumeLabel & " (" & driveName.Name.Substring(0, 2) & ")"
    li.SubItems.Add(driveName.DriveType.ToString)
    If driveName.IsReady = False Then li.SubItems.Add("0") Else li.SubItems.Add(driveName.TotalSize.ToString)
    If driveName.IsReady = False Then li.SubItems.Add("0") Else li.SubItems.Add(driveName.TotalFreeSpace.ToString)

    'Determine the drive type and assign the relevant group to the current ListViewItem Group property
    Select Case driveName.DriveType
        Case IO.DriveType.Fixed
            li.Group = hddGroup
        Case IO.DriveType.Removable, IO.DriveType.CDRom
            li.Group = removableGroup
    End Select

    lv.Items.Add(li)

Next

posted @ 3:52 PM

Saturday, February 11, 2006 #

I have finally started to look into Visual Studio 2005 in more detail today and something caught my attention on the start page. It was a link to an MSDN TV clip that introduces you to the My.Blogs object that has been created for use with Visual Studio 2005. This object allows you to add blogging capabilities directly into your Windows and ASP.NET projects and also demonstrates how you can extend the My namespace.

I have downloaded the sample code but I had a little trouble installing the Template. However, I was able to easily add a reference to the MyBlogs.dll file and using the following snippet of code (provided by the MSDN documentation) was able to download my current blog entries into a DataGrid.

Dim myFeed As MyBlogs.Feed

myFeed = MyBlogs.Feed.Read(
"http://blogs.vbcity.com/djjeavons/Rss.aspx")
DataGridView1.DataSource = myFeed.Entries

So if anybody is interested in adding blogging capabilities to their application I recommend watching the short introduction, downloading the sample and reading the related articles.

posted @ 2:14 PM

Wednesday, February 08, 2006 #

Late last year my company provided our IT team with a weeks training in Object Orientated programming and design. Much of the course was taken up with UML and methodologies but the final day was more focused on actual programming concepts (which I enjoyed the most). The tutor was a really nice guy and was happy to answer any questions (I guess at a £1,000 a day, I'd answer anybody's questions). As our IT department is relatively small (4 members) the tutor advised us to follow the SCRUM methodology which is a variation on Extreme Programming (XP) and has thus far helped us be more productive than we have normally managed.

He also mentioned a discipline known as Test Driven Development (TDD) which I had never heard of before and as he explained is the practice of writing tests before writing any code and then making those tests succeed. Now, unless you are aware of this methodology, I would expect the same response as I had, "How can you write a test for something that doesn't exist?".

Well, I have recently been thinking about this principle and done a little research and I can really see the benefits. The basic idea is that you write a test using xUnit (NUnit for VB.NET, JUnit for Java, pyUnit for Python and so on) and run that test. This test will then fail (red bar) as there is no code to test. More likely than not however, the code won't even compile as there is no code for the test to run. So to get around this, you create the object that you are testing and add stubs (empty procedures) in order for your code to compile and then watch it fail. Then you go back to the object and have it return what your test expects it to return (in the first phases, this would be simply hardcoding the values to make the test succeed) and run it again, this time it should succeed (green bar). Then you start to refactor your object so that it starts to look more like a piece of production code rather than a slap happy coder having a laugh! All the time, testing to make sure that each set of changes has not broken the initial test.

Now the thing I really like about this approach is that you can write your initial test that uses a non-existant object and enforce some assumptions on how you would like this non-existant object to expose it's interface. This then gives you a really good outline when it comes to actually creating the object and making those tests succeed. Of even more importance is that when an object has to be changed for whatever reason, you have the tests to rely on that will tell you if you have broken anything by implementing those changes.

So now having done some research on this (links at the bottom for anybody interested), I went ahead and downloaded NUnit as I will be using .NET (still trying to learn C# proficiently so may go ahead with that) and also bought a book Test-Driven Development By Example by Kent Beck. Now I'm armed and ready, I just hope I don't have nightmares about red bars (rather nice dreams about green bars ;))

TDD Links I found of interest

posted @ 8:52 PM

Saturday, February 04, 2006 #

Well, I finally plucked up the courage to give blogging a go, with a little motivation from Ged ;)

So what can you expect from this blog? To be honest, I'm not too sure about that myself. Since I was 18 I have always worked for companies developing Windows software (using VB) but now coming up to the ripe old age of 30 (shudder) I have spent the last year working solely on ASP.NET applications. So I guess, you can expect a number of entries to be related to my struggles/successes with web development. You can also expect a few review type entries as I often evaluate software at my company to assess it's worth.

I will also be upgrading to VS 2005 in the next few months which I am greatly looking forward to so there will no doubt be a few entries there as well.

After that short introduction, I feel I have answered my own question :)

posted @ 5:13 PM