Del Articulo al Albaran

‘ A tren de una consulta de como duplicar filas de un DGV a otro

‘ a petición de Raul os dejo esta idea (muy básica) de como

‘ componer un «albarán» a partir de un DGV con los datos del articulo.

‘ Al realizar un doble clic sobre una fila de artículos

‘ se abrirá un cuadro de dialogo pidiendo la cantidad

‘ una vez introducida, crearemos una nueva línea en un

‘ DataGridView personalizado para contener la entradas

‘ de un albarán… evidentemente ficticio.

‘Ejemplo utilizando VB2008

ArticulosYFacturas

Imports System.Data.OleDb

 

Public Class Form1

   

    ‘Definir objectos de conexion a base de datos

    Private MiConexion As New OleDbConnection(«Provider=Microsoft.Jet.OLEDB.4.0; Data Source=MiBd.mdb;»)

    Private MiAdaptador As New OleDbDataAdapter(«SELECT * FROM Articulos», MiConexion)

    Private MiDataSet As New DataSet()

    Private MiEnlazador As New BindingSource

 

   

    ‘tareas en tiempo de carga de la aplicación

    Private Sub Form1_Load() Handles MyBase.Load

        ‘Abrir conexion y llenar el dataset

        MiConexion.Open()

        MiAdaptador.Fill(MiDataSet)

        Dim commandbuilder As New OleDb.OleDbCommandBuilder(Me.MiAdaptador)

        ‘Asignamos el origen de datos para del DataGridView

        Me.DataGridView1.DataSource = MiDataSet.Tables(0)

        ‘Cerrar la conexión

        MiConexion.Close()

        ‘Clonar o…

        ‘Reproducir la estructura del 1er dataGrid en DataGridView2

        ‘añadiendo una columna para la cantidad y otra para totalizar

        Me.DataGridView2.ColumnCount = Me.DataGridView1.ColumnCount + 1

        Me.DataGridView2.Columns(0).Name = «Cantidad»

        Me.DataGridView2.Columns(0).HeaderText = «Cantidad»

        For x = 1 To Me.DataGridView1.ColumnCount – 1

            Me.DataGridView2.Columns(x).Name = Me.DataGridView1.Columns(x).Name

            Me.DataGridView2.Columns(x).HeaderText = Me.DataGridView1.Columns(x).HeaderText

        Next

        Me.DataGridView2.Columns(DataGridView1.ColumnCount).Name = «Total»

        Me.DataGridView2.Columns(DataGridView1.ColumnCount).HeaderText = «Total»

        Me.DataGridView2.AllowUserToAddRows = False

    End Sub

   

    ‘ Al hacer doble click sobre la fila del articulo esta se duplica en el segundo grid

   

    Private Sub DataGridView1_DoubleClick(….) Handles DataGridView1.DoubleClick

        If DataGridView1.SelectedRows.Count > 0 Then

            ‘Añadir los valores obtenidos de la fila seleccionada

            ‘al segundo datagridview

            Dim Unidades = InputBox(«Numero de unidades para :» _
                + DataGridView1.SelectedRows.Item(0).Cells(1).Value, «Cantidad»)

            If Unidades.Length > 0 Then

                Me.DataGridView2.Rows.Add( _

                   FilaAlbaran( _

                                Unidades, _

                                DataGridView1.SelectedRows.Item(0)) _

                              )

            End If

        End If

    End Sub

   

    ‘ Componer la nueva entrada al DGV del albaran

   

    Function FilaAlbaran(ByVal cantidad As String, ByVal fila As DataGridViewRow) As String()

        ‘Dimensionar el array al tamaño de columnas del DGV + una de total

        Dim Contenido(Me.DataGridView1.ColumnCount) As String

        ‘La primera columna corresponde a la cantidad

        Contenido(0) = cantidad

        ‘Rellenar el contenido con el valor de las celdas de la fila

        For Ndx = 1 To Contenido.Length – 2

            Contenido(Ndx) = fila.Cells(Ndx).Value

        Next

        ‘Calcular y mover a la columna total el resultado de la cantidad por el precio

        Contenido(Contenido.Length – 1) = cantidad * Contenido(Contenido.Length – 2)

        Return Contenido

    End Function

End Class

Copiar o mover filas de un DataGridView a otro.

Atendiendo a la consulta de Javier..

Hola Pep Lluis, he leído varias veces las soluciones que das en los diferentes espacios y foros, y quizá esta pregunta te la hayan hecho ya, pero la verdad ando algo atorado con este problemilla… ahí va :
La idea es tener 2 datagrid’s : el1er Datagrid : Muestra el resultado de una búsqueda, de este datagrid deben seleccionar 1 o varios registros y deberán pasarse al 2do Datagrid : Que debe mostrar los registros seleccionados en el 1er datagrid.Si paso un registro del Datagrid 1 al 2, el registro desaparecerá del 1 y aparecerá en el 2, y viceversa.

____

DgvToDgv

Supongo que existen diversas formas de conseguir lo mismo y sin duda más sofisticadas pero como siempre buscando la simplicidad y en pro de la comprensión os muestro el siguiente ejemplo evitando a exprofeso estructuras complejas difíciles de seguir.

 Para poder tener visión sobre dos maneras distintas de hacerlo, he decido mostrar el primer DGV unido a una estructura de datos y el segundo “clonado” pero sin estar enlazado a ninguna BD, por lo tanto deberéis situar el ejemplo como un punto de partida, en ningún caso como una solución concreta y mucho menos pensando en dos DGV’s enlazados a datos y con relaciones… pues la cosa puede complicarse ligeramente y como os digo no es el propósito ni alcance de este corto.

Tampoco contempla en qué orden y como se ordenan los registros o filas que se copian o mueven de un lado a otro J, también he obviado procesar la excepciones para concentrarnos solo en el código que puede interesarnos… por lo que no está libre de ‘errores’.

Para utilizar este código tienes que crear un nuevo proyecto “Windows Form Application” desde el menú de Visual Basic y arrastrar y soltar dos DGV’s, dos CheckBox y dos Botones de la ventana de herramientas, a continuación solo debes copiar y pegar este código substituyendo el generado por el ‘wizard’. También debes crear una BD de Access en la carpeta ‘debug’ conteniendo la tabla de la BD referenciada en la cadena de conexión, para poder leer tanto código comodamente,.me he tomado la libertad de eliminar las firmas de las funciones, por lo que tendréis de substituir el “(….)” Por el ‘ByVal sender As System.Object, ByVal e As System.EventArgs’ correspondiente en VB2005 o dejarlo simplemente () en VB2008.

Espero que os sea útil,
Saludos!
Pep Lluis,

Imports System.Data.OleDb

Public Class Form1
   
    ‘Definir objectos de conexion a base de datos
    Private MiConexion As New OleDbConnection(«Provider=Microsoft.Jet.OLEDB.4.0; Data Source=TuBd.mdb;»)
    Private MiAdaptador As New OleDbDataAdapter(«SELECT * FROM TuTabla», MiConexion)
    Private MiDataSet As New DataSet()
    Private MiEnlazador As New BindingSource

   
    ‘tareas en tiempo de carga de la aplicación
    Private Sub Form1_Load(….) Handles MyBase.Load
        ‘Abrir conexion y llenar el dataset
        MiConexion.Open()
        MiAdaptador.Fill(MiDataSet)
        Dim commandbuilder As New OleDb.OleDbCommandBuilder(Me.MiAdaptador)
        ‘Asignamos el origen de datos para del DataGridView
        Me.DataGridView1.DataSource = MiDataSet.Tables(0)
        ‘Cerrar la conexión
        MiConexion.Close()
        ‘Clonar o…
        ‘Reproducir la estructura del 1er dataGrid en DataGridView2
        Me.DataGridView2.ColumnCount = Me.DataGridView1.ColumnCount
        For x = 0 As Integer To Me.DataGridView1.ColumnCount – 1
            Me.DataGridView2.Columns(x).Name = Me.DataGridView1.Columns(x).Name
            Me.DataGridView2.Columns(x).HeaderText = Me.DataGridView1.Columns(x).HeaderText
        Next
        Me.CheckBox1.Checked = True     ‘por defecto al iniciar seleccionamos
        Me.CheckBox2.Checked = False    ‘Operaciones origen DGV1, destino DGV2
    End Sub
   
    ‘Boton Copiar
    Private Sub Btn_Copiar_Click(….) Handles Btn_Copiar.Click
        ‘determinar la direccion de copiar entre DGV1 y 2
        If CheckBox1.Checked Then

            ‘Comprobar que existen columnas seleccionadas
            If DataGridView1.SelectedRows.Count > 0 Then
                CopiarSeleccionadosDGV1aDGV2()
            End If
        Else
            If DataGridView2.SelectedRows.Count > 0 Then
                CopiarSeleccionadosDGV2aDGV1()
            End If
        End If
    End Sub
   
    ‘Boton Mover
    Private Sub Btn_Mover_Click(….) Handles Btn_Mover.Click
        ‘determinar la direccion de mover entre DGV1 y 2
        If CheckBox1.Checked Then
            ‘Comprobar que existen columnas seleccionadas
            If DataGridView1.SelectedRows.Count > 0 Then
                MoverSeleccionadosDGV1aDGV2()
            End If
        Else
            If DataGridView2.SelectedRows.Count > 0 Then
                MoverSeleccionadosDGV2aDGV1()
            End If
        End If
    End Sub
   
    ‘Copiar los elementos seleccionados del DGV1 al DGV2
    Sub CopiarSeleccionadosDGV1aDGV2()
        For Each Seleccion As DataGridViewRow In DataGridView1.SelectedRows
            Me.DataGridView2.Rows.Add(ObtenerValoresFila(Seleccion))
        Next
        DataGridView1.ClearSelection()
    End Sub
   
    ‘Copiar los elementos seleccionados del DGV1 al DGV2
    Sub CopiarSeleccionadosDGV2aDGV1()
        For Each Seleccion As DataGridViewRow In DataGridView2.SelectedRows
            Me.MiDataSet.Tables(0).Rows.Add(ObtenerValoresFila(Seleccion))
        Next
        DataGridView2.ClearSelection()
    End Sub
   
    ‘Mover los elementos seleccionados del DGV1 al DGV2
    Sub MoverSeleccionadosDGV1aDGV2()
        ‘Para cada fila seleccionada
        For Each Seleccion As DataGridViewRow In DataGridView1.SelectedRows
            ‘Añadir los valores obtenidos de la fila seleccionada
            ‘al segundo datagridview
            Me.DataGridView2.Rows.Add(ObtenerValoresFila(Seleccion))
            ‘eliminar la fila del DataGridView origen
            DataGridView1.Rows.Remove(Seleccion)
        Next
    End Sub
   
    ‘Mover los elementos seleccionados del DGV1 al DGV2
    Sub MoverSeleccionadosDGV2aDGV1()
        ‘Para cada fila seleccionada
        For Each Seleccion As DataGridViewRow In DataGridView2.SelectedRows
            ‘Añadir los valores obtenidos de la fila seleccionada
            ‘al segundo datagridview
            Me.MiDataSet.Tables(0).Rows.Add(ObtenerValoresFila(Seleccion))
            ‘eliminar la fila del DataGridView origen

            DataGridView2.Rows.Remove(Seleccion)
        Next
    End Sub
   
    ‘Obtener el contenido de la fila en un string()
    ‘con el proposito de copiarlo o moverlo
   
    ‘Recibe el ‘row’ y retorna su contenido en un array tipo string
    Function ObtenerValoresFila(ByVal fila As DataGridViewRow) As String()
        ‘Dimensionar el array al tamaño de columnas del DGV
        Dim Contenido(Me.DataGridView1.ColumnCount – 1) As String
        ‘Rellenar el contenido con el valor de las celdas de la fila
        For Ndx As Integer = 0 To Contenido.Length – 1
            Contenido(Ndx) = fila.Cells(Ndx).Value
        Next
        Return Contenido
    End Function
   
    ‘Seleccionar la direccion en que se efectuara la copia
    Private Sub CheckBox1_CheckedChanged(….) Handles CheckBox1.CheckedChanged
        CheckBox2.Checked = Not CheckBox1.Checked
    End Sub
    Private Sub CheckBox2_CheckedChanged(….) Handles CheckBox2.CheckedChanged
        CheckBox1.Checked = Not CheckBox2.Checked
    End Sub
End
Class

Leer los ceros y unos de un micro-controlador

En muchas situaciones, sobre todo cuando hablamos de PIC’s se plantean cuestiones en torno como manejar un simple aplicación de intercambio de datos utilizando el IO.Ports.

A falta de un ejemplo concreto os facilito este código, aunque en anteriores Post’s podéis aprender algunas observaciones y consideraciones a tener en cuenta.

El siguiente ejemplo, envía una petición al micro-controlador cada 100ms, siempre y cuando no este ocupado esperando una respuesta. La respuesta se compone del Byte enviado mas un ‘0’ o un ‘1’, por lo tanto después de identificar la respuesta añadiremos el estado a un ‘Label1’ que acumulara todas las respuestas o dicho de otro modo todos los Ceros y Unos J

CerosYUnos

No dudéis en seguir la conversación si os interesa discutir algún aspecto en concreto. Pero como siempre estos ejemplos son muy ligeros, pretendiendo ser una idea inicial para demostrar que es posible, aunque distan mucho de ser la solución completa o ideal.

Saludos,
Pep Lluis,

Public Class Form1
    Private PuertoSerie As New IO.Ports.SerialPort
    Private Temporizado As New System.Timers.Timer
    Private IOEncurso As Boolean = False
    Delegate Sub ActualizarTexto(ByVal Texto As String)

    Private Sub Form1_Load(….) Handles MyBase.Load
        Temporizado.Interval = 100
        ‘cada 100ms ejecutar la funcion TareasTemporizadas
        AddHandler Temporizado.Elapsed, AddressOf TareasTemporizadas
        ‘Abrir el puerto serie
        PuertoSerie = My.Computer.Ports.OpenSerialPort(«COM1», 115200, IO.Ports.Parity.Even, 7, IO.Ports.StopBits.Two)
        ‘ejecutar la funcion recepcion al recibir datos
        AddHandler PuertoSerie.DataReceived, AddressOf Recepcion
        Temporizado.Start()
    End Sub

    ‘Buffer de recepcion
    Private Dato(1) As Byte
    Sub Recepcion()
        Try
            ‘Añadir la recepcion actual al buffer           
            If PuertoSerie.BytesToRead > 1 Then
                ‘Leer dos bytes
                PuertoSerie.Read(Dato, 0, 2)
                ‘Verificar que el primero identifica inicio
                Select Case Chr(Dato(0))
                    Case «R»
                        ‘añadir el status leido (0 o 1) al Label
                        Actualizar_Etiqueta(Label1.Text + Chr(Dato(1)))
                    Case Else
                        ‘descartar el contenido del buffer
                        ‘pues el dato(0) no corresponde a inicio
                        PuertoSerie.DiscardInBuffer()
                End Select
                ‘Dar por finalizada la respuesta
                IOEncurso = False
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message)
            IOEncurso = False
        End Try
    End Sub
   
    ‘Utilizamos el INVOKE de LABEL1 Para evitar error..
    ‘ Operación no válida a través de subprocesos:
      Se tuvo acceso al control ‘Label1’ desde
      un subproceso distinto a aquel en que lo creó.
    Private Sub Actualizar_Etiqueta(ByVal [texto] As String)
        ‘Mostrar los bytes recibidos en el Label1       
        If Me.Label1.InvokeRequired Then
            Dim delegado As New ActualizarTexto(AddressOf Actualizar_Etiqueta)
            Me.Invoke(delegado, New Object() {[texto]})
        Else
            Me.Label1.Text = [texto]
        End If
    End Sub
   
    ‘Controlar el envio de peticiones
    ‘ en nuestro caso cada 100ms
    Sub TareasTemporizadas()
        ‘Solo enviar una nueva peticion
        ‘si se ha completado la anterior
        If Not IOEncurso Then
            PuertoSerie.Write(«R»)
            IOEncurso = True
        End If
    End Sub
End
Class

Para finalizar y dar otros puntos de vista, según las escuelas pueden utilizarse formas tales como:

Dim PuertoSerie As New IO.Ports.SerialPort
PuertoSerie =
My.Computer.Ports.OpenSerialPort(«COM1»)
….

….

PuertoSerie.Write(«Peticion»)
System.Threading.Thread.Sleep(100) 
‘Dar tiempo al dispotivo
Dim Resultado() As Byte(Longitud)
PuertoSerie.Read(Resultado, 0, Longitud, 10000)

 

  ‘ donde 10000 es el timepo predefinido para
  ‘ que el puerto serie dispare una excepcion

  ‘ por tiempo de expera excedido

A pesar de que en mi opinión, utilizar ‘Sleeps’ y técnicas de esperar un fuera de tiempo no cumple con las expectativas de un programa que se precie. Pero esto ultimo no deja de ser una opinión muy personal.

 

 

 

 

Problemas en la recepción de datos

Considerando interesante la pregunta y con el permiso de Cream, me gustaría compartir esta pequeña cuestión en tanto a la metodología  en la recepción de datos usando el IO.Ports.

La pregunta:
“no siempre recibo bien los datos o no los capturo por el puerto serie”.. el código que estoy usando actualmente es el siguiente :

puertoSerie.write(«R»)                                              ‘enviamos carácter
dato=Asc(puertoSerie.ReadExisting.Chars(1))          ‘leemos y cogemos valor de x

Una de las características de las comunicaciones serie en uno de sus modos, es que son asíncronas… lo que significa que los ‘Bytes’ se serializan y transmiten sin que el receptor conozca el momento preciso. Es decir el bit de ‘start’ indica al receptor el envío de un ‘byte’ pero en ningún caso y por ausencia de protocolo conocemos de antemano la cantidad de ‘bytes’ que vamos a recibir asi como el intervalo de tiempo que va a transcurrir en la transmision  entre byte’s.

Como tu bien dices y expresas en tus razonamientos, estas ejecutando la lectura directamente sin esperar al evento de ‘Data Received’,  es presumible que en la rapidez de proceso del PC nos dispare la excepción de   “index out of range exception”  pues estas intentando procesar la posición del segundo carácter que evidentemente aun no has recibido y por lo tanto es inexistente.

El mandato ReadExisting, lee los bytes recibidos que actualmente permanecen en el buffer, en tu caso y en ocasiones, dependiendo del flujo de ejecución, en el buffer debes tener por leer, 0, quizas 1 o cuando te funciona bien2 bytes.

La práctica correcta es formalizar el intercambio de tramas delimitándolas con un carácter de inicio y otro de fin… por ejemplo la mayoría implementan el CR o Chr(13) como fin de trama, algunos fabricantes optan por utilizar como fin de trama secuencias tales como 2 bytes de FCS + Un Carácter identificativo + LF + CR, en fin como siempre hay para todos los gustos. Al menos con este método podrás estar seguro de que la transmisión a finalizado correctamente.

Deberías implementar el disparo de recepción y procesar los datos una vez se ha completado la recepción.  En todo caso otra opción podría ser algo parecido a:

‘String de recepción utilizado como buffer
Private PortSerie_Recepcion As String = «»    
‘Anadir el manipulador de recepción en la sub New, Load…   
AddHandler Serie.DataReceived, AddressOf Rx
 
Sub
Rx(ByVal sender As Object, _
       ByVal e As serialDataReceivedEventArgs)       
   Try

    ‘Añadir la recepción actual al buffer            
    PortSerie_Recepcion += Serie.ReadExisting
    If PortSerie_Recepcion.Contains(Chr(13)) Then                
        ….PROCESAR LA INFORMACION
        PortSerie_Recepcion = «»           
    End If       
   Catch ex As Exception
    ‘En caso de excepción       
  End Try   
 End Sub

Si la longitud de tus tramas es de 2 bytes… una idea muy básica puede ser controlar el número de caracteres que están en el buffer pendientes de ser leídos y antes de procesarlos con: PuertoSerie.BytesToRead

         Prohibido definitivamente
       
        If PuertoSerie.BytesToRead = 2 Then
            dato = Asc(PuertoSerie.ReadExisting.Chars(1))
       
End If

        ‘ Definitivamente NO ES RECOMENDABLE!
       
        If PuertoSerie.BytesToRead > 2 Then
            dato = Asc(PuertoSerie.ReadExisting.Chars(1))
       
End If

El problema utilizando el primer caso es que nunca se procesara el dato si no se reciben exactamente dos caracteres, por ende y peor aún si BytesToRead es > 2 nunca procesara los bytes recibidos, poniendo en apuros a nuestra aplicación cuando él se desborde el buffer de recepción. En segundo caso y en determinadas situaciones de intercambios muy rápidos o con interferencias podria perder la secuencia lecturas de pares de bytes y procesar inadecuadamente por desplazamiento de posiciones… como mal menor necesitarías usar PuertoSerie.BytesToRead > 2 conjuntamente con PuertoSerie.Read(Dato(),0,2), aunque insisto lo mejor es incluir un fin de trama en cada transmisión desde el firmware del dispositivo.

        ‘ una propuesta… Quizas

       

        Dim Trama() As Char

        If PuertoSerie.BytesToRead > 2 Then

            PuertoSerie.Read(Trama, 0, 2)

            dato = Asc(Trama(1))

        End If

Saludos,
Pep Lluis,

 

 

 

Saber de los procesos que se estan ejecutando… Ordenadamente

Efectivamente… para responder a la pregunta de si podemos ordenar la consulta, añadiremos simplemente el ‘Order By’ antes del select, tal y como sigue :

         (From procesos In ProcesosLocales _
          Order By procesos.Id _
          Select _
          New MiProcessInfo() With {.Id = procesos.Id, _
                                    .Nombre = procesos.ProcessName} _
         ).ToList
        ‘ En este caso obtenemos la lista ordenada por el Id

         (From procesos In ProcesosLocales _
          Order By procesos.ProcessName _
          Select _
          New MiProcessInfo() With {.Id = procesos.Id, _
                                    .Nombre = procesos.ProcessName} _
         ).ToList
        ‘ En este caso obtenemos la lista ordenada por el Nombre


No olvideis que se puede ordenar de mayor a menor o Viceversa usando la opcion ‘Ascending‘ o ‘Descending‘ justo despues del nombre del campo a ordenar.

Saludos,
Pep Lluis,

PD. la ‘V’ de Vice por gentileza de Fran… jajajajaja.

 

Combinar un ComboBox y un TextBox con diferentes columnas de una BD

A peticion de Ariel, me complace compartir este sencillo ejemplo de cómo enlazar el Combobox visualizando el valor de una columna asignando el conocido ‘DisplayMember’ y obteniendo el valor de otra columna con su ‘ValueMember’. De esa forma entre otras muchas aplicaciones, lo tendremos disponible y podremos visualizarlo en un textbox por poner un ejemplo.

 

Public Class Form1
    Private MiComboBox As New ComboBox
    Private MiTextBox As New TextBox

    Private Sub Form1_Load(… ..) Handles MyBase.Load
       
        ‘ Simular tabla Maestros
       
        Dim Maestros As New DataTable(«Maestro»)
        Maestros.Columns.Add(«Nombre»)
        Maestros.Columns.Add(«Matricula»)
        Maestros.Rows.Add(«Juan Jose», «1001 BCN»)
        Maestros.Rows.Add(«Alberto Juan», «2002 ABC»)
        Maestros.Rows.Add(«Antonio Miguel», «3003 NJR»)
        Maestros.Rows.Add(«Jose Maria», «4004 FCB»)
       
        ‘ Construir el DataSet
       
        Dim MiDataSet As New DataSet
        MiDataSet.Tables.Add(Maestros)
       
        ‘ Añadir un ‘ComboBox’
        ‘ Conteniendo la tabla ‘Maestro’
        ‘ mostrando la columna ‘Nombre’
        ‘ y señalando como valor a la matricula
       
        MiComboBox.DisplayMember = «Nombre»
        MiComboBox.ValueMember = «Matricula»
        MiComboBox.DataSource = MiDataSet.Tables(«Maestro»)
        MiComboBox.Dock = DockStyle.Top
        Me.Controls.Add(MiComboBox)
        AddHandler MiComboBox.SelectedIndexChanged, AddressOf ActualizarTextBox
        MiTextBox.Dock = DockStyle.Bottom
        Me.Controls.Add(MiTextBox)
        ActualizarTextBox()
    End Sub
   
    ‘ Mover el valor seleccionado del combo al textbox
    Private Sub ActualizarTextBox()
        MiTextBox.Text = MiComboBox.SelectedValue
    End Sub
End
Class

Saber de los procesos que se estan ejecutando

»
» Saber de los procesos que se estan ejecutando
»
Public Class Form1

    Private Sub Form1_Load(….) Handles MyBase.Load

        ‘Obtener la lista de procesos en ejecucion
        Dim ProcesosLocales As Process() = Process.GetProcesses
        ‘Construir un DataGridView para visualizar
        Dim MiDgv As New DataGridView
        ‘Acoplarlo al form rellenandolo en su totalidad
        MiDgv.Dock = DockStyle.Fill
        Me.Controls.Add(MiDgv)
        ‘ Podriamos utilizar : MiDgv.DataSource = ProcesosLocales.ToList
        ‘ aunque antes deberiamos contemplar las excepciones 
        ‘ derivadas de la falta de privilegios en el
        ‘ acceso a ciertas propiedades de los procesos
        MiDgv.DataSource = _
         (From procesos In ProcesosLocales Select _
          New MiProcessInfo() With {.Id = procesos.Id, _
                                    .Nombre = procesos.ProcessName} _
         ).ToList
    End Sub
End
Class

Class MiProcessInfo
   
    ‘Leer/Asignar su Id
    Private m_Id As String
    Public Property Id() As Integer
        Get
            Return m_Id
        End Get
        Set(ByVal value As Integer)
            m_Id = value
        End Set
    End Property
   
    ‘Leer/Asignar su Nombre
    Private m_Nombre As String

    Public Property Nombre() As String
        Get
            Return m_Nombre
        End Get
        Set(ByVal value As String)
            m_Nombre = value
        End Set
    End Property
End
Class

Volvemos!

Mas que un ‘Post’… una nota, en primer lugar por descubrirme la gran cantidad de personas que visitáis este humilde blog cada día, en segundo lugar para pediros paciencia y tiempo para poder responder a todas las preguntas y comentarios que durante este mes habéis dejado tan amablemente, en tercer lugar y para finalizar agradeceros los comentarios tan alentadores que por supuesto dan sentido a las horas dedicadas.

Es excitante estar de nuevo aquí con la esperanza de aportar un poquito de lo mucho que nos espera encarando la última etapa de este año.

Contento de saludaros de nuevo!
Pep Lluis,