Principales respuestas
Cómo crear un formulario tipo factura

Pregunta
-
Hola todos, Soy nuevo en el foro pero me gusta consultarlo constantemente, Soy nuevo programando con vb 2010.
Mi necesidad es esta: debo crear un formulario tipo factura, es decir, con tablas padre-hijo de tal manera que tenga su encabezado pero en el detalle sea dinámico: Que en cada registro de una grid pueda validad el codigo (por ejemplo del producto), tener un combobox en una columna (para elegir tipo de producto), cantidad, % Dscto, subtotal, etc. Además, que pueda corregir antes de grabar y cuando haya ingresado todos los registros entonces grabar en mi db, todos los cambios realizados en la grid.
¿Es posible eso? ¿cómo lo haría? . Estoy trabajando con MySQL en una aplicación Windows Forms. Les agradezco su valiosa ayuda....
Respuestas
-
Solph, todo lo expuesto es en referencia a mi formulario para crear una cotización usando una datagridview con ingreso de datos directamente en las celdas. Obviamente debes usar las ideas que puedan servirte.
Mi programación es con n capas, por lo que las lecturas de datos se encuentran fuera de la interfaz de usuario, y desde el codigo se llaman las funciones que hacen las consultas. Te darás cuenta de eso cuando revises el código.
La imagen del formulario es la siguiente:
primero construimos la grilla en base a un tipo personalizado. La definición de la Grilla está en la siguiente clase:
Public Class DgvPlus Inherits DataGridView 'Heredar del DataGridView 'en el 'processDialogKey'... cuando estamos en edicion Protected Overrides Function ProcessDialogKey(ByVal keyData As System.Windows.Forms.Keys) As Boolean If keyData = Keys.Enter Then 'Si es 'enter' SendKeys.Send(Chr(Keys.Tab)) 'Enviar un 'Tab' Return True 'Marcar como procesado Else 'en caso contrario Return MyBase.ProcessDialogKey(keyData) 'devolver KeyData End If End Function End Class
Luego construimos la grilla:
Private WithEvents Listado As New DgvPlus
Este código va al principio de la clase formulario (Public ClassCotizacion_nueva)
Hacemos la llamada a la rutina que construye la grilla y la inserta dentro de un control, en este caso dentro de un Panel:
Private Sub ConstruirGrilla() Listado.ColumnCount = 10 Listado.Columns(0).HeaderText = "Código" Listado.Columns(1).HeaderText = "Descripción" Listado.Columns(2).HeaderText = "P.Unitario" Listado.Columns(3).HeaderText = "Costo" Listado.Columns(4).HeaderText = "Cantidad" Listado.Columns(5).HeaderText = "Total" Listado.Columns(6).HeaderText = "V.Unidad" Listado.Columns(7).HeaderText = "V.Metro/hoja" Listado.Columns(8).HeaderText = "Stock Disponible" Listado.Columns(9).HeaderText = "Unidad" Listado.Columns(0).Width = 60 Listado.Columns(1).Width = 300 Listado.Columns(2).Width = 80 Listado.Columns(3).Width = 80 Listado.Columns(4).Width = 80 Listado.Columns(5).Width = 80 Listado.Columns(6).Width = 90 Listado.Columns(7).Width = 90 Listado.Columns(8).Width = 120 Listado.Columns(9).Width = 100 'codigo Listado.Columns(0).DefaultCellStyle.BackColor = Color.LemonChiffon 'Descripcion Listado.Columns(1).DefaultCellStyle.BackColor = Color.LemonChiffon 'Precio Unitario Listado.Columns(2).DefaultCellStyle.Format = "N0" Listado.Columns(2).DefaultCellStyle.NullValue = "0" Listado.Columns(2).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(2).DefaultCellStyle.BackColor = Color.LemonChiffon 'Costo Listado.Columns(3).DefaultCellStyle.Format = "N0" Listado.Columns(3).DefaultCellStyle.NullValue = "0" Listado.Columns(3).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(3).ReadOnly = True Listado.Columns(3).Visible = True 'Cantidad Listado.Columns(4).DefaultCellStyle.NullValue = "0" Listado.Columns(4).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(4).DefaultCellStyle.BackColor = Color.LemonChiffon 'Total Listado.Columns(5).DefaultCellStyle.Format = "N0" Listado.Columns(5).DefaultCellStyle.NullValue = "0" Listado.Columns(5).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(5).ReadOnly = True 'V.Unidad Listado.Columns(6).DefaultCellStyle.Format = "N0" Listado.Columns(6).DefaultCellStyle.NullValue = "0" Listado.Columns(6).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(6).DefaultCellStyle.BackColor = Color.LemonChiffon 'V. Metro/hoja Listado.Columns(7).DefaultCellStyle.Format = "N0" Listado.Columns(7).DefaultCellStyle.NullValue = "0" Listado.Columns(7).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(7).DefaultCellStyle.BackColor = Color.LemonChiffon 'stock Listado.Columns(8).DefaultCellStyle.NullValue = "0" Listado.Columns(8).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(8).ReadOnly = True 'Unidad Listado.Columns(9).ReadOnly = True Listado.BackgroundColor = Color.LightSteelBlue Panel2.Controls.Add(Listado) Listado.Dock = DockStyle.Fill Listado.AlternatingRowsDefaultCellStyle.BackColor = Color.AliceBlue End Sub
Bien, con eso esta construida la grilla, ahora el manejo de los datos en las celdas:
'cuando el usuario ha ingresado un dato en una celda Private Sub Listado_CellEndEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Dim Precio As Integer = 0 If e.ColumnIndex = 0 Then 'codigo Dim Codigo As String = Listado.CurrentCell.Value.ToString Dim p As New Producto p = [Global].Business.Conexion.GetProducto(Codigo) ' se busca el producto filtrando por código de producto If p IsNot Nothing Then If p.Activo = 1 Then Dim Mensaje As String = "El Código de Producto existe pero está inactivo." Mensaje += "(" & p.Descripcion & ")" MessageBox.Show(Mensaje, "Validación", MessageBoxButtons.OK, MessageBoxIcon.Information) Exit Sub End If 'como el producto existe, muestra sus datos en las respectivas celdas Listado.Rows(e.RowIndex).Cells(1).Value = p.Descripcion Listado.Rows(e.RowIndex).Cells(3).Value = p.PrecioCosto Listado.Rows(e.RowIndex).Cells(9).Value = p.Unidad.Unidad 'rutina que determina el precio al que se venderá el producto. Dim UltimoPrecio As Integer = 0 If txtRut.Text.Trim = String.Empty Then UltimoPrecio = 0 Else UltimoPrecio = TraerUltimoPrecio(Codigo, txtRut.Text) End If If UltimoPrecio <> 0 Then Precio = UltimoPrecio Else Precio = CalcularPRecio(p) End If 'coloca el precio determinado en la celda correspondiente Listado.Rows(e.RowIndex).Cells(2).Value = Precio 'Calcula cantidad * precio Multiplicar(e.RowIndex) End If ' si la celda que se ha modificado es la que contiene el precio de venta ElseIf e.ColumnIndex = 2 Then 'precio If IsNumeric(Listado.CurrentCell.Value) = False Then Listado.CurrentCell = Listado.CurrentRow.Cells(2) Listado.CurrentCell.ErrorText = "Solo números positivos mayores que cero." Listado.CurrentCell.Value = 0 Listado.Rows(e.RowIndex).Cells(5).Value = 0 Exit Sub Else If Listado.CurrentCell.Value > 0 Then Listado.CurrentCell.ErrorText = String.Empty If IsNumeric(Listado.CurrentCell.Value) = False Then Exit Sub Dim Cantidad As Double = Listado.CurrentCell.Value Multiplicar(e.RowIndex) Else Listado.CurrentCell.ErrorText = "Solo números positivos mayores que cero." Listado.CurrentCell.Value = 0 Listado.Rows(e.RowIndex).Cells(5).Value = 0 End If End If ' si la celda que se ha modificado es la que contien la cantidad ElseIf e.ColumnIndex = 4 Then 'cantidad If IsNumeric(Listado.CurrentCell.Value) = False Then Listado.CurrentCell = Listado.CurrentRow.Cells(4) Listado.CurrentCell.ErrorText = "Solo números positivos mayores que cero." Listado.CurrentCell.Value = 0 Listado.Rows(e.RowIndex).Cells(5).Value = 0 Exit Sub Else If Listado.CurrentCell.Value > 0 Then Listado.CurrentCell.ErrorText = String.Empty If IsNumeric(Listado.CurrentCell.Value) = False Then Exit Sub Dim Cantidad As Double = Listado.CurrentCell.Value Multiplicar(e.RowIndex) Else Listado.CurrentCell.ErrorText = "Solo números positivos mayores que cero." Listado.CurrentCell.Value = 0 Listado.Rows(e.RowIndex).Cells(5).Value = 0 End If End If 'valida que el stock disponible sea suficiente para efectuar la venta Dim stockDisponible As Integer = Listado.Rows(e.RowIndex).Cells(8).Value If stockDisponible < Listado.CurrentCell.Value Then MessageBox.Show("No hay stock suficiente.", "Validación", MessageBoxButtons.OK, MessageBoxIcon.Warning) Listado.Rows(e.RowIndex).DefaultCellStyle.ForeColor = Color.Red Exit Sub Else Listado.Rows(e.RowIndex).DefaultCellStyle.ForeColor = Color.Black End If End If Sumar() End Sub
Las rutinas relacionadas y que son llamadas del codigo anterior son:
'obtiene el último precio del producto. 'la consulta se encuentra en otra capa del proyecto. Private Function TraerUltimoPrecio(ByVal codigo As String, ByVal rut As String) As Integer Try Return [Global].Business.Conexion.GetUltimoPrecio(codigo, rut) Catch ex As Exception MessageBox.Show("Error al buscar último precio: " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error) Return 0 End Try End Function
'Multiplica la cantidad por el precio unitario y pone el total en la celda correspondiente. Private Sub Multiplicar(ByVal fila As Integer) Listado.Rows(fila).Cells(5).Value = Listado.Rows(fila).Cells(4).Value * Listado.Rows(fila).Cells(2).Value End Sub
'suma el monto total de cada linea y calcula los impuestos. Private Sub Sumar() 'valida la cantidad de líenas que acepta el documento If Listado.Rows.Count - 1 <= Integer.Parse(lblLineas.Text) - 1 Then Dim suma As Integer = 0 Dim iva As Integer = 0 Dim total As Integer = 0 Dim factor As Double = Double.Parse(lblIVA.Text) / 100 Try For i As Integer = 0 To Listado.Rows.Count - 2 suma += Listado.Rows(i).Cells(5).Value Next iva = suma * factor total = suma + iva txtSumaAfecto.Text = String.Format("{0:n0}", suma) txtSumaIva.Text = String.Format("{0:n0}", iva) txtSumaTotal.Text = String.Format("{0:n0}", total) Catch ex As Exception End Try Else MessageBox.Show("La Cotización no acepta más lineas.", "Validación", MessageBoxButtons.OK) Listado.AllowUserToAddRows = False Listado.Refresh() Exit Sub End If End Sub
Bueno, eso es todo, como puedes ver todos los cálculos se hacen en CellEndEdit, dependiendo de que celda es la que ha utilizado el usuario.
respecto de tu consulta ¿Qué es mejor? ¿usar enlace a datos o realizr todo en forma programática? ¿y Por qué? yo creo que depende de cada uno. Para unos será más facil con enlace a datos y para otros será más facil de la forma dificil (jejejej). En mi caso, como ya soy viejito, he programado siempre a codigo pelado...
Finalmente, quedo a tus ordenes para cualquier consulta y, si esto te ha sido útil, márcala como resupesta.
Atentamente
Manuel Luengo
- Editado manuel.softmedia martes, 14 de febrero de 2012 21:05 complementar
- Marcado como respuesta Solp martes, 14 de febrero de 2012 21:20
Todas las respuestas
-
Tal vez algo de esto te pueda orientar...
http://social.msdn.microsoft.com/Forums/es-ES/vbes/thread/b0560a4c-6f59-4501-97d7-8941c0671b67
Atentamente,
Manuel Luengo
-
Gracias Manuel por tu colaboración.
No obstante, lo que quisiera es no utilizar unos texbox's que sirvan de captura y un datagridview que me los muestre, sino en la misma grilla poder realizar las modificaciones. En este momento se me ocurre algo, ustedes me dicen si es factible:
cuando uno crea el datagridview tiene la opción de permitir actualizar o eliminar o adionar. utilizando estas propiedades, ¿se podría hacer lo que pienso? voy a probar. Si se puede por favor, les agradezco su colaboración.
Atentemente,
Solph.
-
En el caso de que la grilla este enlazada a datos, es posible hacer lo que indicas.
Yo, en lo personal no uso enlace a datos y realizo todas las operaciones en forma programática.
Si quieres puedo dejarte algunos código de ejemplo para trabajar directamente sobre las celdas de la grilla, pero siempre programáticamente.Atentamente,
Manuel Luengo
-
Gracias Manuel,
Sí me interesa analizar los códigos que usas para no usar enlace a datos.
Te pregunto una cosa: ¿Qué es mejor? ¿usar enlace a datos o realizr todo en forma programática? ¿y Por qué? ¿tiene inconvenientes usar enlace a datos? Hasta ahora en los formularios de captura básica, ej: productos, terceros, etc. lo he hecho en enlace a datos.
Te agradezco tu ayuda.
Atentamente,
Solph.
-
Solph, todo lo expuesto es en referencia a mi formulario para crear una cotización usando una datagridview con ingreso de datos directamente en las celdas. Obviamente debes usar las ideas que puedan servirte.
Mi programación es con n capas, por lo que las lecturas de datos se encuentran fuera de la interfaz de usuario, y desde el codigo se llaman las funciones que hacen las consultas. Te darás cuenta de eso cuando revises el código.
La imagen del formulario es la siguiente:
primero construimos la grilla en base a un tipo personalizado. La definición de la Grilla está en la siguiente clase:
Public Class DgvPlus Inherits DataGridView 'Heredar del DataGridView 'en el 'processDialogKey'... cuando estamos en edicion Protected Overrides Function ProcessDialogKey(ByVal keyData As System.Windows.Forms.Keys) As Boolean If keyData = Keys.Enter Then 'Si es 'enter' SendKeys.Send(Chr(Keys.Tab)) 'Enviar un 'Tab' Return True 'Marcar como procesado Else 'en caso contrario Return MyBase.ProcessDialogKey(keyData) 'devolver KeyData End If End Function End Class
Luego construimos la grilla:
Private WithEvents Listado As New DgvPlus
Este código va al principio de la clase formulario (Public ClassCotizacion_nueva)
Hacemos la llamada a la rutina que construye la grilla y la inserta dentro de un control, en este caso dentro de un Panel:
Private Sub ConstruirGrilla() Listado.ColumnCount = 10 Listado.Columns(0).HeaderText = "Código" Listado.Columns(1).HeaderText = "Descripción" Listado.Columns(2).HeaderText = "P.Unitario" Listado.Columns(3).HeaderText = "Costo" Listado.Columns(4).HeaderText = "Cantidad" Listado.Columns(5).HeaderText = "Total" Listado.Columns(6).HeaderText = "V.Unidad" Listado.Columns(7).HeaderText = "V.Metro/hoja" Listado.Columns(8).HeaderText = "Stock Disponible" Listado.Columns(9).HeaderText = "Unidad" Listado.Columns(0).Width = 60 Listado.Columns(1).Width = 300 Listado.Columns(2).Width = 80 Listado.Columns(3).Width = 80 Listado.Columns(4).Width = 80 Listado.Columns(5).Width = 80 Listado.Columns(6).Width = 90 Listado.Columns(7).Width = 90 Listado.Columns(8).Width = 120 Listado.Columns(9).Width = 100 'codigo Listado.Columns(0).DefaultCellStyle.BackColor = Color.LemonChiffon 'Descripcion Listado.Columns(1).DefaultCellStyle.BackColor = Color.LemonChiffon 'Precio Unitario Listado.Columns(2).DefaultCellStyle.Format = "N0" Listado.Columns(2).DefaultCellStyle.NullValue = "0" Listado.Columns(2).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(2).DefaultCellStyle.BackColor = Color.LemonChiffon 'Costo Listado.Columns(3).DefaultCellStyle.Format = "N0" Listado.Columns(3).DefaultCellStyle.NullValue = "0" Listado.Columns(3).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(3).ReadOnly = True Listado.Columns(3).Visible = True 'Cantidad Listado.Columns(4).DefaultCellStyle.NullValue = "0" Listado.Columns(4).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(4).DefaultCellStyle.BackColor = Color.LemonChiffon 'Total Listado.Columns(5).DefaultCellStyle.Format = "N0" Listado.Columns(5).DefaultCellStyle.NullValue = "0" Listado.Columns(5).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(5).ReadOnly = True 'V.Unidad Listado.Columns(6).DefaultCellStyle.Format = "N0" Listado.Columns(6).DefaultCellStyle.NullValue = "0" Listado.Columns(6).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(6).DefaultCellStyle.BackColor = Color.LemonChiffon 'V. Metro/hoja Listado.Columns(7).DefaultCellStyle.Format = "N0" Listado.Columns(7).DefaultCellStyle.NullValue = "0" Listado.Columns(7).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(7).DefaultCellStyle.BackColor = Color.LemonChiffon 'stock Listado.Columns(8).DefaultCellStyle.NullValue = "0" Listado.Columns(8).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(8).ReadOnly = True 'Unidad Listado.Columns(9).ReadOnly = True Listado.BackgroundColor = Color.LightSteelBlue Panel2.Controls.Add(Listado) Listado.Dock = DockStyle.Fill Listado.AlternatingRowsDefaultCellStyle.BackColor = Color.AliceBlue End Sub
Bien, con eso esta construida la grilla, ahora el manejo de los datos en las celdas:
'cuando el usuario ha ingresado un dato en una celda Private Sub Listado_CellEndEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Dim Precio As Integer = 0 If e.ColumnIndex = 0 Then 'codigo Dim Codigo As String = Listado.CurrentCell.Value.ToString Dim p As New Producto p = [Global].Business.Conexion.GetProducto(Codigo) ' se busca el producto filtrando por código de producto If p IsNot Nothing Then If p.Activo = 1 Then Dim Mensaje As String = "El Código de Producto existe pero está inactivo." Mensaje += "(" & p.Descripcion & ")" MessageBox.Show(Mensaje, "Validación", MessageBoxButtons.OK, MessageBoxIcon.Information) Exit Sub End If 'como el producto existe, muestra sus datos en las respectivas celdas Listado.Rows(e.RowIndex).Cells(1).Value = p.Descripcion Listado.Rows(e.RowIndex).Cells(3).Value = p.PrecioCosto Listado.Rows(e.RowIndex).Cells(9).Value = p.Unidad.Unidad 'rutina que determina el precio al que se venderá el producto. Dim UltimoPrecio As Integer = 0 If txtRut.Text.Trim = String.Empty Then UltimoPrecio = 0 Else UltimoPrecio = TraerUltimoPrecio(Codigo, txtRut.Text) End If If UltimoPrecio <> 0 Then Precio = UltimoPrecio Else Precio = CalcularPRecio(p) End If 'coloca el precio determinado en la celda correspondiente Listado.Rows(e.RowIndex).Cells(2).Value = Precio 'Calcula cantidad * precio Multiplicar(e.RowIndex) End If ' si la celda que se ha modificado es la que contiene el precio de venta ElseIf e.ColumnIndex = 2 Then 'precio If IsNumeric(Listado.CurrentCell.Value) = False Then Listado.CurrentCell = Listado.CurrentRow.Cells(2) Listado.CurrentCell.ErrorText = "Solo números positivos mayores que cero." Listado.CurrentCell.Value = 0 Listado.Rows(e.RowIndex).Cells(5).Value = 0 Exit Sub Else If Listado.CurrentCell.Value > 0 Then Listado.CurrentCell.ErrorText = String.Empty If IsNumeric(Listado.CurrentCell.Value) = False Then Exit Sub Dim Cantidad As Double = Listado.CurrentCell.Value Multiplicar(e.RowIndex) Else Listado.CurrentCell.ErrorText = "Solo números positivos mayores que cero." Listado.CurrentCell.Value = 0 Listado.Rows(e.RowIndex).Cells(5).Value = 0 End If End If ' si la celda que se ha modificado es la que contien la cantidad ElseIf e.ColumnIndex = 4 Then 'cantidad If IsNumeric(Listado.CurrentCell.Value) = False Then Listado.CurrentCell = Listado.CurrentRow.Cells(4) Listado.CurrentCell.ErrorText = "Solo números positivos mayores que cero." Listado.CurrentCell.Value = 0 Listado.Rows(e.RowIndex).Cells(5).Value = 0 Exit Sub Else If Listado.CurrentCell.Value > 0 Then Listado.CurrentCell.ErrorText = String.Empty If IsNumeric(Listado.CurrentCell.Value) = False Then Exit Sub Dim Cantidad As Double = Listado.CurrentCell.Value Multiplicar(e.RowIndex) Else Listado.CurrentCell.ErrorText = "Solo números positivos mayores que cero." Listado.CurrentCell.Value = 0 Listado.Rows(e.RowIndex).Cells(5).Value = 0 End If End If 'valida que el stock disponible sea suficiente para efectuar la venta Dim stockDisponible As Integer = Listado.Rows(e.RowIndex).Cells(8).Value If stockDisponible < Listado.CurrentCell.Value Then MessageBox.Show("No hay stock suficiente.", "Validación", MessageBoxButtons.OK, MessageBoxIcon.Warning) Listado.Rows(e.RowIndex).DefaultCellStyle.ForeColor = Color.Red Exit Sub Else Listado.Rows(e.RowIndex).DefaultCellStyle.ForeColor = Color.Black End If End If Sumar() End Sub
Las rutinas relacionadas y que son llamadas del codigo anterior son:
'obtiene el último precio del producto. 'la consulta se encuentra en otra capa del proyecto. Private Function TraerUltimoPrecio(ByVal codigo As String, ByVal rut As String) As Integer Try Return [Global].Business.Conexion.GetUltimoPrecio(codigo, rut) Catch ex As Exception MessageBox.Show("Error al buscar último precio: " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error) Return 0 End Try End Function
'Multiplica la cantidad por el precio unitario y pone el total en la celda correspondiente. Private Sub Multiplicar(ByVal fila As Integer) Listado.Rows(fila).Cells(5).Value = Listado.Rows(fila).Cells(4).Value * Listado.Rows(fila).Cells(2).Value End Sub
'suma el monto total de cada linea y calcula los impuestos. Private Sub Sumar() 'valida la cantidad de líenas que acepta el documento If Listado.Rows.Count - 1 <= Integer.Parse(lblLineas.Text) - 1 Then Dim suma As Integer = 0 Dim iva As Integer = 0 Dim total As Integer = 0 Dim factor As Double = Double.Parse(lblIVA.Text) / 100 Try For i As Integer = 0 To Listado.Rows.Count - 2 suma += Listado.Rows(i).Cells(5).Value Next iva = suma * factor total = suma + iva txtSumaAfecto.Text = String.Format("{0:n0}", suma) txtSumaIva.Text = String.Format("{0:n0}", iva) txtSumaTotal.Text = String.Format("{0:n0}", total) Catch ex As Exception End Try Else MessageBox.Show("La Cotización no acepta más lineas.", "Validación", MessageBoxButtons.OK) Listado.AllowUserToAddRows = False Listado.Refresh() Exit Sub End If End Sub
Bueno, eso es todo, como puedes ver todos los cálculos se hacen en CellEndEdit, dependiendo de que celda es la que ha utilizado el usuario.
respecto de tu consulta ¿Qué es mejor? ¿usar enlace a datos o realizr todo en forma programática? ¿y Por qué? yo creo que depende de cada uno. Para unos será más facil con enlace a datos y para otros será más facil de la forma dificil (jejejej). En mi caso, como ya soy viejito, he programado siempre a codigo pelado...
Finalmente, quedo a tus ordenes para cualquier consulta y, si esto te ha sido útil, márcala como resupesta.
Atentamente
Manuel Luengo
- Editado manuel.softmedia martes, 14 de febrero de 2012 21:05 complementar
- Marcado como respuesta Solp martes, 14 de febrero de 2012 21:20
-
-
-
Manuel
no hubiera sido mas practico subir el ejemplo de codigo en un zip a skydrive para que lo descargara
en lugar de poner todo el codigo en el foro, digo creo que hubiera ayudado mas y no quedaria tan extenso
Leandro Tuttini
Blog
Buenos Aires
Argentina -
-
Hola Buenos días Manuel,
He estado adaptando el código. Tengo algunas dificultades... quizás por cuanto todavía no manejo lo de n-Capas.
Es posible que usted me envíe el código empaquetado para mirar cómo están dispuestas las rutinas y analizar mejor?
por ejemplo no entiendo el CellEndEdit, muy bien... Si es posible. Le agradezco.
Atentamente,
Solph.
-
-
-
-
-
-
Hola Solp,
Ya he observado que Manuel te ha dado casi el trabajo hecho. Pero me gustaria añadir otra opción mucha más orientada a objetos y creo que de más fácil mantenimiento en un futuro.
Podrias realizar lo mismo utilizando objetos enlazados al dataSource de un objeto BindingSource y luego ese objeto BindingSource asignarlo a la propiedad dataSource del DatagridView de la siguiente forma:
this.MaestroBindingSource.DataSource = objectList; this.DetalleBindingSource.DataSource = MaestroBindingSource; this.DetalleBindingSource.DataMember = "Atributo del objectList"; this.dataGridView1.DataSource = DetalleBindingSource;
Creo que queda más limpio.
Saludos.
Albert Gassó
Ingeniero Técnico en Informática
Computer Software Engineer -
Gracias Albert por tu aportación, lo tendré en cuenta.
No obstante, lo que necesito es poder editar la grilla, realizar los cambios (insertar, modificar,etc.) y finalmente guardar los cambios y además,
Que en cada registro de una grid pueda validad el codigo (por ejemplo del producto), tener un combobox en una columna (para elegir tipo de producto), cantidad, % Dscto, subtotal, etc.
Si tienes otra forma, te agradezco me lo envíes para comparar y realizar uno bastante acorde con lo que necesito.
Muchas gracias,
Solph.
-
Hola Solp,
Ya he observado que Manuel te ha dado casi el trabajo hecho. Pero me gustaria añadir otra opción mucha más orientada a objetos y creo que de más fácil mantenimiento en un futuro.
Podrias realizar lo mismo utilizando objetos enlazados al dataSource de un objeto BindingSource y luego ese objeto BindingSource asignarlo a la propiedad dataSource del DatagridView de la siguiente forma:
this.MaestroBindingSource.DataSource = objectList; this.DetalleBindingSource.DataSource = MaestroBindingSource; this.DetalleBindingSource.DataMember = "Atributo del objectList"; this.dataGridView1.DataSource = DetalleBindingSource;
Creo que queda más limpio.
Saludos.
Albert Gassó
Ingeniero Técnico en Informática
Computer Software Engineer
Los objetos enlazados a datos facilitan mucho el trabajo es cierto, pero yo, que ya soy viejito en el tema, prefiero trabajar línea a línea. Siento que tengo dominio completo sobre el código y que el programa hace lo que quiero que haga.
Obviamente cada uno verá como le acomoda más.
Manuel Luengo
-
Hola Albert,
cuando dices que utilice:
this.MaestroBindingSource.DataSource = objectList;
el "objectList"a qué te refieres?
el "Atributo del objectList" en
this.DetalleBindingSource.DataMember = "Atributo del objectList";
¿qué es? es que soy nuevo programando en vb.net 2010
En el formulario donde utilizo principalmente 1 tabla maestro y el datagridview contiene el detalle
como se haría?
podrías ponerme un ejemplo? las tablas que tengo son:
en el maestro "Egresos" y el detalle es "det_egresos" la DatagridView es "dgvEgresos"
Te agradezco la aclaración y la colaboración
Solph.
- Editado Solp lunes, 20 de febrero de 2012 23:02
-
Hola Manuel,
Trabajar con objetos no significa que pierdas dominio sobre el código, sinó todo lo contrario, y además de manera más estructurada, flexible y mantenible. Pero logicamente cada uno se encuentra más a gusto con un paradigma en concreto.
Saludos
Albert Gassó
Ingeniero Técnico en Informática
Computer Software Engineer -
Hola Solp,
Cuando pongo objectList me refiero a un objeto de tipo lista, te pongo un ejemplo muy sencillo, perfecto para el caso que estamos comentando:
public class Object : IEditableObject { private int id; private List<objectdetail> liniasDetalle; } public class ObjectList : BindingList<object> { } public class ObjectDetail : IEditableObject { private int idLinia; } public class ObjectDetailList : BindingList<objectdetail> { } public partial class Form1 : Form { Maestrobindingsource.DataSource = ObjectList; Detallebindingsource.DataSource = Maestrobindingsource; Detallebindingsource.DataMember = liniasDetalle; dataGridView1.DataSource = Detallebindingsource; }</objectdetail></object></objectdetail>
Espero te sirva.
Nota: El código está en C# pero te será fácil traducirlo a VB
Saludos
Albert Gassó
Ingeniero Técnico en Informática
Computer Software Engineer
- Editado Albert Gassó martes, 21 de febrero de 2012 11:46 Añadir Nota
-
-
hola man oe me puedes pasar el archivo comprimido en winzip.......porfavor......enviamelo a mi correo joseph_loveyou@hotmail.com
Solph, todo lo expuesto es en referencia a mi formulario para crear una cotización usando una datagridview con ingreso de datos directamente en las celdas. Obviamente debes usar las ideas que puedan servirte.
Mi programación es con n capas, por lo que las lecturas de datos se encuentran fuera de la interfaz de usuario, y desde el codigo se llaman las funciones que hacen las consultas. Te darás cuenta de eso cuando revises el código.
La imagen del formulario es la siguiente:
primero construimos la grilla en base a un tipo personalizado. La definición de la Grilla está en la siguiente clase:
Public Class DgvPlus Inherits DataGridView 'Heredar del DataGridView 'en el 'processDialogKey'... cuando estamos en edicion Protected Overrides Function ProcessDialogKey(ByVal keyData As System.Windows.Forms.Keys) As Boolean If keyData = Keys.Enter Then 'Si es 'enter' SendKeys.Send(Chr(Keys.Tab)) 'Enviar un 'Tab' Return True 'Marcar como procesado Else 'en caso contrario Return MyBase.ProcessDialogKey(keyData) 'devolver KeyData End If End Function End Class
Luego construimos la grilla:
Private WithEvents Listado As New DgvPlus
Este código va al principio de la clase formulario (Public ClassCotizacion_nueva)
Hacemos la llamada a la rutina que construye la grilla y la inserta dentro de un control, en este caso dentro de un Panel:
Private Sub ConstruirGrilla() Listado.ColumnCount = 10 Listado.Columns(0).HeaderText = "Código" Listado.Columns(1).HeaderText = "Descripción" Listado.Columns(2).HeaderText = "P.Unitario" Listado.Columns(3).HeaderText = "Costo" Listado.Columns(4).HeaderText = "Cantidad" Listado.Columns(5).HeaderText = "Total" Listado.Columns(6).HeaderText = "V.Unidad" Listado.Columns(7).HeaderText = "V.Metro/hoja" Listado.Columns(8).HeaderText = "Stock Disponible" Listado.Columns(9).HeaderText = "Unidad" Listado.Columns(0).Width = 60 Listado.Columns(1).Width = 300 Listado.Columns(2).Width = 80 Listado.Columns(3).Width = 80 Listado.Columns(4).Width = 80 Listado.Columns(5).Width = 80 Listado.Columns(6).Width = 90 Listado.Columns(7).Width = 90 Listado.Columns(8).Width = 120 Listado.Columns(9).Width = 100 'codigo Listado.Columns(0).DefaultCellStyle.BackColor = Color.LemonChiffon 'Descripcion Listado.Columns(1).DefaultCellStyle.BackColor = Color.LemonChiffon 'Precio Unitario Listado.Columns(2).DefaultCellStyle.Format = "N0" Listado.Columns(2).DefaultCellStyle.NullValue = "0" Listado.Columns(2).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(2).DefaultCellStyle.BackColor = Color.LemonChiffon 'Costo Listado.Columns(3).DefaultCellStyle.Format = "N0" Listado.Columns(3).DefaultCellStyle.NullValue = "0" Listado.Columns(3).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(3).ReadOnly = True Listado.Columns(3).Visible = True 'Cantidad Listado.Columns(4).DefaultCellStyle.NullValue = "0" Listado.Columns(4).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(4).DefaultCellStyle.BackColor = Color.LemonChiffon 'Total Listado.Columns(5).DefaultCellStyle.Format = "N0" Listado.Columns(5).DefaultCellStyle.NullValue = "0" Listado.Columns(5).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(5).ReadOnly = True 'V.Unidad Listado.Columns(6).DefaultCellStyle.Format = "N0" Listado.Columns(6).DefaultCellStyle.NullValue = "0" Listado.Columns(6).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(6).DefaultCellStyle.BackColor = Color.LemonChiffon 'V. Metro/hoja Listado.Columns(7).DefaultCellStyle.Format = "N0" Listado.Columns(7).DefaultCellStyle.NullValue = "0" Listado.Columns(7).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(7).DefaultCellStyle.BackColor = Color.LemonChiffon 'stock Listado.Columns(8).DefaultCellStyle.NullValue = "0" Listado.Columns(8).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Listado.Columns(8).ReadOnly = True 'Unidad Listado.Columns(9).ReadOnly = True Listado.BackgroundColor = Color.LightSteelBlue Panel2.Controls.Add(Listado) Listado.Dock = DockStyle.Fill Listado.AlternatingRowsDefaultCellStyle.BackColor = Color.AliceBlue End Sub
Bien, con eso esta construida la grilla, ahora el manejo de los datos en las celdas:
'cuando el usuario ha ingresado un dato en una celda Private Sub Listado_CellEndEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Dim Precio As Integer = 0 If e.ColumnIndex = 0 Then 'codigo Dim Codigo As String = Listado.CurrentCell.Value.ToString Dim p As New Producto p = [Global].Business.Conexion.GetProducto(Codigo) ' se busca el producto filtrando por código de producto If p IsNot Nothing Then If p.Activo = 1 Then Dim Mensaje As String = "El Código de Producto existe pero está inactivo." Mensaje += "(" & p.Descripcion & ")" MessageBox.Show(Mensaje, "Validación", MessageBoxButtons.OK, MessageBoxIcon.Information) Exit Sub End If 'como el producto existe, muestra sus datos en las respectivas celdas Listado.Rows(e.RowIndex).Cells(1).Value = p.Descripcion Listado.Rows(e.RowIndex).Cells(3).Value = p.PrecioCosto Listado.Rows(e.RowIndex).Cells(9).Value = p.Unidad.Unidad 'rutina que determina el precio al que se venderá el producto. Dim UltimoPrecio As Integer = 0 If txtRut.Text.Trim = String.Empty Then UltimoPrecio = 0 Else UltimoPrecio = TraerUltimoPrecio(Codigo, txtRut.Text) End If If UltimoPrecio <> 0 Then Precio = UltimoPrecio Else Precio = CalcularPRecio(p) End If 'coloca el precio determinado en la celda correspondiente Listado.Rows(e.RowIndex).Cells(2).Value = Precio 'Calcula cantidad * precio Multiplicar(e.RowIndex) End If ' si la celda que se ha modificado es la que contiene el precio de venta ElseIf e.ColumnIndex = 2 Then 'precio If IsNumeric(Listado.CurrentCell.Value) = False Then Listado.CurrentCell = Listado.CurrentRow.Cells(2) Listado.CurrentCell.ErrorText = "Solo números positivos mayores que cero." Listado.CurrentCell.Value = 0 Listado.Rows(e.RowIndex).Cells(5).Value = 0 Exit Sub Else If Listado.CurrentCell.Value > 0 Then Listado.CurrentCell.ErrorText = String.Empty If IsNumeric(Listado.CurrentCell.Value) = False Then Exit Sub Dim Cantidad As Double = Listado.CurrentCell.Value Multiplicar(e.RowIndex) Else Listado.CurrentCell.ErrorText = "Solo números positivos mayores que cero." Listado.CurrentCell.Value = 0 Listado.Rows(e.RowIndex).Cells(5).Value = 0 End If End If ' si la celda que se ha modificado es la que contien la cantidad ElseIf e.ColumnIndex = 4 Then 'cantidad If IsNumeric(Listado.CurrentCell.Value) = False Then Listado.CurrentCell = Listado.CurrentRow.Cells(4) Listado.CurrentCell.ErrorText = "Solo números positivos mayores que cero." Listado.CurrentCell.Value = 0 Listado.Rows(e.RowIndex).Cells(5).Value = 0 Exit Sub Else If Listado.CurrentCell.Value > 0 Then Listado.CurrentCell.ErrorText = String.Empty If IsNumeric(Listado.CurrentCell.Value) = False Then Exit Sub Dim Cantidad As Double = Listado.CurrentCell.Value Multiplicar(e.RowIndex) Else Listado.CurrentCell.ErrorText = "Solo números positivos mayores que cero." Listado.CurrentCell.Value = 0 Listado.Rows(e.RowIndex).Cells(5).Value = 0 End If End If 'valida que el stock disponible sea suficiente para efectuar la venta Dim stockDisponible As Integer = Listado.Rows(e.RowIndex).Cells(8).Value If stockDisponible < Listado.CurrentCell.Value Then MessageBox.Show("No hay stock suficiente.", "Validación", MessageBoxButtons.OK, MessageBoxIcon.Warning) Listado.Rows(e.RowIndex).DefaultCellStyle.ForeColor = Color.Red Exit Sub Else Listado.Rows(e.RowIndex).DefaultCellStyle.ForeColor = Color.Black End If End If Sumar() End Sub
Las rutinas relacionadas y que son llamadas del codigo anterior son:
'obtiene el último precio del producto. 'la consulta se encuentra en otra capa del proyecto. Private Function TraerUltimoPrecio(ByVal codigo As String, ByVal rut As String) As Integer Try Return [Global].Business.Conexion.GetUltimoPrecio(codigo, rut) Catch ex As Exception MessageBox.Show("Error al buscar último precio: " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error) Return 0 End Try End Function
'Multiplica la cantidad por el precio unitario y pone el total en la celda correspondiente. Private Sub Multiplicar(ByVal fila As Integer) Listado.Rows(fila).Cells(5).Value = Listado.Rows(fila).Cells(4).Value * Listado.Rows(fila).Cells(2).Value End Sub
'suma el monto total de cada linea y calcula los impuestos. Private Sub Sumar() 'valida la cantidad de líenas que acepta el documento If Listado.Rows.Count - 1 <= Integer.Parse(lblLineas.Text) - 1 Then Dim suma As Integer = 0 Dim iva As Integer = 0 Dim total As Integer = 0 Dim factor As Double = Double.Parse(lblIVA.Text) / 100 Try For i As Integer = 0 To Listado.Rows.Count - 2 suma += Listado.Rows(i).Cells(5).Value Next iva = suma * factor total = suma + iva txtSumaAfecto.Text = String.Format("{0:n0}", suma) txtSumaIva.Text = String.Format("{0:n0}", iva) txtSumaTotal.Text = String.Format("{0:n0}", total) Catch ex As Exception End Try Else MessageBox.Show("La Cotización no acepta más lineas.", "Validación", MessageBoxButtons.OK) Listado.AllowUserToAddRows = False Listado.Refresh() Exit Sub End If End Sub
Bueno, eso es todo, como puedes ver todos los cálculos se hacen en CellEndEdit, dependiendo de que celda es la que ha utilizado el usuario.
respecto de tu consulta ¿Qué es mejor? ¿usar enlace a datos o realizr todo en forma programática? ¿y Por qué? yo creo que depende de cada uno. Para unos será más facil con enlace a datos y para otros será más facil de la forma dificil (jejejej). En mi caso, como ya soy viejito, he programado siempre a codigo pelado...
Finalmente, quedo a tus ordenes para cualquier consulta y, si esto te ha sido útil, márcala como resupesta.
Atentamente
Manuel Luengo
-
Bien, prepararé la porcion de codigo y te lo enviaré al correo señalado. Debes tener en cuenta que lo expuesto es parte de un proyecto mucho más grande, por que habrán referencias que no tendrás disponible.
¿cual es tu nombre?
Atentamente,
Manuel Luengo
-
Bien, prepararé la porcion de codigo y te lo enviaré al correo señalado. Debes tener en cuenta que lo expuesto es parte de un proyecto mucho más grande, por que habrán referencias que no tendrás disponible.
¿cual es tu nombre?
Atentamente,
Manuel Luengo
-