July 2003 - Posts
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.
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.
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! :)
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
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*
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.
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>
Duncan points out the new blogs section he's setup and what do you know...there I am! :) Thanks, Duncan!
Being an Eagle Scout myself (and a geek), this seems really cool and a great idea!
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
More Posts
Next page »