Mostrando un cuadro de dialogo de confirmación cuando el usuario intenta eliminar una fila de un grid DataGridView

Problema: Tengo un grid con datos, pero antes de que el usuario elimine una fila, necesito que confirme si realmente desea borrarla o solo fue un descuido con el teclado.
Solución: Utilizando correctamente el evento UserDeletingRow.

El evento UserDeletingRow se ejecuta después de que el usuario presionó la tecla Supr y antes de que la fila desaparezca completamente del grid.

Para mayor entendimiento, pongo un ejemplo.

Tengo un formulario llamado Form1, el cual contiene un grid llamado DataGridView1.

Lo siguiente es lo que va en el evento UserDeletingRow.

Private Sub DataGridView1_UserDeletingRow(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewRowCancelEventArgs) _
Handles DataGridView1.UserDeletingRow
        If Not e.Row.IsNewRow Then 'Se verifica que no sea una nueva fila
            Dim response As DialogResult = MessageBox.Show("¿Está seguro?", "¿Borrar fila?", MessageBoxButtons.YesNo, _
                                                           MessageBoxIcon.Question, MessageBoxDefaultButton.Button2)
            If response = DialogResult.No Then
                e.Cancel = True
            End If
        End If
End Sub

Dos grid DataGridView en relación maestro - detalle

Problema: Tengo dos grid, donde el primero muestra los datos maestros principales, y el segundo grid, debe cambiar los datos, dependiendo de la fila seleccionada del maestro, con el detalle respectivo.

Solución: Utilizar la habilidad de relación de un dataset.

Para explicar mejor, pongo un ejemplo.

Tengo mi formulario llamado Form1, el cual contiene dos grid, GridMaestro y GridDetalle.

Todo la programación lo realizo en el load del formulario.

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Creo un dataset que va a contener las tablas maestro - detalle
        Dim ds As New DataSet

        'Creo los binding que relacionen a los grid
        Dim maestroBinding As New BindingSource
        Dim detalleBinding As New BindingSource

        'Creo la tabla maestro y lo lleno con datos
        Dim tablaMaestro As DataTable = ds.Tables.Add("tablaMaestro")
        tablaMaestro.Columns.Add("unico")
        tablaMaestro.Columns.Add("dato")
        tablaMaestro.Rows.Add(1, "AAA")
        tablaMaestro.Rows.Add(2, "BBB")
        tablaMaestro.Rows.Add(3, "CCC")

        'Creo el grid detalle y lo lleno con datos
        Dim tablaDetalle As DataTable = ds.Tables.Add("tablaDetalle")
        tablaDetalle.Columns.Add("unico")
        tablaDetalle.Columns.Add("relacion")
        tablaDetalle.Columns.Add("dato")
        tablaDetalle.Rows.Add(1, 1, "AAA-AAA")
        tablaDetalle.Rows.Add(2, 1, "BBB-AAA")
        tablaDetalle.Rows.Add(3, 1, "CCC-AAA")
        tablaDetalle.Rows.Add(1, 2, "AAA-BBB")
        tablaDetalle.Rows.Add(2, 2, "BBB-BBB")
        tablaDetalle.Rows.Add(3, 2, "CCC-BBB")
        tablaDetalle.Rows.Add(1, 3, "AAA-CCC")
        tablaDetalle.Rows.Add(2, 3, "BBB-CCC")
        tablaDetalle.Rows.Add(3, 3, "CCC-CCC")

        'Creo la relacion entre las dos tablas
        Dim columnaMaestro As DataColumn = tablaMaestro.Columns(0)
        Dim columnaDetalle As DataColumn = tablaDetalle.Columns(1)
        Dim relation As DataRelation
        relation = New DataRelation("relacion", columnaMaestro, columnaDetalle)

        'Asigno la relacion al dataset
        ds.Relations.Add(relation)

        'Relaciono el Binding Maestro al dataset
        maestroBinding.DataSource = ds
        maestroBinding.DataMember = "tablaMaestro"

        'Asigno el binding del maestro al detalle e identifico la relacion
        detalleBinding.DataSource = maestroBinding
        detalleBinding.DataMember = "relacion"

        'Asigno los grid a los binding
        GridMaestro.DataSource = maestroBinding
        GridDetalle.DataSource = detalleBinding
End Sub

La belleza aquí es la relación asignada al detalleBinding, el cual hace que al cambiar las filas en el maestro, se actualice la información en el detalle.

Mostrar datos de un grid (DataGridView) de una columna combo box (DataGridViewComboBoxCell) basados en la selección de otra columna combo box

Problema: Tengo un grid, el cual tiene dos columnas de tipo combo box, en donde, dependiendo de lo que el usuario seleccione en la primera columna combo box, debe presentarse los datos en la segunda columna combo box.
Solución: Crear una nueva celda tipo combo box y reemplazarlo por el original.

Sabemos que antes de llenar el grid con los datos, debemos primero llenar los datos de la columna combo box, y luego, pasar los datos al grid, caso contrario nos dará un bonito error de que el combo box no está relacionado con nuestros datos.

Pero cuando tenemos datos de tipo grupo - subgrupo, en donde dependiendo del grupo cambia la información del subgrupo, se debe crear un mecanismo para que, a la hora de editar la información, la segunda columna combo box, cambie con respecto a la selección de la primera.

Existen muchas maneras de hacerlo, sobre todo dependiendo de cómo se esté obteniendo la información y cómo se estén enlazando los datos al combo box.

Se puede encontrar mucha información en la red sobre la manera de realizar este mismo proceso, algunos indican que la manera más práctica es traer toda la información en la segunda columna combo box y filtarlo dependiendo de lo seleccionado.

En mi caso, que la información es demasiado extensa para traerla toda y ponerla dentro de la segunda columna del combo box, he decidido volver a traer la información desde la base de datos con lo seleccionado en el primer combo box y llenar el segundo combo box con la resultante. Esto también sirve de ayuda para que, dependiendo de los datos de una tercera y/o cuarta columna, también se deba realizar el filtro correspondiente.

Para que se entienda mejor mi explicación, voy a poner un poco de código de ejemplo.

Tengo un formulario llamado Form1, el cual contiene un grid llamado DataGridView1, el cual a su vez, tiene dos columnas combo box llamadas dtg_cmb1 y dtg_cmb2

La acción que se dispara al momento en que el usuario selecciona un dato del primer combo box es el CellValueChanged, por lo que iniciaré por allí.

Private Sub DataGridView1_CellValueChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _
Handles DataGridView1.CellValueChanged
 Dim r As Integer = e.RowIndex
 Dim c As Integer = e.ColumnIndex
 Dim dgrow As New DataGridViewComboBoxCell()
 
 Select Case c
         Case 1 'Pregunto si la columna seleccionada pertenece al primer combo box
          'Aquí realizo el llenado de los datos, dependiendo de lo seleccionado
          Using connection As SqlConnection = New SqlConnection(conn)
           Dim command As New SqlCommand("sp_datos_combobox", connection)
           command.CommandType = CommandType.StoredProcedure
           Dim adapter As New SqlDataAdapter(command)
           With command.Parameters
            .Add(New SqlParameter("@param1", SqlDbType.Int)).Value = DataGridView1.Rows(r).Cells("dtg_cmb1").Value
           End With
           Dim dataCombo As New DataTable
           adapter.Fill(dataCombo)
           'Aqui enlazo los datos al combo box
           dgrow.DataSource = dataCombo
           dgrow.DisplayMember = "campo1"
           dgrow.ValueMember = "campo2"
           
           'Aqui cambio el combo box original, por lo obtenido de la consulta
           DataGridView1.Item("dtg_cmb2", DataGridView1.CurrentCell.RowIndex) = dgrow
          End Using
 End Select
End Sub

Mostrando varios encabezados de columnas combinados en un DataGridView

Problema: Deseo tener, como en Microsoft Excel, un encabezado doble en dos columnas que estén combinados.

De esta manera.

------------------------------------------------------
|     Enero          |       Febrero         |     Marzo          |
|  Ganó | Perdió |  Ganó   | Perdió   |  Ganó | Perdió  |
------------------------------------------------------
|           |            |             |              |            |             |
|           |            |             |              |            |             |
------------------------------------------------------

Solución: Se debe personalizar el evento Paint.

Para mayor entendimiento, pongo un ejemplo.

Tengo un formulario llamado Form1, el cual contiene un grid llamado DataGridView1.

En el evento load del formulario lleno el grid.

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Lleno los datos del grid
        With DataGridView1
            .Columns.Add("", "Ganó")
            .Columns.Add("", "Perdió")
            .Columns.Add("", "Ganó")
            .Columns.Add("", "Perdió")
            .Columns.Add("", "Ganó")
            .Columns.Add("", "Perdió")

            .ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing
            .ColumnHeadersHeight = .ColumnHeadersHeight * 2
            .ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.BottomCenter
        End With
    End Sub

Luego, se personaliza el evento Paint del DataGridView.

    Private Sub dataGridView1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles DataGridView1.Paint
        Dim monthes As String() = {"Enero", "Febrero", "Marzo"}

        Dim j As Integer = 0
        While j < 6
            Dim r1 As Rectangle = Me.DataGridView1.GetCellDisplayRectangle(j, -1, True)
            r1.X += 1
            r1.Y += 1
            r1.Width = r1.Width * 2 - 2
            r1.Height = r1.Height / 2 - 2

            e.Graphics.FillRectangle(New SolidBrush(Me.DataGridView1.ColumnHeadersDefaultCellStyle.BackColor), r1)

            Dim format As New StringFormat()

            format.Alignment = StringAlignment.Center
            format.LineAlignment = StringAlignment.Center
            e.Graphics.DrawString(monthes(j \ 2), Me.DataGridView1.ColumnHeadersDefaultCellStyle.Font, _
                                  New SolidBrush(Me.DataGridView1.ColumnHeadersDefaultCellStyle.ForeColor), r1, format)
            j += 2
        End While
    End Sub

Nota: Ejemplos e información proporcionada desde está página web: Windows Forms Data Controls and Databinding FAQ

Cambiando dinámicamente, por programación, el tipo de celda DataGridViewCell de un DataGridView

Problema: Tengo un grid que contiene una columna de tipo combo DataGridViewComboBoxCell y deseo que, por medio de programación, cambiarlo a un tipo texto DataGridViewTextBoxCell, pero solo una celda en particular.
Solución: Crear un nuevo tipo y asignarlo al grid.

Para mejor comprensión, pongo un ejemplo.

Tengo un formulario llamado Form1, el cual contiene un grid llamado DataGridView1 y un botón llamado Button1.

En el load del formulario tengo el llenado del grid.

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Se llenan datos de prueba en el grid
        Dim dt As New DataTable("b")
        dt.Columns.Add("col")
        dt.Rows.Add("bb1")
        dt.Rows.Add("bb2")
        dt.Rows.Add("bb3")
        Me.DataGridView1.DataSource = dt

        'Se crea una columna combo, se llenan de datos de prueba y se añade al grid
        Dim cmb As New DataGridViewComboBoxColumn()
        cmb.Items.Add("111")
        cmb.Items.Add("222")
        cmb.Items.Add("333")
        Me.DataGridView1.Columns.Add(cmb)
End Sub

Luego, el cambio de tipo lo tengo en el evento Click del botón.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim cell As New DataGridViewTextBoxCell() 'Creamos un nuevo tipo de celda
        cell.Value = "bb1" 'Se pone un valor cualquiera
        Me.DataGridView1(1, 1) = cell 'Se lo cambia en la posicion deseada
End Sub

Nota: Ejemplos e información proporcionada desde está página web: Windows Forms Data Controls and Databinding FAQ

Mostrando un texto vertical en la celda de un DataGridView

Problema: Necesito que el texto de una celda se muestre de manera vertical.
Solución: Se debe controlar el evento CellPainting del DataGridView.

Para entenderlo mejor, pongo un ejemplo a continuación.

Tengo un formulario llamado Form1, el cual contiene un grid llamado DataGridView1.

En el load del formulario tengo el llenado del grid.

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 'Se llenan datos de prueba en el grid
 Dim dt As New DataTable()
 dt.Columns.Add("c1")
 dt.Columns.Add("c2")

 For j As Integer = 0 To 9
  dt.Rows.Add("aaaaaaaaa", "bbbb") 'Son datos cualquiera de prueba
 Next

 Me.DataGridView1.DataSource = dt

 For j As Integer = 0 To 9
  Dim height As Integer = TextRenderer.MeasureText(Me.DataGridView1(0, j).Value.ToString(), _
           Me.DataGridView1.DefaultCellStyle.Font).Width
      Me.DataGridView1.Rows(j).Height = height
 Next

 AddHandler DataGridView1.CellPainting, AddressOf dataGridView1_CellPainting 'Aqui se invoca al evento CellPainting
End Sub

Después se programa la parte del CellPainting.

No se utiliza la que viene por defecto en el Visual. Esto es copiar y pegar.

Private Sub dataGridView1_CellPainting(ByVal sender As Object, ByVal e As DataGridViewCellPaintingEventArgs)
 If e.ColumnIndex = 0 AndAlso e.RowIndex > -1 AndAlso e.Value IsNot Nothing Then
         e.Paint(e.CellBounds, DataGridViewPaintParts.All And Not DataGridViewPaintParts.ContentForeground)

             Dim sf As New StringFormat()

             sf.Alignment = StringAlignment.Center
             sf.LineAlignment = StringAlignment.Center
             sf.FormatFlags = StringFormatFlags.DirectionVertical 'Aqui le indico que sea vertical

             e.Graphics.DrawString(e.Value.ToString(), e.CellStyle.Font, New SolidBrush(e.CellStyle.ForeColor), e.CellBounds, sf)

             e.Handled = True
        End If
End Sub

Nota: Ejemplos e información proporcionada desde está página web: Windows Forms Data Controls and Databinding FAQ

Trigger con update - Insertar más de un registro

Problema: Por motivos varios, estoy usando un trigger que cuando actualiza el dato de una tabla, esa misma información se inserta en otra. El problema surge cuando lo actualizado son varios registros, todos contenidos en la famosa tabla lógica inserted, ¿cómo inserto cada uno de esos registros en la otra tabla?
Solución: Pidiendo ayuda en el internet, me dijeron de todo, desde que no usara triggers sino stored procedures hasta que cambiara de base de datos, pero mi problema persistía. Muchas veces estuve tentada a usar cursores y matar mi base de datos, pero en un foro que nada tenía que ver con el tema, se me iluminaron las ideas. Y para no usar cursores, utilicé un método poco ortodoxo de ir procesando registro por registro la tabla inserted.

¿Cómo? Primero debo poner en una temporal lo que contiene dicha tabla

SELECT * INTO #tmp_inserted FROM inserted

Luego empiezo a recorrer fila por fila la tabla. La belleza aquí es usar el set rowcount 1 para que solo se procese una fila, con dicha fila hacer lo que necesitemos, en mi caso insertar los datos en otra tabla, y luego eliminar la fila de la temporal y procesar la siguiente. Más o menos como un cursor pero utilizando menos procesos.

El código queda algo parecido a lo siguiente.

CREATE TRIGGER trigger1
ON Base_Datos..tabla
AFTER UPDATE
AS

IF UPDATE(campo) --Sirve para verificar que el trigger se ejecute solo cuando se actualice un campo en especial
BEGIN
 --Temporal para recorrer cada uno de los registros
 SELECT * INTO #tmp_inserted FROM inserted

 --Recorro cada uno de los registros
 While(Exists(select * from #tmp_inserted))
 BEGIN
  set ROWCOUNT 1
  
  --Aqui van mis procesos de inserción
  
  --Al final borro el registro procesado
  delete from #tmp_inserted
  set ROWCOUNT 0
 END
END

Joomla 2.5 para Pendrive USB

Problema: Por las diferentes cuestiones de la vida, estoy utilizando un servidor de contenidos como el Joomla, el cual sirve para la fácil creación de páginas web. Pero por movilidad, necesito tener instalado en mi pendrive usb todo lo que he realizado y que funcione desde cualquier computadora.
Solución: No fue fácil encontrar una solución directa, pero gracias a la ayuda de varios foros del internet, me indicaron una manera más o menos óptima de realizarlo.

Necesité descargar una versión de servidor portable del Joomla, el cual descomprimí en mi computadora. Esta versión trae todo lo necesario para funcionar sin necesidad de tener nada instalado. Pero la versión de prueba que allí trae es de una anterior de Joomla, por lo que necesité actualizarle con una superior. Luego lo copié todo a mi pendrive usb y funcionó perfectamente.

Mi versión modificada de Joomla se encuentra aquí: Joomla 2.5 para Pendrive USB

Le explico un poco el cómo funcionar para la versión 2.5

Luego que se descarga y descomprima el archivo en el pendrive usb, se debe abrir el archivo iniciar.exe, el cual mostrará un icono de joomla en la barra de la hora.

Ese icono servirá para abrir el menú del servidor al darle un clic.

En el menú se deberá dar clic en "Iniciar Servidor (Apache MySql)" para iniciar el proceso. Cuando se termine de trabajar se deberá dar clic en "Parar Servidor (Apache MySql)" y en "Salir" antes de retirar el pendrive usb.

Para detalles más específicos de cada una de las funciones del menú, se puede revisarlo desde aquí: Joomla! Spanish Server 2.0 Guía rápida de ayuda

Luego se puede abrir el navegador de su agrado e iniciar el administrador de Joomla 2.5 escribiendo lo siguiente en la barra de direcciones: http://localhost/joomla25/administrator/

Se abrirá la página de Administración del Joomla 2.5

El usuario es admin y la contraseña es admin

Y listo para funcionar.

Aquí se podrá instalar los componentes y módulos que se deseen, personalizandolo a su gusto. Sobre todo de manera portable para que pueda ser mostrado en cualquier computadora.

Como pasar inicios de sesion de un servidor a otro en SQL Server

Problema: Tengo configurado mi servidor con los usuarios que accesan a la información del SQL Sever por medio de la respectiva aplicación, pero necesito pasarlo a otro servidor SQL Server con los mismos usuarios y sus permisos establecidos.
Solución: En la página de Microsoft me encontré con diversas opciones, pero la que finalmente utilicé fue la siguiente: Cómo transferir inicios de sesión y contraseñas entre servidores SQL Server

Resumo lo que allí se publica.

La página proporciona un script, que al ejecutarse, provee de los inicios de sesión de todos los usuarios del servidor.

El script es solo copiar y ejecutar.

El script es el siguiente.

----- Begin Script, Create sp_help_revlogin procedure -----

USE master
GO
IF OBJECT_ID ('sp_hexadecimal') IS NOT NULL
  DROP PROCEDURE sp_hexadecimal
GO
CREATE PROCEDURE sp_hexadecimal
    @binvalue varbinary(256),
    @hexvalue varchar(256) OUTPUT
AS
DECLARE @charvalue varchar(256)
DECLARE @i int
DECLARE @length int
DECLARE @hexstring char(16)
SELECT @charvalue = '0x'
SELECT @i = 1
SELECT @length = DATALENGTH (@binvalue)
SELECT @hexstring = '0123456789ABCDEF' 
WHILE (@i <= @length) 
BEGIN
  DECLARE @tempint int
  DECLARE @firstint int
  DECLARE @secondint int
  SELECT @tempint = CONVERT(int, SUBSTRING(@binvalue,@i,1))
  SELECT @firstint = FLOOR(@tempint/16)
  SELECT @secondint = @tempint - (@firstint*16)
  SELECT @charvalue = @charvalue +
    SUBSTRING(@hexstring, @firstint+1, 1) +
    SUBSTRING(@hexstring, @secondint+1, 1)
  SELECT @i = @i + 1
END
SELECT @hexvalue = @charvalue
GO

IF OBJECT_ID ('sp_help_revlogin') IS NOT NULL
  DROP PROCEDURE sp_help_revlogin 
GO
CREATE PROCEDURE sp_help_revlogin @login_name sysname = NULL AS
DECLARE @name    sysname
DECLARE @xstatus int
DECLARE @binpwd  varbinary (256)
DECLARE @txtpwd  sysname
DECLARE @tmpstr  varchar (256)
DECLARE @SID_varbinary varbinary(85)
DECLARE @SID_string varchar(256)

IF (@login_name IS NULL)
  DECLARE login_curs CURSOR FOR 
    SELECT sid, name, xstatus, password FROM master..sysxlogins 
    WHERE srvid IS NULL AND name <> 'sa'
ELSE
  DECLARE login_curs CURSOR FOR 
    SELECT sid, name, xstatus, password FROM master..sysxlogins 
    WHERE srvid IS NULL AND name = @login_name
OPEN login_curs 
FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @xstatus, @binpwd
IF (@@fetch_status = -1)
BEGIN
  PRINT 'No login(s) found.'
  CLOSE login_curs 
  DEALLOCATE login_curs 
  RETURN -1
END
SET @tmpstr = '/* sp_help_revlogin script ' 
PRINT @tmpstr
SET @tmpstr = '** Generated ' 
  + CONVERT (varchar, GETDATE()) + ' on ' + @@SERVERNAME + ' */'
PRINT @tmpstr
PRINT ''
PRINT 'DECLARE @pwd sysname'
WHILE (@@fetch_status <> -1)
BEGIN
  IF (@@fetch_status <> -2)
  BEGIN
    PRINT ''
    SET @tmpstr = '-- Login: ' + @name
    PRINT @tmpstr 
    IF (@xstatus & 4) = 4
    BEGIN -- NT authenticated account/group
      IF (@xstatus & 1) = 1
      BEGIN -- NT login is denied access
        SET @tmpstr = 'EXEC master..sp_denylogin ''' + @name + ''''
        PRINT @tmpstr 
      END
      ELSE BEGIN -- NT login has access
        SET @tmpstr = 'EXEC master..sp_grantlogin ''' + @name + ''''
        PRINT @tmpstr 
      END
    END
    ELSE BEGIN -- SQL Server authentication
      IF (@binpwd IS NOT NULL)
      BEGIN -- Non-null password
        EXEC sp_hexadecimal @binpwd, @txtpwd OUT
        IF (@xstatus & 2048) = 2048
          SET @tmpstr = 'SET @pwd = CONVERT (varchar(256), ' + @txtpwd + ')'
        ELSE
          SET @tmpstr = 'SET @pwd = CONVERT (varbinary(256), ' + @txtpwd + ')'
        PRINT @tmpstr
        EXEC sp_hexadecimal @SID_varbinary,@SID_string OUT
        SET @tmpstr = 'EXEC master..sp_addlogin ''' + @name 
          + ''', @pwd, @sid = ' + @SID_string + ', @encryptopt = '
      END
      ELSE BEGIN 
        -- Null password
        EXEC sp_hexadecimal @SID_varbinary,@SID_string OUT
        SET @tmpstr = 'EXEC master..sp_addlogin ''' + @name 
          + ''', NULL, @sid = ' + @SID_string + ', @encryptopt = '
      END
      IF (@xstatus & 2048) = 2048
        -- login upgraded from 6.5
        SET @tmpstr = @tmpstr + '''skip_encryption_old''' 
      ELSE 
        SET @tmpstr = @tmpstr + '''skip_encryption'''
      PRINT @tmpstr 
    END
  END
  FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @xstatus, @binpwd
  END
CLOSE login_curs 
DEALLOCATE login_curs 
RETURN 0
GO
 ----- End Script -----

Este script sirve para crear el procedimiento que generará los inicios de sesión.

Para ejecutar este script sería de la siguiente manera.

EXEC master..sp_help_revlogin

Al ejecutarse el procedimiento, saldrá un listado de los usuarios con su información.

Este listado se ejecuta en el nuevo servidor y listo, los usuarios serán creados.

Restaurar Base de Datos de SQL Server desde el Visual Basic .Net

Problema: Necesito restaurar, por medio de un programa, una base de datos del SQL Server.
Solución: Encontré un mundillo de cosas en la web, así que decidí unificarlo todo.
Tengo un procedimiento, el cual utilizo para restaurar la base de datos.

Public Sub RestaurarBD(ByVal base As String, ByVal ruta As String, ByVal servidor As String, ByVal ArchivoMdf As String, _
ByVal ArchivoLdf As String, ByVal RutaMdf As String, ByVal RutaLdf As String)
 Dim sBackup As String = "RESTORE DATABASE " & base & _
 " FROM DISK = '" & ruta & "'" & _
 " WITH REPLACE, " & _
 "MOVE '" & ArchivoMdf & "' TO '" & RutaMdf & ".mdf', " & _
 "MOVE '" & ArchivoLdf & "' TO '" & RutaLdf & ".ldf'"

 Dim csb As New SqlConnectionStringBuilder
 csb.DataSource = servidor
 ' Es mejor abrir la conexión con la base Master
 csb.InitialCatalog = "master"
 csb.IntegratedSecurity = True

 Using con As New SqlConnection(csb.ConnectionString)
  Try
  con.Open()

  Dim cmdBackUp As New SqlCommand(sBackup, con)
  cmdBackUp.ExecuteNonQuery()
  MessageBox.Show("Se ha restaurado la copia de la base de datos.", _
    "Restaurar base de datos", _
    MessageBoxButtons.OK, MessageBoxIcon.Information)
  con.Close()
  Catch ex As Exception
  MessageBox.Show(ex.Message, _
  "Error al restaurar la base de datos", _
  MessageBoxButtons.OK, MessageBoxIcon.Error)
  End Try
 End Using
End Sub

Hay que recordar que si son rutas locales la sentencia sería, por ejemplo, C:\Archivos de Programa\Microsoft SQL Server\MSSQL\Data Pero si son rutas de red la sentencia sería, por ejemplo, \\Servidor1\Carpeta\Database

Se necesita saber el archivo físico del mdf y ldf, generalmente se llaman igual que la base de datos, por ejemplo, si restauro la base llamada Clientes, los archivos serían Clientes.mdf y Clientes.lfd respectivamente. Pero OJO, no siempre se llaman así, por lo que deben verificar el nombre de cada archivo. Así mismo, los archivos mdf y ldf suele ir en la misma carpeta en donde se encuentra la Data del SQL Server, pero esto no es una regla exacta, sobre todo si se trabaja en una red local, por lo que deben también verificar esto.

Tener en cuenta la conexión, el que pongo de ejemplo es un genérico que sirve cuando la base de datos es local, de ser un servidor en red, deberá tener su propio usuario y contraseña de autenticación.

Para este ejemplo, utilizaré la base de datos llamada Clientes, el cual he sacado una copia de seguridad desde el SQL Server llamada Clientes.bak

base: es el nombre lógico de la base de datos, en este caso sería Clientes
ruta: es el lugar y nombre de la copia de seguridad, sería C:\Carpeta\Clientes.bak
ArchivoMdf: es el nombre del archivo .mdf, sería Clientes.mdf
RutaMdf: es el lugar y el nombre del archivo .mdf, sería C:\Archivos de Programa\Microsoft SQL Server\MSSQL\Data\Clientes.mdf
ArchivoLdf: es el nombre del archivo .ldf, sería Clientes.ldf
RutaLdf: es el lugar y el nombre del archivo .ldf, sería C:\Archivos de Programa\Microsoft SQL Server\MSSQL\Data\Clientes.ldf

La manera de usarlo sería la siguiente

RestaurarBD(base, ruta, servidor, ArchivoMdf, ArchivoLdf, RutaMdf, RutaLdf)

El proyecto con el código de ejemplo se puede descargar desde aquí: Ejemplo

Deshabilitar columna tipo DataGridViewButtonColumn en DataGridView

Problema: Tengo una columna tipo botón en mi grid, pero por validaciones, necesito que en una fila específica, el botón esté deshabilitado y que no funcione.
Solución: Microsoft da una versión general del problema y su solución es bastante limitada, así que he decidido unificar los pedazos que he encontrado en la web.

La parte de Microsoft que utilizo, es la siguiente, sin importar cómo lo voy a utilizar después. Este código sirve para crear un nuevo tipo de botón "deshabilitado", que no viene originalmente en el grid.

Solo es de copiar y pegar, yo lo tengo al final de todo mi código. Más adelante explico como utilizarlo.

#Region "Columna Botón Deshabilitada"
    Public Class DataGridViewDisableButtonColumn
        Inherits DataGridViewButtonColumn

        Public Sub New()
            Me.CellTemplate = New DataGridViewDisableButtonCell()
        End Sub
    End Class

    Public Class DataGridViewDisableButtonCell
        Inherits DataGridViewButtonCell

        Private enabledValue As Boolean
        Public Property Enabled() As Boolean
            Get
                Return enabledValue
            End Get
            Set(ByVal value As Boolean)
                enabledValue = value
            End Set
        End Property

        ' Override the Clone method so that the Enabled property is copied.
        Public Overrides Function Clone() As Object
            Dim Cell As DataGridViewDisableButtonCell = _
                CType(MyBase.Clone(), DataGridViewDisableButtonCell)
            Cell.Enabled = Me.Enabled
            Return Cell
        End Function

        ' By default, enable the button cell.
        Public Sub New()
            Me.enabledValue = True
        End Sub

        Protected Overrides Sub Paint(ByVal graphics As Graphics, _
            ByVal clipBounds As Rectangle, ByVal cellBounds As Rectangle, _
            ByVal rowIndex As Integer, _
            ByVal elementState As DataGridViewElementStates, _
            ByVal value As Object, ByVal formattedValue As Object, _
            ByVal errorText As String, _
            ByVal cellStyle As DataGridViewCellStyle, _
            ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle, _
            ByVal paintParts As DataGridViewPaintParts)

            ' The button cell is disabled, so paint the border, 
            ' background, and disabled button for the cell.
            If Not Me.enabledValue Then

                ' Draw the background of the cell, if specified.
                If (paintParts And DataGridViewPaintParts.Background) = _
                    DataGridViewPaintParts.Background Then

                    Dim cellBackground As New SolidBrush(cellStyle.BackColor)
                    graphics.FillRectangle(cellBackground, cellBounds)
                    cellBackground.Dispose()
                End If

                ' Draw the cell borders, if specified.
                If (paintParts And DataGridViewPaintParts.Border) = _
                    DataGridViewPaintParts.Border Then

                    PaintBorder(graphics, clipBounds, cellBounds, cellStyle, _
                        advancedBorderStyle)
                End If

                ' Calculate the area in which to draw the button.
                Dim buttonArea As Rectangle = cellBounds
                Dim buttonAdjustment As Rectangle = _
                    Me.BorderWidths(advancedBorderStyle)
                buttonArea.X += buttonAdjustment.X
                buttonArea.Y += buttonAdjustment.Y
                buttonArea.Height -= buttonAdjustment.Height
                buttonArea.Width -= buttonAdjustment.Width

                ' Draw the disabled button.               
                ButtonRenderer.DrawButton(graphics, buttonArea, _
                    PushButtonState.Disabled)

                ' Draw the disabled button text.
                If TypeOf Me.FormattedValue Is String Then
                    TextRenderer.DrawText(graphics, CStr(Me.FormattedValue), _
                        Me.DataGridView.Font, buttonArea, SystemColors.GrayText)
                End If

            Else
                ' The button cell is enabled, so let the base class
                ' handle the painting.
                MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, _
                    elementState, value, formattedValue, errorText, _
                    cellStyle, advancedBorderStyle, paintParts)
            End If
        End Sub

    End Class
#End Region

Bien, ahora a utilizarlo. Como yo ya tengo mi grid diseñado, debo cambiar mi columna botón original, por el nuevo tipo de botón.

Nota: Recordar que es un nuevo tipo de columna, y se lo debe de cambiar, como si cambiáramos del tipo botón al tipo check.

Primero debemos eliminar la columna botón actual y luego crear la nueva columna con los valores deseados en el sitio específico, todo cuando carga la aplicación.

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Elimino la columna botón que ya tengo actualmente
        DataGridView1.Columns.Remove("boton")
        'Creo el nuevo tipo de botón
        Dim column As New DataGridViewDisableButtonColumn()
        'Defino las propiedades del botón
        With column
            .Name = "boton"
            .HeaderText = "Dar Click"
            .AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells
        End With
        'Inserto la nueva columna en el sitio especificado
        DataGridView1.Columns.Insert(1, column) 'Está en la segunda fila
End Sub

Ahora la manera de utilizarlo:

Por ejemplo, cuando cargo los datos al grid, deseo que en ciertos registros no se habilite el botón, por lo que lo realizo de esta manera.

Private Sub Actualizar_Boton()
        For Each row As DataGridViewRow In DataGridView1.Rows
                If Not row.Cells("columna1").Value is DBNull.Value Then 'Si el campo NO es nulo
                        'Se deshabilita la columna Botón
                        Dim buttonCell As DataGridViewDisableButtonCell = CType(DataGridView1.Rows(row.Index).Cells("boton"), DataGridViewDisableButtonCell)
                        buttonCell.Enabled = False
                End If
        Next
End Sub

Con esto el botón pasa a verse como si estuviera deshabilitado, pero OJO, aún pueden hacer click en el.
Pero esto se puede resolver añadiendo una validación adicional a la programación que se hace al dar click en el botón.

Private Sub DataGridView1_CellContentClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
        'Columna Botón
        If DataGridView1.Columns(e.ColumnIndex).Name = "boton" Then
                Dim buttonCell As DataGridViewDisableButtonCell = CType(DataGridView1.Rows(e.RowIndex).Cells("boton"), DataGridViewDisableButtonCell)
                If buttonCell.Enabled = False Then Exit Sub 'Si está deshabilitado no hace nada
                'Aquí el resto de mi código
                'Lo que pasa cuando se da click en el botón
        End If
End Sub

Eliminar Archivos

Problema: Por medio de programación, debe eliminar un archivo específico.
Solución: Una de esas cositas que encontré por allí.

Public Sub Eliminar_Archivo(ByVal archivo As String)
        Try
                'My.Computer.FileSystem.DeleteFile(archivo, FileIO.UIOption.AllDialogs, FileIO.RecycleOption.SendToRecycleBin, FileIO.UICancelOption.DoNothing) 'Opción Larga
                My.Computer.FileSystem.DeleteFile(archivo) 'Opción corta
        Catch ex As Exception
                MsgBox(ex.Message.ToString, MsgBoxStyle.Critical)
        End Try
End Sub

La opción larga permite mostrar el cuadro de dialogo que le pregunta al usuario si desea que el archivo vaya a la papelera de reciclaje. La opción corta, simplemente elimina el archivo sin pasar por la papelera. Se usaría de la siguiente manera:

Dim archivo As String = "C:\Carpeta\archivo.txt"

Eliminar_Archivo(archivo)

Comprimir y Descomprimir archivos

Problema: Necesito, por medio de código de programación, comprimir y descomprimir un archivo.
Solución: Encontré estas opciones buscando por allí, en la web. Para comprimir.

Public Sub ComprimirArchivo(ByVal archivoEntrada As String, ByVal archivoSalida As String)
        Using sourceFile As FileStream = File.OpenRead(archivoEntrada)
                Using destFile As FileStream = File.Create(archivoSalida)
                        Using compStream As GZipStream = New GZipStream(destFile, CompressionMode.Compress)
                                Dim data(sourceFile.Length) As Byte
                                sourceFile.Read(data, 0, data.Length)
                                compStream.Write(data, 0, data.Length)
                        End Using
                End Using
        End Using
End Sub

Para descomprimir.

Public Sub DescomprimirArchivo(ByVal archivoEntrada As String, ByVal archivoSalida As String)
        Using sourceFile As FileStream = File.OpenRead(archivoEntrada)
                Using destFile As FileStream = File.Create(archivoSalida)
                        Using compStream As GZipStream = New GZipStream(sourceFile, CompressionMode.Decompress)
                                Dim data As Integer
                                data = compStream.ReadByte()
                                While (data <> -1)
                                        destFile.WriteByte(CByte(data))
                                        data = compStream.ReadByte()
                                End While
                        End Using
                End Using
        End Using
End Sub
Se usa así:
Dim path As String = "C:\Carpeta\ejemplo.txt"
Dim path2 As String = "C:\Respaldo\ejemplo_comprimido.zip"

ComprimirArchivo(path, path2)

Me indicaron que se podía usar con diferentes tipos de archivos comprimidos, como son los Zip y los Rar, pero no estoy muy segura de otros formatos, así que toca probar.

Copiar un archivo y mostrar el progreso

Problema: Necesito copiar un archivo de un lugar a otro y además, muestre el progreso del mismo.
Solución: Un proceso con una barra de progreso (ProgressBar)

El proceso no es del todo mío, lo encontré por allí y lo adapté a mis necesidades, como siempre.

Sub CopiaArchivoConProgreso(ByVal path As String, ByVal path2 As String, ByVal file As String)
        'path = ruta del lugar de origen, en donde se encuentra el archivo
        'path2 = ruta del lugar de destino, a donde se copiará el archivo
        'file = nombre del archivo a copiar
        Dim fi As New IO.FileInfo(file)
        Dim sr As New IO.FileStream(path & file, IO.FileMode.Open) 'lugar de origen
        Dim sw As New IO.FileStream(path2 & file, IO.FileMode.Create) 'lugar de destino
        Dim len As Long = sr.Length - 1
        For i As Long = 0 To len
            sw.WriteByte(sr.ReadByte)
            If i Mod 1000 = 0 Then 'Actualiza con cada 1 kb copiado
                ProgressBar1.Value = i * 100 / len
                Application.DoEvents()
            End If
        Next
        ProgressBar1.Value = 0
        sr.Close()
        sw.Close()
End Sub

Recordar importar

Imports System.IO

Para usarlo, sería más o menos así:

Dim ruta_servidor As String = "D:\Carpeta\"
Dim ruta_local As String = "C:\Respaldo\"
Dim archivo As String = "Ejemplo.zip"

CopiaArchivoConProgreso(ruta_servidor, ruta_local, archivo)