I got tired of waiting for the registration page to start working so I thought I'd post a direct link. Those who missed the live webcast last week can get it here now! This is fixed in the events system but may take a day or so to work itself into the feeds on the VB Dev Center.
If you missed it, there's a really awesome video on Channel 9 from David Schach the lead developer on the LINQ to XML team. In this video he walks us through VB 9.0 and its support for XML literals by creating an rss feed of his pictures. Not only is the content awesome but so is how David filmed it, using a web cam to record himself while recording the screen, and showing himself as a window in the bottom right-hand corner. Very cool!
What are your favorite videos or screencasts on Visual Basic? I'm looking to update the Visual Basic Videos page with new stuff. If you have a cool video on VB let me know!
I've been noticing a lot of questions on the forums related to Winforms data binding and the ComboBox and I thought I'd post something up here to help people out. In fact data binding, or what we call “Windows Forms over Data” is a huge, sometimes misunderstood, topic. Because of this I’m putting together a “how-to” video series on a variety of topics in this area. Two of the videos are dedicated to data binding the ComboBox in a couple very common scenarios:
1. To display information from a lookup table and send the selected value into another table's field.
2. To display a list of parent table's records and use that as a filter to display related child records. For instance, as the user selects a record in the ComboBox, you want to display all the related child records in a grid.
The trick is setting up the data binding properly using the BindingSource. I wrote about how to set up related lists in this post in order to get this second scenario to work with BindingSources managing lists of objects. Here, I’ll put it into the context of using DataSets.
In the first case it's not necessary to set up a data relation in your DataSet between the lookup table and the table you're editing, but it doesn't hurt. In the second case it is necessary to create a relation between your parent and child tables. Let's take an example from our beloved Northwind.
First we’ll use the Data Source Configuration Wizard to create a DataSet with Regions and Territories. In VS 2005, go to the Data menu and select “Show Data Sources” then select “Add New Data Source”.
If we take a look at the DataSet through the DataSet Designer, we see that these tables are related on RegionID:
In the first scenario we want to select a Region from the ComboBox and have that value populated into the Territorries record. In this case we set up the RegionBindingSource with the following properties:
Me.RegionBindingSource.DataSource = Me.NorthwindDataSet
Me.RegionBindingSource.DataMember = "Region"
Then you use set the BindingSource as the Datasource of the ComboBox and set the display member and value member properties:
Me.ComboBox1.DataSource = Me.RegionBindingSource
Me.ComboBox1.DisplayMember = "RegionDescription"
Me.ComboBox1.ValueMember = "RegionID"
These properties control what items are displayed in the ComboBox and what value is used when the user makes a selection. Now to get that value into the Territories table, we use the TerritoriesBindingSource when we create the binding to the RegionID:
Me.TerritoriesBindingSource.DataMember = "Territories"
Me.TerritoriesBindingSource.DataSource = Me.NorthwindDataSet
Dim b As New System.Windows.Forms.Binding("SelectedValue", _
Me.TerritoriesBindingSource, "RegionID", True)
Me.ComboBox1.DataBindings.Add(b)
Okay we're all set, right? Well... almost! You'll also need to call EndEdit on the TerritoriesBindingSource at some point in order to write the value back to the DataSet. If you’re using the designers to do this then it takes care of the code for you when you click save on the BindingNavigator’s save button. So depending on the style of your form you could do this from an "Update" button (similarly you could call CancelEdit from a Cancel button).
Private Sub TerritoriesBindingNavigatorSaveItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TerritoriesBindingNavigatorSaveItem.Click
Me.Validate()
Me.TerritoriesBindingSource.EndEdit()
Me.TerritoriesTableAdapter.Update(Me.NorthwindDataSet.Territories)
End Sub
The cool thing about EndEdit/CancelEdit on the BindingSources is that they cancel or commit only the fields in which they have bindings for, where as the DataSet rows' AcceptChanges/RejectChanges works on the whole row regardless of the data bindings.
Now let's take our second scenario where we want to use the ComboBox as a row filter. In this case we have to have a relation set up between our parent and our child; in the example this is FK_Territories_Region in our DataSet. So the BindingSources in this case need to be set up so that they are related as well. If you use the Data Sources Window, make sure you are working with the Region and the related Territories, just like if you were creating a One-to-Many form.
So the BindingSources will be set up like so:
Me.TerritoriesBindingSource.DataSource = Me.RegionBindingSource
Me.TerritoriesBindingSource.DataMember = "FK_Territories_Region"
Notice that the main difference here is that the TerritoriesBindingSource’s DataSource property is set to the parent BindingSource, RegionBindingSource and its DataMember is the relation name. This sets up automatic filtering on the TerritoriesBindingSource as the position changes on the RegionBindingSource. Also notice how the BindingSources decouple the data from the actual controls, making it very easy to switch controls or change the data sources. Now the ComboBox properties can then be set up just like the first example:
Technically we don't need to specify the ValueMember property this time because we're not writing it anywhere, but it doesn't hurt to specify it. Next all we need to set up is the DataSource property of the DataGridView setting it to the TerritoriesBindingSource.
Me.TerritoriesDataGridView.DataSource = Me.TerritoriesBindingSource
(By the way, all the code up to this point could all be written by the designers by using drag-and-drop from the Data Sources Window. You’ll see this in the videos ;-))
Okay we're all set, right? Well... almost! Unfortunately a ComboBox won't move the BindingSource’s position for you like list controls do (Grids, ListBoxes). So the trick is to simply set the position of the RegionBindingSource by handling the ComboBox's SelectedIndexChanged event. So we need to write some code:
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
Me.RegionBindingSource.Position = Me.ComboBox1.SelectedIndex
Because we have related BindingSources the grid will automatically filter its rows based on the selected parent row in the ComboBox.
And notice that this code would work with other controls as well, for instance, instead of a ComboBox we could have used a ListBox or have set up two related grids.
Because we’re using DataSets as the source of our data, the BindingSources are maintaining DataViews so you can easily access the current DataRowView and cast it to the Typed DataSets’s row for typed access to the fields. For instance it’s handy to be able to get the current row when working on your form. You can do this by adding a property to your form. Just make sure to check for Nothing because there may not be a selected row:
Public ReadOnly Property CurrentRegion() As NorthwindDataSet.RegionRow
Get
If Me.RegionBindingSource.Position > -1 Then
Return CType(CType(Me.RegionBindingSource.Current, DataRowView).Row, NorthwindDataSet.RegionRow)
Else
Return Nothing
End If
End Get
End Property
We can use this property like so:
Dim region As NorthwindDataSet.RegionRow = Me.CurrentRegion
If region IsNot Nothing Then
MsgBox("The selected Region is:" & region.RegionDescription)
The BindingSources are your friends. They decouple the data from the actual controls, making it very easy to switch controls or change the data sources without affecting the bindings. Use the Data Sources Window and it will save you from writing 90% of your data binding code. Have fun and keep a look out for the Windows Forms over Data video series that will be published soon!
Join Kit George, Visual Basic Program Manager, and explore the new LinQ features in Visual Basic. Kit will show how to take advantage of LinQ to build applications that query and aggregate data from multiple sources, including in-memory objects, databases, and XML. The webcast starts today at 9AM PST -- Register here!
Tomorrow at 9AM PST John Stallo, a Program Manager on the Visual Basic team, will give a webcast on Orcas, the next version of Visual Studio. In this overview John will cover the breadth of features that you can expect to see in the upcoming release of Visual Basic. John will demo how all the features such as LINQ, N-Tier Data, WCF, and the Local Data Cache work together to help you build better applications in less time. I've walked through the scripts on this one and this stuff is pretty impressive, do not miss this!
By the way, those of you who tried the last webcast, Live Meeting was having some major problems, we apologize. We just did a dry run and it all worked flawlessly, so I hope you can join us tomorrow!
I thought I'd post a quick how-to here based on some questions that came up in the forums like this one. The question is how do we relate two lists of data together so that when we select a "parent" object we can get automatic filtering on the related items in a Winform. For instance, one person in the forums was trying to put a list of states in a ListBox and when you selected one, a list of cities in that state would populate a CheckedListBox.
The answer lies in the BindingSource object. BindingSources do all of the heavy lifting for you when it comes to filtering and even sorting and editing. The key to using these though is we need to set up our object model correctly, in this case State and City, so that they are related properly.
In our example, we create two classes, State and City and set them up so that State has an internal list of Cities. Then you can use data binding on the controls by setting up two BindingSources that are related -- this will manage the position and the contents of the related lists automatically.
So our State and City classes need to look like this:
Public Class State
Private m_cities As New List(Of City)
Sub New(ByVal state As String)
m_State = state
Private m_State As String
Public Property State() As String
Return m_State
Set(ByVal value As String)
m_State = value
End Set
Public ReadOnly Property Cities() As List(Of City)
Return m_cities
Public Overrides Function ToString() As String
Return Me.State
End Function
End Class
Public Class City
Sub New(ByVal city As String)
m_City = city
Private m_City As String
Public Property City() As String
Return m_City
m_City = value
Return Me.City
Then we can set up our data and two BindingSources that we relate together. We do this by setting the CitiesBindingSource.DataSource property to the StateBindingSource and then setting its DataMember to the Cities property on the State class. Once that's set up then we set the BindingSources to the DataSource property of our controls:
Private States As New List(Of State)
Private StatesBindingSource As New BindingSource
Private CitiesBindingSource As New BindingSource
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim ny As New State("New York")
ny.Cities.Add(New City("New York"))
ny.Cities.Add(New City("Rochester"))
Dim vt As New State("Vermont")
vt.Cities.Add(New City("Rutland"))
vt.Cities.Add(New City("South Burlington"))
Dim id As New State("Idaho")
id.Cities.Add(New City("St. Albans"))
States.Add(ny)
States.Add(vt)
States.Add(id)
Me.StatesBindingSource.DataSource = Me.States
Me.CitiesBindingSource.DataSource = Me.StatesBindingSource
Me.CitiesBindingSource.DataMember = "Cities"
Me.ListBox1.DataSource = Me.StatesBindingSource
Me.ListBox2.DataSource = Me.CitiesBindingSource
Now all we need to do is move the position in the StatesBindingSource when the SelectedIndex changes in the first ListBox. This will automatically filter the list of cities for us:
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
Me.StatesBindingSource.Position = Me.ListBox1.SelectedIndex
This is really easy when you use list controls that have a Datasource property like a Combobox, ListBox or a DataGridView. However, the CheckedListBox does not have one so we have to fill the items a little more manually. We still use the CitiesBindingSource though because it will still contain our filtered list of items as the StatesBindingSource position changes. So we just need to add this code:
'Clear out the cities in the city checkedlistbox first
CheckedListBox1.Items.Clear()
'This is necessary only because the CheckedListbox does not have
' a Datasource property. Any control with a Datasource property
' could simply be set to Me.CitiesBindingSource
For Each c As City In Me.CitiesBindingSource.List
Me.CheckedListBox1.Items.Add(c)
Next
So now when we move through our ListBox1, we will get automatic filtering on the rest of our controls.
Visual Basic LINQ samples have been updated and were just released today! Lots of stuff to download and play with today.... :-)
Okay I admit it. I like Vista. I didn't want to like it, really. I'm a VB developer, not a gamer, not a heavy office user, I know the difference between an .exe and a .dll, I keep my own dang files organized -- I don't need the OS to index anything while taking up my precious CPU!
But.. it happened.
A month ago I got a new Lenovo T60p and after about 2 hours on Vista and Office 2007 I was hooked. Development has its bumps (it always does) but it's been a good experience so far, much better than I thought it would be.
There are a couple annoying things, however, like when I attach a SQL-Express database it coughs up an error and puts the database into read-only mode. I just have to set it back to read-write everytime. Turns out I just need to run SQL-Server Management Studio as an administrator to get around this problem.
The most annoying thing for me was that when I click on a Visual Studio Solution (.sln) file it would do nothing. Nada. Ziltch. Bummer. I was already running VS as an administrator. Today I finally decided to look around the web for a solution/hack. Here's what I found and it works great! I know a couple people in our .NET User Group were griping about this a while back. BTW, this came from the same blog as the SQL attach post above. Thanks to Bryan Phillips.
Two annoying Vista problems solved. :-)