Erik Porter's Blog

Life and Development at Microsoft and Other Technology Discussions

News

    July 2003 - Posts

    The HC Update

    Just a little bit on what I've been doing lately...

    Last week my gf and I went camping.  Lots of good and absolutely horrible experiences.  A couple highlights:

    Two days ago, I gave my presentation “Getting Started with WindowsForms” at the Northwest Ohio .NET User Group in Toledo.  The crowd was small, but overall I think it went well.  I still feel my presentations aren't quite entertaining enough.  It's really hard to get across how excited I am about the technologies in addition to getting everyone as excited about it as I am.  I saw some smiles and nods and people really thinking about everything so that's good, but I also saw a few people about nodding off, which both are my fault!  ;)  One thing I really liked about this presentation is its originality.  Most presentations I've looked at about .NET (but definitely not all) are very marketing oriented.  I wrote my presentation from scratch, making sure to cover everything that I thought was important from the work I've done over the last year or so with WindowsForms.  It's also all the things I would've liked to hear about WindowsForms when I was first learning.  I'm brutally honest about what I talk about also, so if there's something in WindowsForms that I love or hate, you're going to hear a lot about it and hopefully everyone finds that useful.  Be sure to check out the slides and demos if you're interested (sorry if it's really slow to download...you're pulling from my “massive” cable modem upload  ;)) and also the Special Thanks slide in the PPT.  I mention who I got some info from and also who designed my slides.

    On August 19th, I will be giving the same presentation at the Michiana Area .NET Users Group in South Bend.  Looking forward to that!  :)

    Also in the works are two new articles for Advisor.  “Making the Switch from Access to MSDE” and “Strongly Typed Collections and WindowsForms DataBinding”.  These aren't finished so the titles and content are subject to change.

    Also as Duncan hints (at where my blog is listed on MSDN), I will soon be a book author, having written a couple chapters for his new book.

    More Bang For Your Data Acces Buck

    Adam gives a good tip on how to squeeze a bit more out of the DataReader.  Great tip!  *thumbsup*

    If you look at his code, you'll notice that you have to access the field you want by Index, which isn't exactly “programmer friendly”.  The easiest way to work with it, is to use the GetOrdinal Method of the DataReader to lookup the Index for you.

    Under the covers, when you use the Indexer to access a field value by the field name, the Framework is calling GetOrdinal to lookup the Index and then accessing the field by Index, so it's recommended that if you're going to access a field more than once in the lifetime of the DataReader, you should call GetOrdinal and store the Integer in a variable and everytime you want to access the field call the .GetXXX Method or the Indexer, passing in the Column Index for best performance.

    Posted: Jul 31 2003, 01:01 AM by HumanCompiler | with no comments
    Filed under: ,
    Assembly Loading Info

    Great entry from Suzanne Cook.

    <highlights>
         <highlight>
              <info>
                   <![CDATA[
    In v1.1 and v2.0, Frameworks assemblies are unified. That means that the version of those assemblies that you request is ignored - you get the version that matches the loaded CLR. This only applies when the assembly is loaded by version - that is, by assembly display name, or static reference (AssemblyRef in the CLR metadata).]]>
              </info>
              <comment>
                   <![CDATA[
    Holy cow!  This is news to me.  Very interesting and actually really cool.  Great tidbit of information there!  :)]]>
              </comment>
         </highlight>
         <highlight>
              <info>
                   <![CDATA[
    However, do not rely on this behavior. You should still fully-specify assembly references with the correct version. That's just good practice, in general. Besides, if your assembly is loaded in a CLR later than v2.0, those references may not be unified, so you may get unexpected behavior.]]>
              </info>
              <comment>
                   <![CDATA[
    Excellent, excellent tip!  <b>*thumbsup*</b>]]>
              </comment>
         </highlight>
    </highlights>

    Again, Great entry...thanks Suzanne!  :)

    Edit and Continue Madness

    No Edit and Continue in C# is all the madness now.

    The C# team has all kinds of other stuff they work on that is probably more important than E 'n' C, but I'm still with everyone that is all for it in C#.  However, productivity has never really seemed to be the main focus of C#, so it makes sense that something that can help you save time not getting in there is appropriate.  ;)

    I am constantly searching for reasons to use C# (other than translating all my demos), but alas...it appears Whidbey will help me reaffirm my faith in VB.NET.  Not just because of E 'n' C not being in C#, but because of all the cool and great new items that are going to be in VB.NET  :D

    Posted: Jul 30 2003, 03:39 PM by HumanCompiler | with 2 comment(s)
    Filed under:
    Quick WindowsForms Tip

    Ok, I saw basically the same question posted twice over at GDN and I just don't understand.  Instead of complaining about it, I'll post it as a quick tip.

    If you have a Form that needs to check a certain condition when it's loading and see if it should continue to load to close itself, don't bother.  When programming, you should be thinking about every little drop of efficiency that you can squeeze out of your programs no matter how small.  Don't get lazy just because it's not a big deal and won't use many resources.  Do it right the first time.  I'm not perfect at this by any means, but if you always strive for perfection, you'll be one step closer.

    So if you have a Form that needs to do that, and for some reason, Me.Close isn't working...don't keep searching for an answer or a work around...sit back and think: Is what I'm doing the best and most efficient way to do it anyway?  More times than not, the answer will be no and there is an easier way to do what you want and skip over your problem all together in the first place.

    In this particular case, the answer is to not load up the form at all.  Check for the condition before loading up the Form.  If it is not met, then show a message and don't even load up the Form at all.  If the condition is met, load up the Form and execute whatever code you were going to execute if the condition was met in the first place.

    Sorry this was so long for such a small solution.  I just sometimes get a little irked (sp?).  Wait...Eriked?  Woohoo, I'm a verb!

    Anyway, the best advice I can ever give is to think, think, think...all the time, no exceptions.  Think about what you're doing.  Think about what you've already done.  Keep the end result in your head all the time and constantly consider how what you're doing right now will affect the end result in a positive or negative way.

    *gets up on soap box*

    Master the art of evaluating situations, conditions, problems that need solving and there won't be a damn thing you can't do!

    *gets down off of soap box*

    WindowsForms DataBinding

    I'm in the middle of working on my presentation (yes, that's right, I'm not done yet...I'm a procrastinator and love working under pressure) and happened to have just blogged about Strongly Typed Collections and thought of something I had done in a project a while back related to DataBinding in WindowsForms.  Even though it's extremely simple, this will hopefully show you that DataBinding in WindowsForms is extremely powerful.

    First off, create a new Form, slap a ComboBox in the middle and name it "cmbPeople".  Then take the Collection I created in my last post called "PeopleList" and plop it into your Form (the declaration and filling of it anyway).  Now when the Form loads, simply put this line of code:

    cmbPeople.DataSource = PeopleList

    Now, what this actually does is bind the objects themselves to the Items Collection of the ComboBox.  If you're used to ASP.NET, this is quite a bit different.  In WebForms, when you DataBind, ASP.NET actually takes your Collection, DataTable, DataReader, etc and builds the appropriate child controls and adds them into the Items Collection for whatever Control you're binding to and then actually has no reference to the original bound object.

    This idea should trigger a few things in your mind.  What about the DataReader?  It is connected only, read only & forward only data.  Well, if you were wondering if it could be bound to in WindowsForms, you thought right.  It definitely CAN NOT be bound to, because again, in WindowsForms, you're binding to the actual objects and if you close a DataReader, then all the data is no longer there.  The other big reason you wouldn't be able to bind to a DataReader is that only instances that Implement IList can be bound to in WindowsForms.

    Ok, so now that we've gotten that out of the way, how do we tell our ComboBox what data to display from our DataSource that we set earlier?  There are a couple different ways.  First, let's talk about the easier yet more disjointed way to do it.

    Being that the "Person" class has a FirstName and LastName Property, more than likely we'd want to display first name, then a space, then the last name.  This can be done really easily by overriding the ToString Function like so:

    Public Overrides Function ToString() As String
        
    Return Me.FirstName & " " & Me
    .LastName
    End Function

    So now if we run our little Form, you should see in the ComboBox all the Items that were adding in the PeopleList Collection by their First and Last Name.

    Now for kicks (and to demonstrate why binding to the actual objects is so powerful) let's display a message box showing the ID of the currently selected Person in the ComboBox:

    Private Sub cmbPeople_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles cmbPeople.SelectedIndexChanged
         MessageBox.Show(DirectCast
    (cmbPeople.SelectedItem, Person).ID.ToString)
    End Sub

    So as you can see, the SelectedItem itself IS the actual Person object in our People Collection that we're bound to, so you we can just cast it and grab whatever Property we want (or anything else for that matter [call a method, grab a Public Member Variable, etc]).  How cool is that?  Try binding to a DataTable.  You'll find that the SelectedItem holds the current DataRowView.

    In ASP.NET, to access the data again, you'd have to actually resetup the data (depending on what you're using, such as a DataTable, you'd have to requery your DB) and use the SelectedIndex to go find the correct Item to get at whatever data you needed.  I'm not biased or anything, I swear.  I really do love ASP.NET, just pointing out some key advantages here.

    Great, that was easy, now how about a little "tighter" way of binding to our data.  There are two other Properties we can take advantage of to bind a little tighter to our data.  DisplayMember and ValueMember.  If you're used to ASP.NET, these Properties are similar to DataTextField and DataValueField and like those two, are both also Strings that are the "fields" (or Public Properties) you want to represent the underlying "value" and the field to be "displayed".

    So let's set that up instead.  Granted, this particular example (the People Collection) isn't a very good one, as we will have to pick between showing the first name or the last name instead of both, but for this example, it will be better to keep it simple instead.  Leave in the line of code that set the DataSource, but go back into the Person Class and remove the ToString Function.

    Now, before setting the DataSource, put these two lines of code:

    cmbPeople.DisplayMember = "FirstName"
    cmbPeople.ValueMember = "ID"

    Now, to do what we did last time and display the ID Property of the currently selected item in a message box, we're going to use the SelectedValue Property:

    Private Sub cmbPeople_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles cmbPeople.SelectedIndexChanged
         MessageBox.Show(cmbPeople.SelectedValue.ToString)
    End Sub

    Run the Form and you should now see the FirstName in the ComboBox for each item and when you change to a different item, you'll see the ID just as before.  Again, this works great with DataTables as well, but instead of a Property name, you could set DisplayMember and ValueMember to Column Names.  And also, just as it was in the first binding example, SelectedItem will still return back a reference to the actual object that is currently selected.

    Hopefully, if you had any questions about simple binding before, this has helped you a bit.  Maybe even if you're an avid ASP.NET user, but have peaked around at WindowsForms, this should explain some of the differences in DataBinding between the two.

    Have more DataBinding questions in WindowsForms?  Check out the forums.

    Strongly Typed Collections

    Darren and Robert having been talking a bit about Strongly Typed Collections and it's all good stuff, but what I'm a little lost on is I don't see any mention of inheriting from System.Collections.CollectionBase.  This class already Implements IList, ICollection & IEnumberable.  My theory is always...the less work, the better.  CollectionBase is great and helps you implement Strongly Typed Collections really quickly.  Here's a quick example.

    Public C

    lass Person

         Private m_ID As
    Guid
         Private m_FirstName As String
    = ""
         Private m_LastName As String
    = ""

         Public Sub New(ByVal FirstName As String, ByVal LastName As String
    )
              Me
    .m_ID = Guid.NewGuid
              Me
    .m_FirstName = FirstName
              Me
    .m_LastName = LastName
         End
    Sub

        
    Public Sub New(ByVal ID As Guid, ByVal FirstName As String, ByVal LastName As String)

              Me
    .m_ID = ID
              Me
    .m_FirstName = FirstName
              Me
    .m_LastName = LastName
         End
    Sub

        
    Public ReadOnly Property ID() As
    Guid
             
    Get
                  
    Return
    m_ID
              End
    Get
        
    End
    Property

        
    Public Property FirstName() As
    String
             
    Get
                  
    Return
    m_FirstName
              End
    Get
             
    Set(ByVal Value As String
    )
                   m_FirstName = Value
              End
    Set
        
    End
    Property

        
    Public Property LastName() As
    String
             
    Get
                  
    Return
    m_LastName
              End
    Get
             
    Set(ByVal Value As String
    )
                   m_LastName = Value
              End
    Set
        
    End
    Property

    End
    Class

    Public
    Class
    People
         Inherits
    CollectionBase

         Public Function Add(ByVal Person As Person) As
    Integer
             
    Return Me
    .InnerList.Add(Person)
         End
    Function

        
    Public Function Add(ByVal FirstName As String, ByVal LastName As String) As
    Person
              Dim NewPerson As New
    Person(FirstName, LastName)

              Me
    .InnerList.Add(NewPerson)

              Return
    NewPerson
         End
    Function

        
    Public Function Add(ByVal ID As Guid, ByVal FirstName As String, ByVal LastName As String) As
    Person
              Dim NewPerson As New
    Person(ID, FirstName, LastName)

              Me
    .InnerList.Add(NewPerson)

              Return
    NewPerson
         End
    Function

        
    Default Public ReadOnly Property Item(ByVal Index As Integer) As
    Person
             
    Get
                  
    If Index > Me.InnerList.Count - 1 OrElse Index < 0
    Then
                       
    Throw New
    IndexOutOfRangeException("Index out of Range")
                  
    Else
                       
    Return DirectCast(Me
    .InnerList.Item(Index), Person)
                   End
    If
             
    End
    Get
        
    End
    Property

        
    Default Public ReadOnly Property Item(ByVal ID As Guid) As
    Person
             
    Get
                  
    Dim Index As Integer = Me
    .IndexOf(ID)
                   If Index = -1
    Then
                       
    Throw New ArgumentException("No Person was found with the provided ID", "ID")

                   Else
                       
    Return DirectCast(Me.InnerList.Item(Index), Person)
                   End
    If
             
    End
    Get
        
    End
    Property

        
    Default Public ReadOnly Property Item(ByVal FirstName As String, ByVal LastName As String) As
    Person
             
    Get
                  
    Dim Index As Integer = Me
    .IndexOf(FirstName, LastName)
                   If Index = -1
    Then
                       
    Throw New
    ArgumentException("No Person was found with the provided FirstName and LastName")
                  
    Else
                       
    Return DirectCast(Me
    .InnerList.Item(Index), Person)
                   End
    If
             
    End
    Get
        
    End
    Property

        
    Public Function IndexOf(ByVal ID As Guid) As
    Integer
             
    Dim FoundPersonIndex As Integer
    = -1

              For i As Integer = 0 To Me
    .InnerList.Count - 1
                   If DirectCast(Me.InnerList.Item(i), Person).ID.Equals(ID)
    Then
                       
    FoundPersonIndex = i
                        Exit
    For
                  
    End
    If
             
    Next

             
    Return
    FoundPersonIndex
         End
    Function

        
    Public Function IndexOf(ByVal FirstName As String, ByVal LastName As String) As
    Integer
             
    Dim CurrentPerson As
    Person
              Dim FoundPersonIndex As Integer
    = -1

              For i As Integer = 0 To Me
    .InnerList.Count - 1
                   CurrentPerson = DirectCast(Me
    .InnerList.Item(i), Person)
                   If CurrentPerson.FirstName = FirstName AndAlso CurrentPerson.LastName = LastName
    Then
                       
    FoundPersonIndex = i
                        Exit
    For
                  
    End
    If
             
    Next

             
    Return
    FoundPersonIndex
         End
    Function

        
    Public Sub Remove(ByVal Index As Integer
    )
              Me
    .InnerList.RemoveAt(Index)
         End
    Sub

        
    Public Sub Remove(ByVal Person As
    Person)
              Me
    .InnerList.Remove(Person)
         End
    Sub

        
    Public Sub Remove(ByVal ID As
    Guid)
              Dim Index As Integer = Me
    .IndexOf(ID)
              If Index = -1
    Then
                  
    Throw New
    ArgumentException("No Person was found to remove with the provided ID", "ID")
             
    Else
                  
    Me
    .InnerList.RemoveAt(Index)
              End
    If
        
    End
    Sub

    End
    Class

    This may look like a lot of code, but it's really not.  It took me all of 15 minutes to setup from scratch.  Now you can use it just like any other Strongly Typed Collection.

    Dim PeopleList As New People
    Dim PersonIndex As
    Integer

    PersonIndex = PeopleList.Add(New
    Person("Erik", "Porter"))
    PeopleList.Add("Stacey", "Dyer")

    MessageBox.Show(PeopleList(PersonIndex).LastName)
    MessageBox.Show(PeopleList("Stacey", "Dyer").ID.ToString)

    So if you're thinking about creating your own Collection definitely take a look at CollectionBase.  Extremely easy and fun (well for me anyway)!

    <update>

    I originally had a lot of Overloads Keywords in the Collection, which were not necessary.  That's what I get for copying old code instead of typing it out myself.  I took them out.

    </update>

    VB Blog section on MSDN
    Duncan points out the new blogs section he's setup and what do you know...there I am!  :)  Thanks, Duncan!
    Posted: Jul 27 2003, 01:24 AM by HumanCompiler | with 1 comment(s)
    Filed under:
    Shoe Scanner
    Being an Eagle Scout myself (and a geek), this seems really cool and a great idea!
    Posted: Jul 25 2003, 10:03 PM by HumanCompiler | with no comments
    Filed under:
    New ASP.NET Control

    It's really basic, but it is something I happen to use in quite a few of my projects, so I thought I'd share.

    OfficeButton Control

    Posted: Jul 25 2003, 03:57 PM by HumanCompiler | with no comments
    Filed under:
    More Posts Next page »