Thursday, January 26, 2006

Check this out.

"The A to Z of Programmer Predilictions" is a funny little article that categorizes programmers into various stereotypes, most of which are surprisingly accurate. As I read through the descriptions, I started spotting people in my organization. Though I (and everyone else) can probably fit into a variety of different personas described there, I probably am most like "Zealous Zack." I DO download all of the betas (even at work!) and, when someone blogs about the "Next New Thing," I've got the download started before I've finished reading the post about it.

Speaking of, I need to download the newest WinFX bits...

(via Digg)

posted on Thursday, January 26, 2006 7:41:44 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Tuesday, January 24, 2006

I've been experimenting with the FlowLayoutPanel. There are a few catches to using it that can cause some confusion. In my case, the confusion came from anchoring and/or docking. I was dynamically adding some listviews to my panel to display results of data. There would be one to many listviews depending on the type of report the user requested. Having come from developing in ASP, it is still my first inclination to just create a table for each section and add it. The flow of the HTML would handle the rest. I figured I could get a FlowLayoutPanel and just add controls as needed and get similar functionality.

That was true to a degree; however, anchoring doesn't perform as you might think. If you anchor to the left and right after setting the width, if there is only one control in the panel, it will drop down to a zero width. The actual behavior is that, if you anchor to the left and right, it will assume the width of the widest control already on the FlowLayoutPanel. The same is true if you set the Dock property to Fill. Check out this article on MSDN to see what I mean. The behavior also depends on the FlowDirection property.

Everything works great if your panel isn't going to resize itself. You can just set the first control's width to the width of the panel minus a few pixels and Dock.Fill everything else. If you want it to resize as you resize the form, though, it is looking like you'll have to handle some layout events.

Here's some code to get you started:

Public Class Form1

    Private WithEvents flowPanel As New FlowLayoutPanel()

 

    Public Sub New()

        ' This call is required by the Windows Form Designer.

        InitializeComponent()

 

        ' Add any initialization after the InitializeComponent() call.

 

        ' DON'T FORGET THESE LINES!

        flowPanel.Dock = DockStyle.Fill

        flowPanel.FlowDirection = FlowDirection.TopDown

 

        Me.Controls.Add(flowPanel)

 

        AddListView()

        AddListView()

    End Sub

 

    Private Sub AddListView()

        Dim totalList As New ListView()

        totalList.View = View.Details

 

        ' If first control, then set a width; otherwise, Dock.Fill it.

        If Me.flowPanel.Controls.Count > 0 Then

            totalList.Dock = DockStyle.Fill

        Else

            totalList.Width = Me.flowPanel.Width - 10

        End If

 

        totalList.Columns.AddRange(New ColumnHeader() _

            {GetColumnHeader("Col 1"), _

            GetColumnHeader("Col 2"), _

            GetColumnHeader("Col 3")})

 

        Dim item As ListViewItem = totalList.Items.Add("Row 1")

        item.SubItems.Add("1234.00")

        item.SubItems.Add("5678.00")

 

        item = totalList.Items.Add("Row 1")

        item.SubItems.Add("1234.00")

        item.SubItems.Add("5678.00")

 

        item = totalList.Items.Add("Row 1")

        item.SubItems.Add("1234.00")

        item.SubItems.Add("5678.00")

 

        Me.flowPanel.Controls.Add(totalList)

    End Sub

 

    Private Function GetColumnHeader(ByVal text As String) As ColumnHeader

        Dim col As New ColumnHeader()

        col.Text = text

        Return col

    End Function

 

    Private Sub flow_Layout(ByVal sender As Object, _

        ByVal e As System.Windows.Forms.LayoutEventArgs) _

        Handles flowPanel.Layout

 

        Dim flowLayout As FlowLayoutPanel = DirectCast(sender, FlowLayoutPanel)

        If flowLayout.Controls.Count > 0 Then

            flowLayout.Controls(0).Width = flowLayout.Width - 10

        End If

    End Sub

End Class

Here's MSDN another article that gives some basic information on the FlowLayoutPanel.

posted on Tuesday, January 24, 2006 8:09:23 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Saturday, January 21, 2006
I know many people have seen the excellent Cropper tool for grabbing screenshots. I found another tool very similar to it by the maker of TaskSwitchXP called WinSnap. It gives a few additional features like adding a dropshadow or rotating the image. The good thing is that it is still a very small application. Here is a screenshot I pulled with it:



Cool shadow effect, huh? I'm giving it a try right now. It seems to work well for me so far.

posted on Saturday, January 21, 2006 12:39:15 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Friday, January 20, 2006
I discovered today that the new FtpWebRequest/FtpWebResponse classes might not be the best options for connecting to FTP servers, at least unless you're in control of the FTP server. The classes make some assumptions about the remote FTP server, like the server's file system.

I was working on converting an application that sends files to a customer's FTP server and I thought I would use the FtpWebRequest and FtpWebResponse classes. The problem is that the customer's FTP server is running on VMS! I know, that isn't very common, but the file system in VMS is NOT like Windows or Unix. Folders aren't separated by "\" or "/" so when a change directory (CWD) command is sent, you can't assume that folders are delimited by one of those characters! When you try to list the files in the directory, it sends a CWD command to change directory to the current directory (why, I don't know) with a "/" at the end. Predictably, I get a 550 error back with a "file specification syntax error."

I haven't found a workaround other than coding it myself. If anyone has any suggestions, let me know.


NOTE: I used Ethereal to observe what was being sent and received. It is a great utility for watching network traffic.
posted on Friday, January 20, 2006 4:03:07 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
Here is a little gotcha with some changes to the way that .NET 2.0 handles COM interoperability. You probably won't run into this problem unless you're converting a project from 1.1 to 2.0.

We had a little command line application that took did some background processing for us that was written in 1.1. We moved it over to 2.0 because we wanted to take advantage of the new FTP capabilities in the 2.0 framework (see FtpWebRequest/FtpWebResponse). If you add a reference to a COM object in .NET 1.1, the typical object that you'll create on the managed side will have a "Class" suffix (i.e. MyCoolComObjectClass as opposed to MyCoolComObject). If you convert to 2.0, it doesn't change that code either...

However, you might see an exception like this if you start using it:

"System.InvalidCastException: Unable to cast COM object of type 'System.__ComObject' to class type 'ComLibrary.MyCoolComObjectClass'. COM components that enter the CLR and do not support IProvideClassInfo or that do not have any interop assembly registered will be wrapped in the __ComObject type. Instances of this type cannot be cast to any other class; however they can be cast to interfaces as long as the underlying COM component supports QueryInterface calls for the IID of the interface."

What do you do? Take the class off the end of your COM object (MyCoolComObjectClass -> MyCoolComObject).

That's it.

AUTOMAGICAL!

(Thanks to this forum posting for the info!)

posted on Friday, January 20, 2006 10:57:24 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Wednesday, January 18, 2006
I was curious if anyone knew if Visual Studio 2005 had the capability to highlight or color "User Types" (i.e. classes you write yourself) while coding in Visual Basic. I know that C# has this functionality built in, but it doesn't seem like VB pays any heed to those settings. Here's a screenshot of the specific setting in Visual Studio:



If anyone knows anything about getting that working for VB, I'd appreciate it.

posted on Wednesday, January 18, 2006 1:04:46 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Friday, January 13, 2006

Do you like C-based languages like C, C++, Java, and C#? Or do you like BASIC instead? It doesn't matter what your answer is, though, because the two links below are hilarious either way.

History of the BASIC family of languages
History of the C family of languages

(via Rockford Lhotka)

posted on Friday, January 13, 2006 2:54:49 PM (Central Standard Time, UTC-06:00)  #    Comments [0]

Continuing on my thoughts from yesterday regarding Windows Forms validation, I first began using Michael Weinhardt's validation library on MSDN after doing a project conversion from 1.1 to 2.0, but there were a few things that I personally wanted to do that weren't currently supported, like validation on controls like the DateTimePicker. It would have been quite easy to add support, but I began developing a picture in my mind of a slightly different approach to validation. His solution was very designer oriented, but I wanted a more code-centric approach.

What I came up with was basically a GroupValidator class that took a control and a delegate to a provided validation function. The class took care of calling the validation function by hooking into the Validating event and then setting the appropriate error message. It added the control and delegate to a collection which could then be looped through so that you could check to see if the entire group was valid. It is pretty basic, but it works quite well so far. I'd like to expand it a little bit to add more automation, but it gets the job done right now.

Here's an example of usage:

Public Class Form1

    Private _validator As New GroupValidator()

 

    Public Sub New()

        ' This call is required by the Windows Form Designer.

        InitializeComponent()

 

        ' Add any initialization after the InitializeComponent() call.

        _validator.AddControl(Me.TextBox1, _

            AddressOf IsTextValid, "Text not valid")

        _validator.AddControl(Me.TextBox2, _

            AddressOf IsTextValid, "Test not valid2")

        _validator.AddControl(Me.TextBox3, _

            AddressOf IsTextValid, "Enter something")

        _validator.AddControl(Me.TextBox4, _

            AddressOf IsTextValid, "Please")

    End Sub

 

    Private Function IsTextValid(ByVal c As Control) As Boolean

        If c.Text.Length > 0 Then

            Return True

        Else

            Return False

        End If

    End Function

 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        MessageBox.Show(_validator.IsValid.ToString)

    End Sub

End Class

It is pretty simple as you can see. If you're interested in the code, drop a line and I'll email it or post it.

posted on Friday, January 13, 2006 8:53:27 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, January 12, 2006

I've been doing some research on best practices for validation in Windows Forms, and I came across a nice set of MSDN articles by Michael Weinhardt where he shows how to create a validation framework that is very similar to the validators found in ASP.NET (i.e. required field validator, regular expression validator, etc). It includes container and form validators that basically manage the control validators already on the form. The link to the articles is to the third article in the series, but the download contains all of the source. His code was apparently incorporated into the Genghis framework as well.

I'm interested in something similar for 2.0, but I haven't found anything. I did see an older post from Chris Sells about moving Genghis over to 2.0, but I haven't seen any updates on that. I'm considering doing it myself, but if anyone has any better ideas, I'm open.

posted on Thursday, January 12, 2006 2:07:18 PM (Central Standard Time, UTC-06:00)  #    Comments [0]

After some severe frustration research, I was able to discover how to repro the crash in Visual Studio 2005 yesterday. It is actually quite simple to do. You need a new VB.NET project and two With statements, one nested within the other. That's it. Then you click on the second With object.

Here, I'll show you how!

Public Class Form1

    Public Shared Sub Main()

        Application.Run(New Form1)

    End Sub

 

    Public Sub New()

        ' This call is required by the Windows Form Designer.

        InitializeComponent()

 

        ' Add any initialization after the InitializeComponent() call.

        Dim p As New Person()

        With p

            ' CRASHHERE: If you want to crash, take your mouse and

            ' click inside .StreetAddress.... BOOM!

            With .StreetAddress

                .Street = "123 BOOM"

            End With

        End With

    End Sub

 

    Public Class Person

        Private _streetAddress As New Address

        Public ReadOnly Property StreetAddress() As Address

            Get

                Return _streetAddress

            End Get

        End Property

    End Class

 

    Public Class Address

        Private _street As String

        Public Property Street() As String

            Get

                Return _street

            End Get

            Set(ByVal value As String)

                _street = value

            End Set

        End Property

    End Class

End Class

 

There, that was easy, huh? (In case you're not seeing it, look for the CRASHHERE note.)

Kids, don't try this at home.

Chances are, it will work for you anyway. I just checked with one of my co-workers and it works just fine for him. Great.

posted on Thursday, January 12, 2006 8:07:54 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Wednesday, January 11, 2006

5+ crashes in a row is a little much.

And I wasn't even in the designer. And yes, I rebooted. It still happened.

I don't know exactly what I did to fix it, though. Let's just say heavy use of the save button and having another instance of devenv up and attached to the other process. Just in case I needed to copy and paste a call stack somewhere. Of course, that's when it began working.

Oh well.

NOTE: Don't take this the wrong way. I still love VS2005 as an IDE. However, it still has quite a few issues. The most annoying of which is the flickering while in the designer. And no, I never got that one up in the debugger either.

UPDATE: For more information on this, see my new post here.

posted on Wednesday, January 11, 2006 2:50:25 PM (Central Standard Time, UTC-06:00)  #    Comments [0]