El pasado día 21 de abril en Madrid y el día 22 de abril en Barcelona tuvo lugar el evento Frameworks y herramientas RAD de código abierto y propietario para soluciones .NET. Donde presenté nuestro Solid RAD, una herramienta para el desarrollo rápido de aplicaciones centradas en datos con una arquitectura de dos y tres capas.
Si estáis interesados en Solid RAD Tenéis disponibles unos vídeos en mms://solidq.com/SolidRad .
NOTA: copiad y pegad mms://solidq.com/SolidRad en la barra de direcciones de IE para ver los vídeos.
La forma en la que se añade un menú personalizado ha variado en la nueva versión de Visual Studio 2008. El SDK de extensibilidad de Visual Studio 2008 ha variado la forma en la que se generan menús y comandos de forma que ya no se utilizan los "antiguos" ficheros de configuración .ctc.
Como pequeña introducción, os digo que en la nueva versión se ha optado por un nuevo sistema de configuración más acorde a los tiempos que corren basado en XML. Dicho sistema de configuración está completa y exquisitamente explicado en el siguiente enlace (no apto para lectura al final del dia;).
Dicho esto, os aviso de antemano que la documentación que viene con la propia descarga del ejecutable SDK Extensibility 1.0 para Visual Studio 2008 es errónea y hace referencia al antiguo sistema de configuración (por lo menos en lo que nos atañe que son los menús en DSL). El antiguo sistema de agregación de menús personalizados en nuestros lenguajes de dominio está explicado bastante bien en el blog de "El Bruno" o en la propia documentación que viene con el descargable de extensibilidad que he mencionado.
Vamos a ponernos manos a la obra. Para ello parto de que tienes ya tu proyecto de lenguaje de especificación de dominio creado…
Tal cual está, podemos crear nuestro menú de una forma bastante más sencilla que antes siguiendo los siguientes pasos:
En dicho archivo es donde vamos a tener que añadir los elementos del menú que queremos. En nuestro caso vamos a crearnos un botoncito que nos diga la figura que hemos clickeado.
La forma de crear nodos dentro del archivo está "explicada" muy por encima en los documentos de ayuda de mdsn (por lo menos ahora cuando escribo este post) por lo que seguramente acabarás antes viéndolo desde aquí ;)
Básicamente lo que vamos a hacer es definirnos un botón y una identificación del mismo. Importante a tener en cuenta son los nodos <Commands/> y <Symbols/> (no quiero liaros con el nodo <Extern/> que no vamos a tocar ahora)
<Buttons>
<Button guid="cmdDimeNombreFiguraGUID" id="cmdDimeNombreFiguraID type="Button">
<Parent guid="guidCmdSet" id="grpidContextMain"/>
<Strings>
<CanonicalName>cmdDimeNombreFigura</CanonicalName>
<ButtonText>Nombre figura</ButtonText>
<ToolTipText>Dice el nombre de la figura seleccionadaToolTipText>
</Strings>
</Button>
</Buttons>
<Symbols>
<GuidSymbol name="cmdDimeNombreFiguraGUID" value="{D5A40ECA-BA87-4a92-B6A7-A36C27C858AE}">
<IDSymbol name="cmdDimeNombreFiguraID" value="1"/>
</GuidSymbol>
</Symbols>
El valor del GuidSymbol ha sido generado mediante la aplicación guidgen.exe
El valor del IDSymbol puede ser decimal o hexadecimal (por ejemplo, valores 0x104 pueden darse) y podemos darle el que queramos.
Una vez realizado esto, el fichero queda de la siguiente manera:
<?xml version="1.0" encoding="utf-8"?>
<CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- -->
<!-- This file contains custom command definitions. -->
<!-- NOTE: Each time commands are added or changed, the "version" parameter to the -->
<!-- ProvideMenuResource attribute in Shell\Package.tt should be incremented. -->
<!-- This causes Visual Studio to re-merge the menu definitions for the package. -->
<!-- Otherwise, changes won't take effect until the next time devenv /setup is run. -->
<Extern href="stdidcmd.h"/>
<Extern href="vsshlids.h"/>
<Extern href="msobtnid.h"/>
<Extern href="virtkeys.h"/>
<Extern href="DSLToolsCmdID.h"/>
<Include href="GeneratedCode\GeneratedVsct.vsct"/>
<Commands package="guidPkg">
<Button guid="cmdDimeNombreFiguraGUID" id="cmdDimeNombreFiguraID" type="Button">
<ToolTipText>Dice el nombre de la figura seleccionada</ToolTipText>
</Commands>
</CommandTable>
Para ello, lo editamos y reemplazamos lo que viene por defecto ( [VSShell::ProvideMenuResource("1000.ctmenu", 1)] ) , por [VSShell::ProvideMenuResource("1000.ctmenu", 2)]
Y le añadimos los métodos OnPopUpMenuClick(), OnPopUpMenuDisplayAction() y GetMenuComands() a la clase.
Evidentemente lo que no vamos a hacer es escribir el código directamente sobre el fichero CommandSet.cs puesto que dicho fichero se machaca cuando le damos a "Transform All Templates" por lo que haciendo uso de las posibilidades de definición de clases parciales, le definiremos el código en un nuevo fichero.
NOTA: En mi caso, mi lenguaje se llama LenguajeOOMM y por eso la clase generada en CommandSet.cs se llama así. Por seguir una nomenclatura estándar he creado dicho nombre al fichero. En cualquier caso, el contenido siempre ha de ser el de la definición de la clase doblemente derivada.
Antes hacíamos referencia al fichero CommandSet.cs. Por poco que lo abramos y le demos un vistazo veremos que sigue la pauta de clase doblemente derivada (que se sale del tema del post pero que en futuros post trataré) que crea una clase heredada de DslShell::CommandSet (en mi caso llamada LenguajeOOMMCommandSetBase), y luego otra clase que hereda de la anterior y es a la que vamos a añadirle la funcionalidad citada en el paso 6.
using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using Microsoft.VisualStudio.Modeling.Shell;
using System.Collections;
using System.Text;
namespace LenguajeOOMM
{
/// <summary>
/// Double-derived class to allow easier code customization.
/// </summary>
internal partial class LenguajeOOMMCommandSet : LenguajeOOMMCommandSetBase
protected override IList<System.ComponentModel.Design.MenuCommand> GetMenuCommands()
IList<System.ComponentModel.Design.MenuCommand> commands = base.GetMenuCommands();
DynamicStatusMenuCommand cmdDimeNombreFigura =
new DynamicStatusMenuCommand(
new EventHandler(OnPopUpMenuDisplayAction),
new EventHandler(OnPopUpMenuClick),
new CommandID(new Guid("D5A40ECA-BA87-4a92-B6A7-A36C27C858AE"), 1));
commands.Add(cmdDimeNombreFigura);
return commands;
}
/// Lo que se desencadena al pinchar sobre el boton.
/// En principio no queremos nada mas que se muestren los objetos seleccioonados
/// <param name="sender"></param>
/// <param name="e"></param>
internal void OnPopUpMenuClick(object sender, EventArgs e)
MenuCommand command = sender as MenuCommand;
StringBuilder sb = new StringBuilder();
foreach (object selectedObject in this.CurrentSelection)
sb.AppendLine("Objetos Seleccionados: " + selectedObject.ToString());
System.Windows.Forms.MessageBox.Show(sb.ToString());
/// Se desencadena cuando vamos a mostrar el menú.
internal void OnPopUpMenuDisplayAction(object sender, EventArgs e)
// Solo se desencadena si entre todos los objetos seleccionados, hay algun ExampleShape
//para conectores por tanto no sale. Comportamiento a posta
if (selectedObject is ExampleShape)
command.Visible = true;
command.Enabled = true;
return;
//por defecto deshabilitado
command.Visible = false;
command.Enabled = false;
Ahora nos saldrá el elemento del menú en cuestión y al clickear nos saldrá un MessageBox con la información que queríamos.
Ni que decir tiene las posibilidades de esto. Podemos crearnos un menú que interactúe con nuestro propio modelo de forma que podamos cambiar incluso el aspecto o propiedades de nuestros objetos para que sin tener que borrar figuras, las podamos modificar
Recientemente, Tim Sneath, del equipo de desarrollo de Microsoft en Redmond, publicaba en su blog (http://blogs.msdn.com/tims/) una interesante entrada sobre las implicaciones del Service Pack 1 para Windows Vista de cara al desarrollo.
La primera de ellas, tiene que ver con la unificación y solidez de las nuevas API instaladas en el SP1. Por primera vez, Vista comparte con el W2008 un enorme conjunto de librerías base, que permiten que las actualizaciones sean más coherentes y sencillas, para ambos sistemas, y los mecanismos de programación no requieran de personalizaciones en función de la plataforma. Además, Vista SP1, se beneficia de componentes presentes en ambos sistemas, que han sido exhaustivamente testados para el servidor 2008.
Uno de esos cambios se aprecia en las herramientas de administración de IIS 7.0, que ahora tienen un nivel de control muy superior al de la versión RTM.
Nota: Para los interesados en la programación con Silverlight, sirva decir que las extensiones MIME correspondientes a esta tecnología (.xaml y .xap), se encuentran por defecto instaladas en W.Server 2008, y también las incluye este Service Pack pero solo para instalaciones limpias con el SP1. Si el lector tenía Vista RTM instalado, podrá observar que dichas extensiones no aparecen al examinar los tipos MIME definidos en la Consola de Administración de IIS7. La solución: desinstalar y volver a Instalar IIS7 en el apartado "Activar o Desactivar características de Windows", en el Panel de Control.
Además, se han añadido nuevas API para control de las características Data Execution Protection y Kernel Patch Protection, así como realizado mejoras notables en los algoritmos de cifrado (en todas las categorías) y generación de números aleatorios, y todos ellos (junto a una actualización a DirectX 10.1), están disponibles para desarrolladores.
El SP1, instala elementos en las API's de .NET 3.0 (convirtiéndolas en .NET 3.0 SP1), estando muchas de las mejoras que aporta .NET 3.5 incluidas en este service pack (con excepciones notables, como LINQ). Esto es así, ya que cada una de las mejoras incluidas en las últimas actualizaciones de .NET Framework, ha sido construida sobre la anterior y no en forma paralela, tal y como puede verse en el gráfico adjunto.
Marino Posadas
Development Dept. (Spain)
Como seguramente sabrás, una de las cosas buenas de .NET Framework, es que al instalar el runtime (motor en tiempo de ejecución o CLR), es decir, cuando instalas el .NET Framework para que puedas usar cualquier aplicación escrita en .NET, automáticamente se instala también los compiladores de Visual Basic y C#.
Estos compiladores son los que utiliza el propio Visual Studio (o las versiones Express de Visual Basic y Visual C#) para compilar el código.
Si te decides a usarlos por tu cuenta, es decir, sin dejar que te ayude el Visual Studio, tendrás que hacer varias cosas.A saber:
@echo off Echo Linea de comandos para los compiladores de .NET Framework 3.5 Echo. rem %comspec% /k "net_bin.bat" rem @SET FrameworkDir=C:\WINDOWS\Microsoft.NET\Framework @SET FrameworkVersion=v2.0.50727 @set PATH=%FrameworkDir%\v3.5;%FrameworkDir%\%FrameworkVersion%;%PATH% @set LIBPATH=%FrameworkDir%\v3.5;%FrameworkDir%\%FrameworkVersion%;%LIBPATH%
Listado 1. Contenido mínimo del fichero para usar los compiladores de .NET Framework 3.5
¿Por qué te explico todo esto?
Entre otras cosas, por si has comprado mi libro de las Novedades de Visual Basic 9.0 y quieres crearte tu propia DLL para suplir el Runtime de Visual Basic y como eso debes hacerlo desde la línea de comandos (no se pueden crear ese tipo de aplicaciones que usan una versión independiente del runtime de VB desde el IDE de Visual Studio), pues así sabes cómo tener esa línea de comandos, además de que (creo) que con las versiones Express no se crea ese acceso directo, pues... ya no tendrás límite para crear tu código sin necesidad de tener que instalar el Visual Studio.
Espero que te sea de utilidad.
Nos vemos.Guillermo
Este artículo también está publicado en mi sitio:Cómo.NET: Compilar desde la línea de comandos
Se encuentra disponible en MSDN una herramienta para generar dicho tipo de código.
EL artículo correspondiente con vínculo para descargar la herramienta, está aquí. http://msdn2.microsoft.com/en-us/magazine/cc164193.aspx
Dim req Set req = WScript.CreateObject("MSXML2.XMLHTTP") req.open "GET", "http://MiServidorWeb/MiSitioWeb/RegistrarSesion.ashx?Operacion=InicioSesion" req.send Do While req.readyState <= 1 WScript.Sleep 50 Loop
Dim req Set req = WScript.CreateObject("MSXML2.XMLHTTP") req.open "GET", "http://MiServidorWeb/MiSitioWeb/RegistrarSesion.ashx?Operacion=CierreSesion" req.send Do While req.readyState <= 1 WScript.Sleep 50 Loop
Imports System Imports System.Web Imports System.Data.SqlClient Public Class RegistrarSesion : Implements IHttpHandler Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest Using cn As SqlConnection = CrearConexion(), _ proc As New Procedimientos.RegistrarSesion(cn) Dim operacion As String = context.Request.QueryString("Operacion") If operacion = "InicioSesion" Then proc.ExecuteNonQuery(context.User.Identity.Name, 1) context.Response.Write("OK") ElseIf operacion = "CierreSesion" Then proc.ExecuteNonQuery(context.User.Identity.Name, 2) context.Response.Write("OK") Else context.Response.StatusCode = 500 context.Response.Write("Operacion no valida") End If End Using End Sub Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable Get Return False End Get End Property Private Function CrearConexion() As SqlConnection Return New SqlConnection(ConfigurationManager.ConnectionStrings("ConnectionString").ConnectionString) End Function End Class
CREATE TABLE Sesiones ( IdSesion int IDENTITY(1,1) PRIMARY KEY, FechaHora datetime NOT NULL DEFAULT GETDATE(), Usuario varchar(128) NOT NULL, Operacion tinyint NOT NULL ) GO CREATE PROCEDURE RegistrarSesion( @Usuario varchar(128), @Operacion tinyint ) AS INSERT INTO Sesiones(Usuario, Operacion) VALUES (@Usuario, @Operacion) GO
Cuando Visual Basic 9.0 (ó 2008) crea un tipo anónimo en una consulta de LINQ (siempre crea un tipo anónimo para el valor devuelto por la cláusula Select), se ve que las propiedades las clasifica por orden alfabético, pero en el orden de los nombres de esas propiedades.
Nota:Este artículo lo escribo a raíz de una consulta de erickorlando en mis foros.Si quieres ver ese hilo, pulsa en este link:http://foros.elguille.info/Mensajes.aspx?ID=39024
Esto en principio no es problema, pero cuando el resultado de esa consulta se asigna a un DataGridView, ese control crea automáticamente las columnas (cabeceras) a partir de las columnas de los datos que se le asigna, y en el caso de asignarle el resultado de una consulta LINQ, esas columnas no son otra cosa que las propiedades del tipo anónimo creado en la orden Select. Y debido a que VB ordena las propiedades/columnas por el nombre de las mismas, resulta que es posible que lo que se muestre en el DataGridView no sea lo deseado.
Por ejemplo, si tenemos una consulta como la de este código:
' Listado 1 Dim cust = From c In northwind.Customers _ Where c.CompanyName.StartsWith("L") _ Order By c.CustomerID, c.CompanyName, c.ContactName _ Select c.CustomerID, c.CompanyName, c.ContactName ' En DataGridView se clasifica como CompanyName, ContactName, CustomerID DataGridView1.DataSource = cust
El DataGridView genera las columnas tal como se ve en la figura 1.Fíjate que en vez de mostrarse tal como se indica en el Select, se ha clasificado por el nombre de las propiedades.
Figura 1. Las columnas del grid están por orden alfabético
La solución que proporciona erickorlando en el hilo que te he comentado antes, es creando un tipo anónimo que tenga los nombres de las columnas de forma que se clasifiquen bien y se muestren los datos como se quiere... es decir, primero el ID del cliente, después la empresa y por último el nombre del contacto.Este es el código que hace eso:
' Listado 2 Dim cust = From c In northwind.Customers _ Where c.CompanyName.StartsWith("L") _ Order By c.CustomerID, c.CompanyName, c.ContactName _ Select New With {Key .Cliente = c.CustomerID, _ Key .Compañia = c.CompanyName, _ Key .Contacto = c.ContactName} DataGridView1.DataSource = cust
Ese mismo código se puede escribir también de esta forma:
' Listado 3 Dim cust = From c In northwind.Customers _ Where c.CompanyName.StartsWith("L") _ Order By c.CustomerID, c.CompanyName, c.ContactName _ Select Cliente = c.CustomerID, _ Compañia = c.CompanyName, _ Contacto = c.ContactName DataGridView1.DataSource = cust
La diferencia entre el listado 2 y el 3, es que en el segundo las propiedades son de solo lectura (Key indica que es de solo lectura) y en el listado 3, son de lectura y escritura, además de que, para generar el tipo anónimo no es necesario indicarlo explícitamente. Es la ventaja de VB, je, je, que hasta en esto nos facilita el trabajo.
Los dos listados anteriores mostrarán los datos como en la figura 2.
Figura 2. Las columnas ordenadas como queremos
El problema de esta solución es que si esos nombres de las propiedades indicadas después de Select no están en el orden que nos gustaría, pues... que no se mostrarían como queremos.
Por tanto, la solución que "casi" nos puede solucionar la papeleta es decirle al DataGridView que no genere automáticamente los nombres, de las columnas.Pero si le decimos eso... pues... ¡no veremos nada! (o casi), así que... tenemos que crear las columnas manualmente, indicar qué queremos que se muestre en la cabecera del DataGridView... pero lo más importante es que le tenemos que indicar qué columna de los datos corresponde con cada columna del DataGridView.Los nombres de las columnas de los datos son los nombres de las propiedades del tipo anónimo que creamos en la consulta de LINQ, para ser más concreto los nombres que usemos en el Select.
Este es el código que no genera los nombres de las columnas del DataGridView y que puedes usar para que estén en el orden que te interese:
' Listado 4 Dim cust = From c In northwind.Customers _ Where c.CompanyName.StartsWith("L") _ Order By c.CustomerID, c.CompanyName, c.ContactName _ Select c.CustomerID, c.CompanyName, c.ContactName DataGridView1.AutoGenerateColumns = False DataGridView1.Columns.Clear() DataGridView1.Columns.Add("CustomerID", "CustomerID") DataGridView1.Columns.Add("CompanyName", "CompanyName") DataGridView1.Columns.Add("ContactName", "ContactName") DataGridView1.Columns(0).DataPropertyName = "CustomerID" DataGridView1.Columns(1).DataPropertyName = "CompanyName" DataGridView1.Columns(2).DataPropertyName = "ContactName" DataGridView1.DataSource = cust
Fíjate que lo que hay en la cláusula Select es lo mismo que en el listado 1, es decir, los nombres de las columnas de la tabla Customers de la base de datos Northwind.
Esos nombres de las columnas de la tabla son los que el compilador de Visual Basic creará para los nombres de las propiedades del tipo anónimo que se crea siempre con Select. Pero como ya vimos que el VB ordena alfabéticamente esas propiedades, lo que tenemos que hacer es asignar al DataGridView lo que queremos que se muestre, y en el orden que nos interese. En este caso, las columnas se muestran en el mismo orden que están indicadas después de Select, y el resultado sería el de la figura 3.
Figura 3. Las columnas ordenadas manualmente
El código del listado 3, hace lo siguiente:
Figura 4. Si no borramos las columnas, se van acumulando
Figura 5. Cabeceras personalizadas
' Listado 5 DataGridView1.Columns.Add("CustomerID", "ID") DataGridView1.Columns.Add("CompanyName", "Empresa") DataGridView1.Columns.Add("ContactName", "Contacto")
Nota:Si el código del listado 4 lo pones junto con otros códigos que manipulen el contenido del DataGridView, debes borrar siempre el contenido de las columnas: DataGridView1.Columns.Clear() antes de asignar los datos al DataGridView por medio de la asignación a la propiedad DataSource. Al menos si no quieres que haya columnas huérfanas, al estilo de la figura 4.
Y si siempre vas a usar esas columnas con el DataGridView, puedes escribir todo el código que hay después de crear la consulta LINQ y antes de asignar el valor al DataSource en el evento Load del formulario o en cualquier otro sitio, ya que si siempre vas a asignar los mismos datos (las mismas columnas/propiedades), pues... te evitas estar repitiendo ese código.
Tal como te comento, todo este "follón" solo es necesario hacerlo con Visual Basic, ya que en C# no se ordenan las propiedades de los tipos anónimos generados en la cláusula select.En el siguiente código tienes lo que habría que escribir en C# para tener algo parecido a la figura 3.
// Listado 6 var cust = from c in northwind.Customers where c.CompanyName.StartsWith("L") orderby c.CustomerID, c.CompanyName, c.ContactName select new {c.CustomerID, c.CompanyName, c.ContactName}; DataGridView1.DataSource = cust;
En el ZIP tienes dos proyectos, uno para Visual Basic y el otro para C#.
En esos proyectos se usan objetos LINQ to SQL, que están conectados a la base de datos Northwind, por tanto, debes tener esa base de datos y seguramente tendrás que cambiar la cadena de conexión, ya que la que yo uso es:Data Source=(local)\sqlexpress; Initial Catalog=Northwind; Integrated Security=True.
P.S. Si quieres saber más sobre todo lo referente a LINQ y otras novedades de Visual Basic 9.0 (ó 2008), te recomiendo que compres mi libro electrónico Las Novedades de Visual Basic 9.0. ;-))))
System.Windows.FormsSystem.Linq
Este artículo también lo puedes ver en mi sitio:http://www.elguille.info/NET/dotnet/LINQ_orden_columnas_DataGridView_VB9.aspx Y puedes bajarte los proyectos de prueba para Visual Basic 9.0 y C# 3.0
En este artículo te explico los pasos para añadir un DataSet tipado (conjunto de datos) a un proyecto de Visual Studio 2008. Estos pasos, entre otras cosas, te serán de utilidad si quieres usar todo lo relacionado con LINQ to DataSet.
Nota:Estos pasos te serán de utilidad para seguir el ejemplo del capítulo 9 de mi libro Novedades de Visual Basic 9.0.
Empecemos añadiendo un DataSet a nuestro proyecto, ese objeto tendrá inicialmente la tabla Employees de la base de datos Northwind, que es la que utilizaremos en nuestro primer ejemplo, después veremos cómo agregar más información a ese DataSet.
Creo que a estas alturas de la programación "asistida" ya sabremos crear un DataSet con los asistentes, pero por si algún lector ha llegado hasta aquí sin antes haber usado un asistente, veamos los pasos que tendremos que dar.
Para simplificar las cosas y no distraernos, vamos a crear un proyecto de tipo consola, ya que lo que realmente interesa es el código que tenemos que escribir, de otras facilidades ya nos ocuparemos en otra ocasión (aunque sea sin mi asistencia directa).
En el proyecto, desde el menú contextual en el Explorador de soluciones (figura 1), seleccionamos agregar un nuevo elemento, y de ese cuadro de diálogo, seleccionamos Conjunto de datos (DataSet en inglés) y le damos el nombre NorthwindDataSet.xsd, tal como vemos en la figura 2.
En unos segundos tendremos el diseñador del DataSet en blanco, ahora tendremos que crear una conexión a la base de datos de la que queremos obtener la información.
Nota:Los pasos que siguen a continuación son válidos para Visual Studio 2008, pero no para la versión Express de Visual Basic 2008, ya que las versiones Express solo permiten crear conexiones asistidas a archivos de bases de datos no a una instancia de SQL Server, si utilizas la versión Express, tendrás que crear manualmente la conexión al servidor de SQL Server.Puedes ver este artículo para un ejemplo paso a paso de cómo crear esa conexión a un servidor de SQL Server desde la versión Express de Visual Basic:http://www.elguille.info/NET/ADONET/base_sql_asistente_express.htm.
Figura 1. Agregar un nuevo elemento desde el explorador de soluciones
Figura 2. Agregamos un nuevo conjunto de datos (DataSet)
Para crear la cadena de conexión a una base de datos, debemos mostrar la ventana del Explorador de servidores (si no está visible, podemos mostrarla desde el menú Ver>Explorador de servidores o pulsando las teclas Ctrl+Alt+S), en esa ventana seleccionamos Conexiones de datos y del menú mostrado al pulsar con el botón secundario del ratón seleccionamos Agregar conexión (figura 3), esta acción nos mostrará un cuadro de diálogo en el que se nos pide que indiquemos la base de datos queremos usar, y debido a que en Visual Studio 2008 tenemos varias formas de hacerlo, nos mostrará un cuadro de diálogo como el de la figura 4 para seleccionar el "origen de datos".
Figura 3. Agregar una nueva conexión al explorador de servidores
Figura 4. Elegir el proveedor del origen de datos
En el cuadro de diálogo Elegir origen de datos, seleccionamos Microsoft SQL Server y pulsamos en Continuar, ahora tendremos un nuevo cuadro de diálogo en el que indicaremos el servidor de SQL Server en el que tenemos la base de datos a la que queremos acceder (en mi caso la he instalado en la instancia de SQLEXPRESS) y una vez indicado el servidor, podremos elegir la base de datos de la lista desplegable que hay bajo la opción Seleccione o escriba el nombre de la base de datos, tal como vemos en la figura 5.
Figura 5. Seleccionamos el servidor de SQL Server y la base de datos para la conexión
Después de aceptar, veremos en el Explorador de servidores la nueva conexión, si expandimos la conexión y mostramos el contenido, podremos elegir la tabla que queremos incluir en el DataSet, para nuestro ejemplo, seleccionaremos la tabla Employees y la arrastramos hasta el diseñador del "conjunto de datos" (figura 6).
Figura 6. Desde las conexiones de datos, agregamos las tablas que queremos tener en el DataSet
Una vez que tenemos definido correctamente el DataSet que queremos usar, podemos pasar al código del Modulo1 y empezar a escribir nuestro código para acceder al contenido del DataSet que acabamos de crear.
P.S.Este artículo también está publicado en mi sitio: http://www.elguille.info/NET/ADONET/novedadesVB9_DataSet_tipado.aspx
El código fuente lo podéis desargar de aquí y e instalador lo podéis descargar de aquí.
El generador sigue siendo una solución de Visual Studio 2005 que para abrirla se necesita el Visual Studio 2005 SDK de febrero de 2007 y el Wix 3.0