jueves, 23 de enero de 2014

¿Qué habilidades buscan de un desarrollador de software los Empresarios: Mis conversaciones con las compañías que contratan a programadores?




Sólo un par de años fuera de la universidad, yo era un programador de un sistema de Gestión comercial hecho en (Cobol),  entrevistado para un trabajo como programador C. En un momento de la entrevista, le pregunté a mi supervisor (eventual) en caso de que la compañía realmente contratar a alguien que no tenía ninguna experiencia con C para este trabajo. Su respuesta tuvo un gran impacto en mi carrera.

Él respondió: "No contratamos a la gente por lo que saben, sino por lo que podemos aprender." Estas palabras siempre han encontrado eco en mí. Desde ese momento, mi estrategia de carrera como programador siempre ha sido la de mirar hacia adelante en lugar de centrarse simplemente en una tecnología específica, actual. Como alguien me dijo recientemente, "Como programador no tiene una única carrera de 30 años, tiene 30 carreras de un año".

No sólo es la tecnología cambia constantemente, pero, en el mundo actual, la programación se puede encontrar en todos los aspectos de nuestra cultura. Esto es lo que hace ser un programador tan interesante y gratificante. ¿Cuántas profesiones existen que pueden llevar por caminos tan diversos como la atención de la salud, la justicia penal, la educación, el entretenimiento y casi todas las áreas de negocio? La variedad de carreras de programación es bastante impresionante, y las oportunidades de cambiar los caminos, e incluso combinarlos, son prácticamente ilimitadas.

Quizás la discusión más interesante que tengo con la gente en la industria de la programación, así como los que enseñan la programación, es la siguiente: ¿Cuáles son los empleadores que buscan en realidad las personas que contratan como programadores ? Con esta frase en mente, este artículo explora algunas de las preguntas que los estudiantes a menudo me preguntan cuando están buscando para entrar en la industria de la programación, en concreto, ¿qué tipo de habilidades que deben concentrarse en el aprendizaje.

¿Qué habilidades dicen los empleadores que están buscando?

Mi primera parada fue en anuncios clasificados de un periódico local, donde se ve principalmente de programación ofertas de empleo como ésta (tomado de un anuncio real): "Experiencia Java Web Developer. Experiencia requerida, Struts 2 o MVC. Hibernate o ORM. JavaScript / jQuery, Ajax, Patrones, HTML y SQL ".

Muchos de los anuncios requieren habilidades específicas, tales como. NET y Oracle, así como muchas otras habilidades que he, honestamente, nunca oído hablar. Por lo tanto, mucha gente cree que cuando se inicia un programa educativo, que debe centrarse en las habilidades que son tecnologías calientes de hoy.

Si bien reconozco que muchos puestos de trabajo están buscando habilidades específicas, siguiendo esta estrategia puede ser problemático. Todos sabemos que la tecnología está cambiando tan rápidamente que nadie sabe cuáles son las tecnologías calientes estarán en un año, por no hablar de los dos o cuatro años que se tardará en obtener un certificado o título.

Así que, si el aprendizaje de la última tecnología no es la mejor estrategia, entonces, ¿qué es?

NOTA
Como con la mayoría de cosas en la vida, en lugar de la marca de una sola estrategia como la mejor, la trayectoria educativa que elija como programador depende del contexto en el que se encuentra. Si usted es un profesional con experiencia de programación, entonces, obviamente, hay muchas situaciones donde se necesita un cierto conjunto de habilidades. Por ejemplo, si una empresa está buscando contratar a un contratista para un conjunto de habilidades muy específicas, entonces ellos quieren encontrar a alguien que satisfaga la necesidad inmediata. O bien, una persona puede desear agregar simplemente una tecnología actual a su conjunto de herramientas de programación, tomando una clase o incluso la búsqueda de un certificado.

¿Qué es lo que  los empleadores realmente buscan?

Después de discutir estos temas con la gente en la industria y el mundo académico durante muchos años, he llegado a suscribirse a la teoría de que la programación es la programación . En mi experiencia, cuando usted contrata a alguien para un puesto de programación, usted no sabe necesariamente qué tecnologías y / o lenguajes de su organización va a utilizar en un año. De hecho, es muy posible que desee este nuevo empleado que te guíe hacia el futuro y explorar direcciones totalmente nuevas.

¿Qué es lo que realmente quieren los empleadores cuando se trata de talento de programación? En última instancia, me decidí a preguntar directamente a las empresas. En primer lugar, me clasifiqué las empresas en tres niveles de tamaño: pequeño (10 o menos empleados), medianas (entre 10 y 100 empleados) y grandes (más de 1000 empleados). Entonces les hice las siguientes preguntas:

1.     ¿Cuáles son las habilidades más importantes (técnicas, habilidades blandas o de otro tipo) que usted busca en la contratación de un programador?

2.     ¿Se concentra en un lenguaje de programación específico o la tecnología (es decir, ¿te pasa en un buen programador que le falta una habilidad específica que su empresa utiliza o usted les entrenar)?

3.     ¿Qué importancia tienen las habilidades blandas (escritura, presentación y otras habilidades de comunicación)?

4.     ¿Qué títulos o certificaciones estás buscando (qué tan relevante son las certificaciones)?

5.     ¿Sus programadores a crear un código nuevo (producto) o están trabajando en el mantenimiento de código existente implementación y aplicación de productos de terceros?

Preguntas y Respuestas

De todas las respuestas que he recibido, he elegido las respuestas de cuatro de los profesionales de software que proporcionan buenas representaciones de los tres tamaños de empresa. Hay respuestas de dos grandes empresas, una empresa mediana y otra pequeña empresa.

En lugar de intentar interpretar las respuestas, simplemente me presento las respuestas textualmente.

¿Cuáles son las habilidades más importantes (técnicas, habilidades blandas o de otro tipo) que usted busca en la contratación de un programador?




Grandes Empresas

"4 años Título Universitario, sólida formación técnica, experiencia profesional, apasionado de la tecnología, profesionalmente conductor, articulado y bien hablado."

"Es verdaderamente una combinación de habilidades técnicas y blandas. Fundamentos de la lógica de programación y la capacidad de aplicar los fundamentos de cualquier base de código que se encuentran."

Empresas Medianas

"La capacidad para resolver problemas. La capacidad de aprender nuevas tecnologías rápidamente. La capacidad de encontrar soluciones a los problemas de uso de Internet. Una mentalidad de la eficiencia y la creatividad."

Pequeñas Empresas

"Yo quiero centrarme en la idea de ser un jugador de equipo decente y no ser una persona que es difícil llevarse bien con un empleado difícil puede crear todo un montón de problemas más habilidades pueden ser aprendidas y mejoradas -.. Lo que a menudo son tiempos difíciles de cambiar son la naturaleza y el carácter de una persona ... Además de las habilidades descritas en otras respuestas, en busca de habilidades interpersonales es importante - especialmente si la organización está en el lado más pequeño. "

Conclusión : título universitario de 4 años ( grandes empresas ), la pasión por la programación, las habilidades interpersonales, solucionador de problemas, trabajar en equipo.

¿Se concentra en un lenguaje de programación específico o la tecnología (es decir, ¿te pasa en un buen programador que le falta una habilidad específica que su empresa utiliza o usted les entrenar)?




Grandes Empresas

"En realidad no;. Esperamos que nuestros desarrolladores ser versátil y ser capaz de aprender nuevas tecnologías, siempre y cuando son similares (. Decir que esperamos un desarrollador de Java para poder sumergirse en NET)"

"No. Fundamentos de lógica de programación y la capacidad de aplicar los fundamentos de cualquier base de código que se encuentran."

Empresas Medianas

"Sería realmente dependerá de la necesidad. El programador que puede saltar entre los idiomas es más valioso, salvo en proyectos especializados. Si no tiene ninguna experiencia con un lenguaje que están solicitando, sin embargo, que probablemente no son deseables. Aunque la experiencia es sólo personal que es mucho mejor que no tener ninguna experiencia. Hay demasiados matices del lenguaje y el medio ambiente y no el suficiente beneficio en la formación de una persona a partir de cero ".

Pequeñas Empresas

"Siempre es bueno estar dispuesto a entrenar a alguien, si ves otra competencia que valoramos mucho. Esperando un programador C + + para poder recoger Java debe ser una apuesta segura, pero, podría tomar algún tiempo para alcanzar la competencia. No es también el tema del medio ambiente, tales como Linux frente de Windows. Yo creo que una persona que ha sido exclusivo de uno puede recoger la otra, y es digno de él para entrenarlos si eso es un problema ".

Conclusión : la lógica de programación fuerte y, a veces requiere tecnologías específicas que prefieren.los empleadores esperan que los programadores pueden aprender a trabajar en la mayoría de entornos.

¿Qué importancia tienen las habilidades blandas (escritura, presentación y otras habilidades de comunicación)?




Grandes Empresas

"Las habilidades sociales son extremadamente importantes. Potencialmente, la habilidad más importante que puede tener. Una vez que se establecen como alguien que es técnicamente útil, habilidades blandas son las que generalmente conduce promociones ".

"Las habilidades de comunicación son muy importantes, habilidades de presentación no tanto."

Empresas Medianas

"Depende del nivel de programador. Para alguien menor, el 90% de codificación y aptitudes generales, 10% habilidades blandas. Para alguien de mayor jerarquía que aumenta de manera significativa."

Pequeñas Empresas

"Parece que las habilidades blandas no puede hacer daño y son a menudo muy importante. Incluso si un programador no puede hacer documentos de Word o en PowerPoint, que debe ser capaz de comprender y comunicar la visión global acerca de lo que están haciendo, y cómo encaja en las piezas generales de la organización ".

Conclusión : Las habilidades sociales pueden en última instancia ser la habilidad más importante, sobre todo a medida que ascienda en la escala en una organización.

Consejos para la adquisición de los conocimientos de programación Derecha

Como profesor universitario asesorar a los estudiantes, aquí hay algunos consejos para cualquier persona que quiere ser un programador:

1.     No te dejes atrapar con tecnologías específicas, sino que se centran en las habilidades profesionales fundamentales que los empleadores en este artículo describen.

2.     En lugar de centrarse en los clasificados, salir y trabajar en red con profesionales de programación local. Hace poco leí que son 4 -5 veces más probabilidades de conseguir un trabajo a través de redes de aplicar a un anuncio de empleo.

3.     Adquirir experiencia práctica tanto la programación como sea posible a través de proyectos de la escuela, pasantías y proyectos auto-impulsado (una de las preguntas que los empleadores están sin duda te va a preguntar es "¿Qué tipo de aplicaciones y sitios web se crea en su propio tiempo - apenas por diversión. ").

4.     Participar en hackathons y otros proyectos de bricolaje. Esto no sólo ayudará a mejorar sus habilidades de programación, sino también demostrar que usted es un apasionado de la programación.

Durante mis conversaciones con muchos profesionales relacionados con el software a estas preguntas, me llamó la atención el hecho de que, a pesar de los enormes cambios tecnológicos de los últimos 10 a 20 años, lo que los empleadores buscan en los programadores realmente no ha cambiado mucho. Si bien es obvio que los programadores de hoy en día están utilizando diferentes lenguajes de programación, sistemas operativos y otras tecnologías modernas, los empleadores están siendo básicamente buscando las mismas "tipos" de los programadores que lo eran hace 10 años-para el caso, incluso hace 20 años.

 
 

miércoles, 22 de enero de 2014

DESKTOP APPLICATION - 5º Parte - Sistema de Ventas C# - Creación de Reporte en Crystal Report

1. Entorno

  • SQL Server 2008
  • Visual Studio 2008

2. Introducción


Continuando con el tutorial del sistemas de ventas con C#, ahora crearemos el reporte con Crystal Report que nos mostrara el documento creado producto de la venta que hemos realizado. Como este es un tutorial con un fin didáctico, para crear el reporte nosotros escribiremos el código auto generado por la inserción de la venta, aunque lo ideal seria que desde la capa de negocios obtengamos el código que se genero y se muestre el reporte de forma automática.

3. Desarrollo


3.1. Diseño del formulario

Ahora debemos de modificar nuestro formulario que hemos creado anteriormente que se llamaba frmRegistrarVenta. Si recordamos este formulario tenia un Tab Control con dos pestañas, una que se llamaba Registrar y otro que se llama Reporte. Y justo en esta ultima pestaña es donde vamos a poner nuestro reporte. Para poder mostrar los reportes en C#, debemos de agregar un componente que se llama CrystalReportViewer que se encuentra en nuestro cuadro de herramientas en el grupo de Informe



















Y luego en nuestro formulario hacemos el siguiente diseño
















3.2. Creando nuestro DataSet

Para poder crear un reporte para Crystal Reporte, lo primero que se tiene que hacer es crear un DataSet en donde se almacenara todo nuestro datos de la consulta y nos servira para llenar nuestro reporte y para eso les prepare el siguiente video para que puedan crear un DataSet de la manera mas rápida y sencilla.




3.3. Creando nuestro Reporte en Crystal Report

Ahora debemos de diseñar nuestro reporte con la información que obtenemos de nuestro DataSet que hemos creado anteriormente, para eso también les prepare otro vídeo.



El reporte al final debería tener el siguiente diseño











3.4. Código Fuente

Ahora nos vamos a ir al evento clic del botón "btnReporte" de nuestro formulario "frmRegistrarVenta" y pondremos el siguiente código fuente

private void btnReporte_Click(object sender, EventArgs e)
{
  try
  {
    //Creamos el documento 
    CrystalDecisions.CrystalReports.Engine.ReportDocument rpt=new CrystalDecisions.CrystalReports.Engine.ReportDocument();
    //Obtenemos el documento que se encuentra en nustra carpeta bin\debug\crReporte.rpt
    rpt.Load( Application.StartupPath + "\\crReporte.rpt");
    //Lleanamos el reporte con la información que obtenemos de la base de datos
    rpt.SetDataSource(NegVenta.ObtenerVenta(Convert.ToInt32(this.txtCodigoVenta.Text)));
    //Establecemos los datos al reporte
    this.crvReporte.ReportSource=rpt;
    //Refrescamos nuestro reporte
    this.crvReporte.RefreshReport();
  }
  catch (Exception ex)
  {
  }
}

4. Ejemplo de la Aplicación

(PARA ESTE BLOG EN BREVE LOS VIDEOS)

DESKTOP APPLICATION - 4º parte - Sistema de ventas C# - Base de datos SQL - Capa Presentación.

1. ENTORNO

  • SQL Server 2008
  • Visual Studio 2008

2. INTRODUCCIÓN

En el tutorial en la Parte II y en la Parte III hemos creado la capa de datos y la capa de negocios respectivamente de nuestra aplicación, ahora solo nos falta crear nuestra capa de presentacion. La capa de presentacion puede ser una aplicacion del tipo escritorio, web, etc. Es por eso que se utiliza la programacion en capas, debido a que no importa que cambiamos hagamos en alguna capa no se sentira en las otras de manera brusca.

3. DESARROLLO


3.1. Creando el Proyecto

Ahora debemos de agregar a nuestro proyecto un proyecto del tipo biblioteca de clases que se llamara "CapaPresentacion". No olvidar que debemos de ir a "Archivo-->Agregar-->Nuevo Proyecto"











3.2. Agregando la referencia con la Capa de Negocios

Debemos de establecer la comunicacion entre la Capa de Presentación y la Capa de Negocios. Para eso hacemos clic derecho en nuestro proyecto que se llama "CapaPresentacion" y nos vamos a la opcion de "Agregar Referencia"















Y de ahí seleccionamos que se comunica con la Capa de Negocios













3.3. Formulario frmMantenimientoProducto

En este formulario vamos a realizar un mantenimiento a la tabla Producto de nuestra Base de Datos que se llama BDTutorial y que esta diseñada en SQL Server 2008. A mantenimiento me refiero a los procesos de inserción, actualización y consulta de datos de la tabla Producto. Debemos de diseñar el siguiente formulario











En el cual el componente dgvProducto tiene los siguientes valores de propiedades:

  • AllowUserToAddRows = False
  • AllowUserToDeleteRows = False
  • MultiSelect = False
  • ReadOnly = True
  • SelectionMode = FullRowSelect

Y como columnas tiene

  • codigoProducto
    • DataPropertyName = codigoProducto
    • HeaderText = codigoProducto
    • Visible = False
  • Nombre
    • DataPropertyName = nombre
    • HeaderText = Nombre
    • Visible = True
  • Precio
    • DataPropertyName = precio
    • HeaderText = Precio
    • Visible = True

En la otra pestaña del tabControl tenemos los siguientes componentes:











Y su código fuente del formulario seria

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
//Comunicarse con la Capa de Negocios
using CapaNegocios;
//Desarollado por Henry Joe Wong Urquiza
namespace CapaPresentacion
{
  public partial class frmMantenimientoProducto : Form
  {
    //Variable que nos indica si vamos a insertar un nuevo producto
    private bool nuevo = false;
    //Variable que nos indica si vamos a modificar un producto
    private bool modificar = false;
    //Constructor del formulario
    public frmMantenimientoProducto()
    {
      InitializeComponent();
    }
    //Evento que se lanza cuando se va a mostrar el formulario
    private void frmMantenimientoProducto_Load(object sender, EventArgs e)
    {
      //Para ubicar al formulario en la parte superior del contenedor
      this.Top = 0;
      this.Left = 0;
      //Le decimos al DataGridView que no auto genere las columnas
      this.dgvProductos.AutoGenerateColumns = false;
      //Llenamos el DataGridView con la informacion de todos nuestros 
      //productos
      this.dgvProductos.DataSource = NegProducto.ObtenerProducto();
      //Deshabilita los controles
      this.habilitar(false);
      //Establece los botones
      this.botones();
    }
    //Para mostrar mensaje de confirmacion
    private void mOK(string men)
    {
      MessageBox.Show(men, "MENSAJE", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    //Para mostrar mensaje de error
    private void mError(string men)
    {
      MessageBox.Show(men, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    //Limpia los controles del formulario
    private void limpiar()
    {
      this.txtNombre.Text = string.Empty;
      this.nudPrecio.Value = 0;
    }
    //Habilita los controles de los formularios
    private void habilitar(bool valor)
    {
      this.txtNombre.ReadOnly = !valor;
      this.nudPrecio.Enabled = valor; 
    }
    //Habilita los botones
    private void botones()
    {
      if (this.nuevo || this.modificar)
      {
        this.habilitar(true);
        this.btnNuevo.Enabled = false;
        this.btnGuardar.Enabled = true;
        this.btnModificar.Enabled = false;
        this.btnCancelar.Enabled = true;
      }
      else
      {
        this.habilitar(false);
        this.btnNuevo.Enabled = true;
        this.btnGuardar.Enabled = false;
        this.btnModificar.Enabled = true;
        this.btnCancelar.Enabled = false;
      }
    }
    //Evento clic del boton btnNuevo
    private void btnNuevo_Click(object sender, EventArgs e)
    {
      this.nuevo=true;
      this.modificar=false;
      this.botones();
      this.limpiar();
      this.txtCodigo.Text = string.Empty;
      this.txtNombre.Focus();
    }
    //Evento clic del boton btnGuardar
    private void btnGuardar_Click(object sender, EventArgs e)
    {
      //La variable que almacena si se inserto o se modifico la tabla
      string rpta = "";
      if(this.nuevo)
      {
        //Vamos a insertar un producto 
        rpta=NegProducto.Insertar(this.txtNombre.Text.Trim().ToUpper(),
        this.nudPrecio.Value);

      }else
      {
        //Vamos a modificar un producto
        rpta=NegProducto.Actualizar(Convert.ToInt32(this.txtCodigo.Text),
        this.txtNombre.Text.Trim().ToUpper(),
        this.nudPrecio.Value);
      }
      //Si la respuesta fue OK, fue porque se modifico o inserto el Producto
      //de forma correcta
      if (rpta.Equals("OK"))
      {
        if (this.nuevo)
        {
          this.mOK("Se inserto de forma correcta al Producto");
        }
        else 
        {
          this.mOK("Se actualizo de forma correcta al Producto");
        }

      }
      else
      {
        //Mostramos el mensaje de error
        this.mError(rpta);
      }
      this.nuevo=false;
      this.modificar=false;
      this.botones();
      this.limpiar();
      this.dgvProductos.DataSource = NegProducto.ObtenerProducto();
      this.txtCodigo.Text="";
    }
    //Evento clic del boton btnModificar
    private void btnModificar_Click(object sender, EventArgs e)
    {
      //Si no ha seleccionado un producto no puede modificar
      if(!this.txtCodigo.Text.Equals(""))
      {
        this.modificar=true;
        this.botones();
      }
      else
      {
        this.mError("Debe de buscar un producto para Modificar");
      }
    }
    //Evento clic del boton btnCancelar
    private void btnCancelar_Click(object sender, EventArgs e)
    {
      this.nuevo=false;
      this.modificar=false;
      this.botones();
      this.limpiar();
      this.txtCodigo.Text=string.Empty;
    }
    //Evento double clic del DataGridView de Productos
    private void dgvProductos_DoubleClick(object sender, EventArgs e)
    {
      this.txtCodigo.Text = Convert.ToString(this.dgvProductos.CurrentRow.Cells["codigoProducto"].Value);
      this.txtNombre.Text = Convert.ToString(this.dgvProductos.CurrentRow.Cells["nombre"].Value);
      this.nudPrecio.Value = Convert.ToDecimal(this.dgvProductos.CurrentRow.Cells["precio"].Value);
      this.tabControl.SelectedIndex = 1;
    }

  }
}

3.4. Formulario frmSeleccionarProducto

Es un formulario del tipo modal que nos permitirá seleccionar un producto de nuestra base de datos para registrar la venta. Y tiene el siguiente diseño













En el cual el componente dgvProducto tiene los siguientes valores de propiedades:

  • AllowUserToAddRows = False
  • AllowUserToDeleteRows = False
  • MultiSelect = False
  • ReadOnly = True
  • SelectionMode = FullRowSelect

Y como columnas tiene

  • codigoProducto
    • DataPropertyName = codigoProducto
    • HeaderText = codigoProducto
    • Visible = False
  • Nombre
    • DataPropertyName = nombre
    • HeaderText = Nombre
    • Visible = True
  • Precio
    • DataPropertyName = precio
    • HeaderText = Precio
    • Visible = True
Y como código fuente tiene lo siguiente

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
//Comunicarse con la Capa de Negocios
using CapaNegocios;
//Desarollado por Henry Joe Wong Urquiza
namespace CapaPresentacion
{
  public partial class frmSeleccionarProducto : Form
  {
    //El formulario padre
    private frmRegistrarVenta frame;
    //El constructor del formulario
    public frmSeleccionarProducto()
    {
      InitializeComponent();
    }
    //Establece los valores del formulario padre
    public void estableceFormulario(frmRegistrarVenta frame)
    {
      this.frame = frame;
    }
    //Evento que se ejecuta cuando se muestra el formulario
    private void frmSeleccionarProducto_Load(object sender, EventArgs e)
    {
      //Que no se genere las columnas de forma automatica
      this.dgvProducto.AutoGenerateColumns = false;
      //Obtiene todos los productos y lo asigana al DataGridView
      this.dgvProducto.DataSource = NegProducto.ObtenerProducto();
    }
    //Evento double clic del DataGridView
    private void dgvProducto_DoubleClick(object sender, EventArgs e)
    {
      //Estableciendo los datos a las cajas de texto del formulario padre
      this.frame.codigoProductoSeleccionado = Convert.ToInt32(this.dgvProducto.CurrentRow.Cells["codigoProducto"].Value);
      this.frame.txtProducto.Text = Convert.ToString(this.dgvProducto.CurrentRow.Cells["nombre"].Value);
      this.frame.txtPrecio.Text = Convert.ToString(this.dgvProducto.CurrentRow.Cells["precio"].Value);
      //Cerrando el formulario
      this.Hide();
    }

  }
}

3.5. Formulario frmRegistrarVenta

Este formulario es la parte principal del sistema en cual se registra la venta. Tener en cuenta que si el detalle de la venta es mayor a 50 soles, dolares, euros, etc se le aplica un descuento del 5% del sub total de la venta.  Debemos realizar el siguiente diseño del formulario










En cual la accesibilidad de los controles txtProducto txtPrecio es del tipoInternal y tiene la propiedad ReadOnly en True.

Y ademas el componente dgvDetalle tiene los siguientes valores de propiedades:
  • AllowUserToAddRows = False
  • AllowUserToDeleteRows = False
  • MultiSelect = False
  • ReadOnly = True
  • SelectionMode = FullRowSelect
Y como columnas tiene
  • codigoProducto
    • DataPropertyName = codigoProducto
    • HeaderText = codigoProducto
    • Visible = False
  • Producto
    • DataPropertyName = Producto
    • HeaderText = Producto
    • Visible = True
  • Cantidad
    • DataPropertyName = cantidad
    • HeaderText = Cantidad
    • Visible = True
  • PU
    • DataPropertyName = PU
    • HeaderText = PU
    • Visible = True
  • Descuento
    • DataPropertyName = Descuento
    • HeaderText = Descuento
    • Visible = True
  • SubTotal
    • DataPropertyName = subTotal
    • HeaderText = SubTotal
    • Visible = True

Y como código fuente tiene lo siguiente:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
//Comunicarse con la Capa de Negocios
using CapaNegocios;
//Desarollado por Henry Joe Wong Urquiza
namespace CapaPresentacion
{
  public partial class frmRegistrarVenta : Form
  {
    //DataTable que se encargara de guardar el detalle de la venta
    //de forma temporal
    private DataTable dtDetalle;
    //Codigo del producto seleccionado
    internal int codigoProductoSeleccionado = -1;
    //Variable que almacena el total de la venta
    private decimal totalPagar = 0;
    //El constructor de la clase
    public frmRegistrarVenta()
    {
      InitializeComponent();
    }
    //Metodo que se ejecuta al cargar el formulario
    private void frmRegistrarVenta_Load(object sender, EventArgs e)
    {
      this.Top = 0;
      this.Left = 0;
      this.crearTabla();
      this.WindowState = FormWindowState.Maximized;
    }
    //Limpia todos los controles del formulario
    private void limpiarControles()
    {
      this.txtCliente.Text = string.Empty;
      this.codigoProductoSeleccionado = -1;
      this.txtProducto.Text = string.Empty;
      this.txtPrecio.Text = string.Empty;
      this.nudCantidad.Value = 1;
      this.crearTabla();
      this.lblTotalPagar.Text = "Total Pagar: S/. 0.00";

    }
    //Crea la tabla de Detalle 
    private void crearTabla()
    {
      //Crea la tabla con el nombre de Detalle
      this.dtDetalle = new DataTable("Detalle");
      //Agrega las columnas que tendra la tabla
      this.dtDetalle.Columns.Add("codigoProducto", System.Type.GetType("System.Int32"));
      this.dtDetalle.Columns.Add("Producto", System.Type.GetType("System.String"));
      this.dtDetalle.Columns.Add("cantidad", System.Type.GetType("System.Decimal"));
      this.dtDetalle.Columns.Add("PU", System.Type.GetType("System.Decimal"));
      this.dtDetalle.Columns.Add("Descuento", System.Type.GetType("System.Decimal"));
      this.dtDetalle.Columns.Add("subTotal", System.Type.GetType("System.Decimal"));
      //Relacionamos nuestro datagridview con nuestro datatable
      this.dgvDetalle.DataSource = this.dtDetalle;

    }
    //Para mostrar mensaje de error
    private void mError(string mensaje)
    {
      MessageBox.Show(this, mensaje, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Warning);
    }
    //Para mostrar mensaje de confirmación
    private void mOk(string mensaje)
    {
      MessageBox.Show(this, mensaje, "MENSAJE", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    //Evento del clic del boton btnBuscar
    private void btnBuscar_Click(object sender, EventArgs e)
    {
      //Creamos una variable del tipo del formulario que deseamos abrir
      frmSeleccionarProducto frame = new frmSeleccionarProducto();
      //Le pasamos como datos la información de nuestro formulario
      frame.estableceFormulario(this);
      //Mostrar el formulario que tiene los productos que hemos seleccionado
      frame.ShowDialog();
    }
    //Evento clic del boton agregar
    private void btnAgregar_Click(object sender, EventArgs e)
    {
      //Valida que hemos seleccionado algun producto
      if (this.codigoProductoSeleccionado == -1)
      {
        this.mError("No ha seleccionado aun ningun producto");
      }
      else
      {
        //Variable que va a indicar si podemos registrar el detalle
        bool registrar = true;
        foreach (DataRow row in dtDetalle.Rows)
        {
          if (Convert.ToInt32(row["codigoProducto"]) == this.codigoProductoSeleccionado)
          {
            registrar = false;
            this.mError("Ya se encuentra el producto en el detalle");
          }
        }
        //Si podemos registrar el producto en el detalle
        if (registrar)
        {
          //Calculamos el sub total del detalle sin descuento
          decimal subTotal = Convert.ToDecimal(this.txtPrecio.Text) * nudCantidad.Value;
          //Obtenemos el descuento
          decimal descuento = NegDetalleVenta.ObtenerDescuento(
          nudCantidad.Value,
          Convert.ToDecimal(this.txtPrecio.Text));
          //Actualizamos el sub total con el descuento correspondiente
          subTotal = subTotal - descuento;
          //Aumentamos el total a pagar
          this.totalPagar += subTotal;
          this.lblTotalPagar.Text = "Total Pagar: S/." + totalPagar.ToString("#0.00#");
          //Agregamos al fila a nuestro datatable
          DataRow row = this.dtDetalle.NewRow();
          row["codigoProducto"] = this.codigoProductoSeleccionado;
          row["Producto"] = this.txtProducto.Text;
          row["cantidad"] = this.nudCantidad.Value;
          row["PU"] = this.txtPrecio.Text ;
          row["Descuento"] = descuento;
          row["subTotal"] = subTotal;
          this.dtDetalle.Rows.Add(row);
        }
      }
    }
    //Evento click del boton quitar
    private void btnQuitar_Click(object sender, EventArgs e)
    {
      try
      {
        //Indice dila actualmente seleccionado y que vamos a eliminar
        int indiceFila = this.dgvDetalle.CurrentCell.RowIndex;
        //Fila que vamos a eliminar
        DataRow row = this.dtDetalle.Rows[indiceFila];
        //Disminuimos el total a pagar
        this.totalPagar = this.totalPagar - Convert.ToDecimal(row["subTotal"].ToString());
        this.lblTotalPagar.Text = "Total Pagar: S/." + totalPagar.ToString("#0.00#"); 
        //Removemos la fila
        this.dtDetalle.Rows.Remove(row);
      }
      catch (Exception ex)
      {
        mError("No hay fila para remover");
      }
    }

    private void btnGuardar_Click(object sender, EventArgs e)
    {
      //Debe de tener por almenos un detalle para poder registrar
      if (this.dtDetalle.Rows.Count > 0)
      {
        string rpta = NegVenta.Insertar(this.txtCliente.Text, this.dtDetalle);
        if (rpta.Equals("OK"))
        {
          mOk("Se inserto de manera correcta la venta");
          this.limpiarControles();
        }
        else
        {
          mError(rpta);
        }
      }
      else
      {
        mError("No agregado ningun detalle");
      }
    }


  }
}