Beth's Chinese blog
If you haven't seen or experienced Second Life it's pretty amazing. It's an online, 3D, digital world. Visual Studio has created an island where you can come listen to live Microsoft presenters in this virtual world's live presentation theater! Amanda Silver will be presenting Visual Basic on Silverlight tomorrow, July 31st at 4pm Pacific time. There's a lot of other fun events you should check out as well.
See you there!
I just posted a couple more videos on Channel9 that you'll definitely want to check out! Thanks again to Kathleen for helping with the production.
The first one Kit George walks us through some of his favorite VB9 language features that enable LINQ:
In this in interview Kit George, a Program Manager on the Visual Basic Team and a former member of the CLR Team, shows us his favorite language features that enable LINQ without actually talking about the queries themselves. His excitement about Extension Methods, Anonymous Types, Object Initializers, Type Inference and the new Refactor! shows through in typical Kit fashion. It's an interview that's as much fun to watch as it was to produce!
The next one Chris Smith gives us a quick TechEd "booth babe" demo of LINQ to XML in VB9:
I suggest watching them full screen for easier viewing of the demos. And stay tuned for more VB Screencasts on Channel9!
Enjoy!
Today we released Visual Studio 2008 Beta 2 as well as updates to the Visual Basic Samples, Express Samples and the LINQ Hands on Labs! Check out the new headlines on the Visual Basic Developer Center. Everything is finally propagated! (What a long morning for me <g>) You also may want to take a look at this Channel9 video with Soma and ScottGu where they talk about what's new in Beta 2.
I'm working on a set of LINQ "How Do I" videos to help get you started so stay tuned for more VB and LINQ goodness.
One of my favorite uses of LINQ is being able to query over metadata and use it to create flexible programs. Conversely, I also like to use LINQ to quickly create metadata about my objects. Metadata simply put is "data about data" or, for example, information that describes content. I want to walk through a simple example that shows how to use information stored in a database that describes some content for some controls on a form. And then I'll show you how to create data (XML) that describes that form and its controls. NOTE: The example I'm creating works with a pre-release Beta 2 version of Visual Studio 2008.
The idea for this example is that I want to read the text of the controls from a database and depending on the language I select, the text on the controls will change. I've created a very simple table in my database called ControlData that has three string fields, Name, Description and Language. The data looks like this:
Name Description Language
---------- ------------- ---------
Button1 Hello English
Button2 Goodbye English
Button3 I love VB English
Button4 LINQ Rocks! English
TextBox1 Hello English
TextBox2 Goodbye English
Button1 Buon Giorno Italian
Button2 Ciao Italian
Button3 Amo VB Italian
Button4 LINQ è potente Italian
TextBox1 Buon Giorno Italian
So next what I've done is create a form with some controls on it. Some control names match the names here in the database and others do not. We're going to write queries that can work over all the controls on the form and join in the matching information here to change the Text they display, depending on the language we select (which I've placed in a Combobox). So my form looks like this:
The first thing we're going to do is create a LINQ to SQL class using the new O\R designer. It's very simple to use this, just right-click on your project and select "Add New Item" and select the LINQ to SQL Class template. This creates a file with a .dbml file extension and opens the O/R designer (I just went with the default name of DataClasses1). You can simply drag tables from your Server Explorer onto the surface and it will generate all the code for you similar to the DataSet designer experience.
In my case I just dragged the ControlData table onto the surface and it created what's called a DataContext with a single class called ControlData. We can now query over the ControlData and LINQ to SQL will translate our LINQ queries into SQL queries automatically. All we need to do is create an instance of the DataContext and then we can start querying over the ControlData.
So the first LINQ query I want to write will populate the contents of the Combobox that displays the Language. This is done by selecting the distinct rows and then setting the result as the DataSource of the Combobox:
Public Class Form1
Private db As New DataClasses1DataContext
Private Sub Form1_Load() Handles MyBase.Load
Dim choices = From info In db.ControlDatas _
Select info.Language Distinct
Me.ComboBox1.DataSource = choices
End Sub
What the variable 'choices' ends up being from this query is a simple list of strings (IQueryable(Of String)) and that works fine for our Combobox's DataSource -- we'll end up with two strings, "English" and "Italian".
Next I want to handle the Combobox's SelectedIndexChanged event in order to change the Text property of our controls. I'm going to add a twist to this example and only set the text of Button controls. We can select all the top-level buttons on a Form my using the Me.Controls collection. This collection has been on WinForms since the beginning of time so it returns a ControlsCollection which means we'll have to cast our Buttons out of it. I chose to do it like this:
Dim buttons = From c In Me.Controls _
Where TypeOf c Is Button _
Select CType(c, Button)
We could iterate this list of buttons (IEnumerable(Of Button)) now and set the Text property manually if we wanted:
For Each button In buttons
button.Text = "LINQ is cool"
Next
But what we want to do is join this list of buttons with the ControlData objects matching on the Name and filtering by the Language so when all is said and done the SelectedIndexChanged event handler code will look like so (I split the query up into two parts for readability):
Private Sub ComboBox1_SelectedIndexChanged() Handles ComboBox1.SelectedIndexChanged
Dim buttonInfo = From Button In buttons _
From info In db.ControlDatas _
Where info.Name = Button.Name _
AndAlso info.Language = Me.ComboBox1.SelectedValue.ToString _
Select Button, info.Description
For Each item In buttonInfo
item.Button.Text = item.Description
What we've selected (projected) for buttonInfo is a list of anonymous types. If you notice we're selecting the Button objects as well as the string Description field -- this creates a list of anonymous types for us that we are iterating and using to set the Text property. That's all there is to it. When we select the language in the combobox, the Text of the Buttons change.
The last thing I want to do is to create some metadata about this form by creating a simple XML document that describes the controls as well as the possible content in the database. We can use LINQ to XML and XML literals to do this easily. The only trick is that we'll need to perform a group join because some of the controls on our form are not contained in the database and some of the controls have multiple rows of information. So we have zero or more matching ControlData objects for each of the Form's Controls. So I perform a group join of the information in the database and then use that group as a sub-query to get the zero, one, or more Descriptions which I place into a <Text> element. This ends up under the <Control> elements that are selected which are under the root <Form> element:
Private Sub cmdMakeXML_Click() Handles cmdMakeXML.Click
Dim formData = <?xml version="1.0"?>
<Form
name=<%= Me.Name %>
height=<%= Me.Height %>
width=<%= Me.Width %>
top=<%= Me.Top %>
left=<%= Me.Left %>
font=<%= Me.Font %>>
<%= _
From item In Me.Controls _
Let c = CType(item, Control) _
Group Join info In db.ControlDatas On info.Name Equals c.Name Into Group _
Order By c.Name _
Select <Control
type=<%= c.GetType %>
name=<%= c.Name %>
height=<%= c.Height %>
width=<%= c.Width %>
top=<%= c.Top %>
left=<%= c.Left %>
font=<%= c.Font %>>
<%= From info In Group _
Order By info.Language _
Select <Text language=<%= info.Language %>>
<%= info.Description %>
</Text> %>
</Control> _
%></Form>
My.Computer.FileSystem.WriteAllText("Form1.xml", formData.ToString, False)
Process.Start("notepad.exe", "Form1.xml")
Here's a rip of the XML that is created:
LINQ is really powerful and simplifies a lot of common scenarios where we need to query over data in many forms, in this case a database, a collection of objects and XML. I've attached this project but please note that some features may not work as expected until the release of Visual Studio 2008 Beta 2. For more information on LINQ please check out the LINQ Project page on MSDN.
I just posted Cameron McColl's Channel9 video where he talks about the performance improvements made in VS 2008. Check it out!
In this in interview Cameron McColl, a Developer on the Visual Basic Team, shows us what kinds of performance improvements were made in Visual Studio 2008. He walks us through a set of scenarios that suffered from performance issues and then shows us the same scenarios in Visual Studio 2008 describing what was happening and how they fixed the issues.
Stay tuned for more videos every week. And here's the link for all the VB.NET screencasts. Also check out Kathleen's blog.
We just got a new section started on the Visual Basic Community page that showcases donated articles from the expert VB community. The first article Jim Duffy, a Visual Basic MVP, walks us through System.Net.Mail namespace. More articles from our MVPs will come online every few weeks. Stay tuned for WCF and WPF/Silverlight content in the coming months! Many thanks to the MVPs that have volunteered so far.
I just posted a couple screen casts/interviews on Channel9 you should definitely check out. I rounded up VB team members and influentials and asked them what their favorite Visual Studio 2008 features were and to give us all a demo of them!
The first one is with Erik Meijer and he shows us his favorite feature, XML Literals:
In this in interview Erik Meijer, an Architect on the Data Programmability team, shows us how LINQ to XML works in the next version of Visual Basic, 9.0. He talks about some of the history behind the features as well as how XML literals, unique to Visual Basic, are implemented. He takes us on an adventure on how to efficiently work with XML using XML Intellisense and an Office Open XML Excel document, pointing out a lot of tid-bits of information along the way that only Erik could show us.
The next one is with Jonathan Aneja and he shows us the Interop Forms Toolkit 2.0:
In this in interview Jonathan Aneja, a Program Manager on the Visual Basic team, shows us how the Interop Forms Toolkit 2.0 helps you migrate your existing VB 6 applications one form at a time to .NET. He gives us insight on how we can write .NET user controls and forms to take advantage of the .NET framework but still run within our VB 6 applications. He shows us a demo where he creates a .NET user control which uses LINQ to SQL features and then shows it running inside a VB 6 form.
I suggest watching them full screen for easier viewing of the demos. More will be coming so stay tuned. And many thanks to Kathleen McGrath for helping with the production.
In a previous post I showed how we could dynamically create a UI based on some XML, however the properties we wanted to set were known because we wrote the XML. I want to follow up with an extension of that sample that can dynamically set the properties on our objects that we're creating by reading the property names from the XML as well.
We need to rewrite the Dynamic class so that it can get and set the properties dynamically. We'll turn to VB's CallByName function to help us (this is similar to the SetProperty() VFP method). Currently this function only works with simple types, however, so we cannot dynamically set our colors with this technique, though it can still be powerful in many scenarios. Let's take a look:
My new XML document looks like the following:
<?xml version="1.0" encoding="utf-8" ?>
<questions>
<question>
<assembly>System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</assembly>
<control>System.Windows.Forms.TextBox</control>
<text>This is the first survey question.</text>
<height>35</height>
<readonly>true</readonly>
<tabstop>false</tabstop>
<multiline>true</multiline>
</question>
<text>This is the second survey question.</text>
<height>100</height>
<control>System.Windows.Forms.Label</control>
<text>This is the third survey question.</text>
<height>80</height>
<control>System.Windows.Forms.Button</control>
<text>This is the fourth survey question.</text>
<height>30</height>
</questions>
Now we just read the list of properties from the document. We can do this easily in VB 8 using a DataSet again:
'Read the xml into a dataset for easier processing of the elements
Dim myData As New DataSet()
myData.ReadXmlSchema(CurDir() & "\questions.xsd")
myData.ReadXml(CurDir() & "\questions.xml")
Dim survey As DataTable = myData.Tables(0)
'Read the properties from the XML
Dim props As New List(Of String)
For Each dc As DataColumn In survey.Columns
props.Add(dc.ColumnName)
'Now add all the questions defined in the questions.xml file
For Each row As DataRow In survey.Rows
Me.AddQuestion(row, props)
Option Strict Off
Public Class Dynamic
''' <summary>
''' Dynamically creats an object and sets properties on it
''' by reading properties on the passed in object.
''' </summary>
''' <param name="info">An object with the property values</param>
''' <param name="properties">The list of properties to set from the info
''' object onto the created object</param>
''' <returns></returns>
Shared Function GetQuestion(ByVal info As Object, ByVal properties As List(Of String)) As Object
Dim c As Object
Dim propValue As Object
Try
c = System.Reflection.Assembly.Load(info!Assembly).CreateInstance(info!Control)
'VB does an automatic conversion at runtime
For Each prop As String In properties
'Late bound call - we don't know the type or the value
propValue = info(prop)
Catch ex As Exception
propValue = Nothing
End Try
If propValue IsNot Nothing AndAlso propValue IsNot System.DBNull.Value Then
CallByName(c, prop, CallType.Set, propValue)
'if we can't set a property on the object, just ignore
End If
'Try/Catch is required here, as this code will cause
' a runtime error if the the type cannot be created.
c = New TextBox
c.Text = ex.ToString
c.MultiLine = True
c.Height = 100
c.ReadOnly = True
c.ScrollBars = ScrollBars.Vertical
Return c
End Function
End Class
I've attached the new sample to this post. No one can deny that VB still has a long way to go to enable better support here, but we can see that the beginings of dynamic programming in Visual Basic today.