Wednesday, February 15, 2006

Let's say you have the following class:

   51 Public Class Person

   52     Private _name As String

   53 

   54     Public Event NameChanged As EventHandler

   55 

   56     Public Property Name() As String

   57         Get

   58             Return _name

   59         End Get

   60         Set(ByVal value As String)

   61             _name = value

   62             OnNameChanged(EventArgs.Empty)

   63         End Set

   64     End Property

   65 

   66     Protected Sub OnNameChanged(ByValAs EventArgs)

   67         RaiseEvent NameChanged(Me, e)

   68     End Sub

   69 End Class

We've set up the [Property]Changed events so that DataBinding will work correctly. Now, let's assume you want to bind the name property over to the text property of your TextBox control. We'll go the simple data binding route here for simplicity.

    3 Public Class Form1

    4     Private txtName As New TextBox

    5     Private _person As New Person

    6 

    7     Public Sub New()

    8         ' This call is required by the Windows Form Designer.

    9         InitializeComponent()

   10 

   11         ' Add any initialization after the InitializeComponent() call.

   12         Me.Controls.Add(txtName)

   13 

   14         _person.Name = "cool"

   15         txtName.DataBindings.Add("Text", _person, "Name")

   16     End Sub

   17 

   18     Private Sub Form_Click(ByVal sender As ObjectByValAs EventArgs) _

   19         Handles Me.Click

   20         _person.Name = "clicked"

   21     End Sub

   22 End Class

There! Now the txtName will display "clicked" whenever you click on the form. Magic! Now, let's change that Click event like so to see what happens:

   18     Private Sub Form_Click(ByVal sender As ObjectByValAs EventArgs) _

   19         Handles Me.Click

   20 

   21         Dim newPerson As New Person

   22         newPerson.Name = "new person"

   23         _person = newPerson

   24     End Sub

Why would I ever want to do is this way? Well, let's say you're remoting somewhere to get your data and your background thread returns a fully populated object. The easiest thing to do is to just point to the new object... except that it doesn't work.

All we did was change our instance over, but the textbox never changed. Why not? Because of REFERENCES, POINTERS, and MEMORY ADDRESSES! That's why! Check this out:

   18     Private Sub Form_Click(ByVal sender As ObjectByValAs EventArgs) _

   19         Handles Me.Click

   20 

   21         Dim newPerson As New Person

   22         newPerson.Name = "new person"

   23 

   24         Debug.WriteLine("Are references equal? "Object.ReferenceEquals(txtName.DataBindings("Text").DataSource, _person))

   25         _person = newPerson

   26         Debug.WriteLine("Are references equal? "Object.ReferenceEquals(txtName.DataBindings("Text").DataSource, _person))

   27     End Sub

Whoa! The first Debug.Writeline will give you TRUE, but the second will give you FALSE. You see, understanding how references and pointers work is important. The textbox's DataSource is holding onto a reference of the old Person instance. You now have two different instances in memory, whether you like it or not.

What do you do about it? Well, as far as I can tell, you can either update your DataSource reference (it did change after all) or you can move your properties over manually so that your references don't change. I'm open to suggestions on other methods here.

posted on Wednesday, February 15, 2006 1:05:04 PM (Central Standard Time, UTC-06:00)  #    Comments [0]

For those two or three who missed it, Yahoo! released two libraries yesterday: the Yahoo! Design Patterns Library and the Yahoo! User Interface Library. I particularly like the UI library. First of all, it was released under as open source, so as long as you include the copyright at the top, it looks like you can use it. I checked out their JavaScript code and it looks pretty good. It seems that the whole object { name : value }* notation of declaring objects is becoming more popular. It is also becoming much more common to see entire frameworks being developed (I'm thinking of the JavaScript libraries that come with Atlas). Anyway, interesting stuff. It will be a lot easier to add some nice, production quality JavaScript to pages now.

* Instead of:

var newObject = new function () {
   this.name = value;
}

It is:

var newObject = {
   name: value;
}

posted on Wednesday, February 15, 2006 7:53:14 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, February 09, 2006

Now this is different, eh? A post on JavaScript instead of .NET! This is a little trick I came up with to add outerHTML functionality in Firefox. For those who aren't familiar with outerHTML, it is an IE addition to the DOM that will return the element's HTML PLUS it's innerHTML. Is it really needed? No, but it can help with debugging sometimes. Here's the code:

if (document.body.__defineGetter__) {

       if (HTMLElement) {

              var element = HTMLElement.prototype;

              if (element.__defineGetter__) {

                     element.__defineGetter__("outerHTML",

                           function () {

                                  var parent = this.parentNode;

                                  var el = document.createElement(parent.tagName);

                                  el.appendChild(this);

                                  var shtml = el.innerHTML;

                                  parent.appendChild(this);

                                  return shtml;

                           }

                     );

              }

       }

}

This entire thing revolves around the __defineGetter__ method off of objects. To be honest, I don't know if it is standard JavaScript or if it is just a Mozilla extension. It makes extending the DOM a lot easier, though. I probably wouldn't trust this in a production environment, but I wouldn't hesitate to use it for testing.

posted on Thursday, February 09, 2006 1:21:16 PM (Central Standard Time, UTC-06:00)  #    Comments [0]

Rory Blyth, the man who brought us the "steel cage death match" of the Avalon authors, tells us what happens when public speaking goes wrong. The way I see it, if you never get in the car in the first place, you can't ever run someone over. Let someone else do the driving.

(My driving comments were an allusion to his post... I do drive my car each and every day to work... in case you were wondering...)

posted on Thursday, February 09, 2006 7:44:18 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Wednesday, February 08, 2006

Visual Studio Hacks posted a new "Ask the Pros" article detailing some of the pros' favorite keyboard shortcuts. Check it out here. There are quite a few good shortcuts in there, like the Comment and Uncomment code blocks (Ctrl-K-C and Ctrl-K-U respectively). Some of my new favorites have to do with additional functionality provided by snippets in Visual Studio 2005, specifically the Edit.SurroundWith command, which is Ctrl-K-S by default. It makes it a cinch to add code to new regions, much like the Visual Studio 2003 Region add-in. As the article says, a nice way to learn more shortcuts is to check them out in Visual Studio for yourself - under Tools, Options, and Keyboard.

Try them yourself and become a true Keyboard Ninja!

posted on Wednesday, February 08, 2006 7:53:13 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Monday, February 06, 2006

There has been a lot of talk recently about VMware releasing a version of their VMware server product for free. The beta version was released today, though the big news to me is that there are a multitude of free "pre-built, ready-to-run virtual appliances" available for use with VMware server. Of course, as these "appliances" are free, don't expect to see a Windows VM image. It WOULD be a good way to easily play around with different versions of Linux like Red Hat or Ubuntu. I'm curious how Microsoft will respond with their Virtual PC product.

posted on Monday, February 06, 2006 12:43:11 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Friday, February 03, 2006

Check this out.

For those who are unfamiliar, Lisp is a functional language often associated with AI programming. I took an AI class in college and Lisp was the primary language used to explain the AI concepts. It is very cryptic to look at if you haven't ever used it, because it makes heavy use of parentheses. It also makes a lot of use of recursion. If I remember correctly, it doesn't actually have any looping structure (i.e. while, for, etc.) other than making use of recursion. It can really help with looking at common programming problems in a different way.

CORRECTION: After looking over the book just a little bit, it appears that Lisp DOES have loop operators in addition to recursion. I wonder if it was one of those academic things, sort of like how they don't tell you about the STL until you've made it through the data structures class and coded your own linked list, binary search tree, and graph. Oh well.

posted on Friday, February 03, 2006 4:04:14 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Sunday, January 29, 2006

I just finished reading an article from Hacknot that describes the predicament that developers are in while attempting to define a software product's requirements as specified by the user. Here is a quote from the article that I find quite telling:

In their efforts to be "user focused", guided by simplistic notions of "usability", many managers and programmers uncritically accept whatever users tell them as a mandate. "The customer is always right" makes a nice slogan but a poor substitute for critical thought. If you want to deliver a product that is genuinely useful, it is important to moderate the user feedback you receive with your own knowledge of usability principles, and to seek independent confirmation of the information they relate. For it is a fact seldom acknowledged in the text books that users are frequently uninformed, mistaken or deliberately deceptive.

I work in an organization which is highly user focused, as opposed to product focused. Essentially, whatever the customer says goes.

Here is a little background: My employer has been relatively slow in adopting new technologies. A large portion of the software that runs is what might be called "legacy" code (i.e. COBOL, JCL, and even Assembly); however, there is still new development being written in that environment. Thankfully, much of the front-end has been moved to an intranet base. Quite recently, there has even been a push to Windows Forms development with .NET.

The problems that the users have is that they do their business work in three different environments at a bare minimum: green screens, intranet webpages, and Windows applications. When my company first began the move to intranet pages, the user requirements would basically be, "make it look like what we have." They had no idea of what the capabilities were with webpages. The first few webpages all looked just like their green screen counterparts, except that they were black text on a white background, instead of green text on a black background.

Today, with some of our new development in .NET, we're running into the same problem again. The users know webpages and their capabilities, but not those of Windows applications. There is a fundamental misunderstanding about what these new applications are. They want a button for everything, when a toolbar or menustrip might be more appropriate. I've really been encouraging my users to look at examples like Office applications for ideas while thinking about what they want the new software to do. Some might argue that Office applications aren't the best example, but the truth is that Office is one application that the users really know.

As software developers, I really think that, to be user focused, you can't always give the user exactly what they asked for. Alternatives can, and often are, much better in the end. The difficult part is communicating that. Is this a common scenario for others? (I know it is!)

posted on Sunday, January 29, 2006 7:53:16 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 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]