none
Maestro detalle con maestro en controles RRS feed

  • Pregunta

  • Hola!

     

    Llevo tiempo con un tema recurrente que no acabo de solventar de una manera limpia i eficiente.

    Mi problema es el siguiente : 

    Si creo un formulario maestro detalle con dos datagridview ( cómo esta ampliamente documentado en todas partes ) , no tengo ningún problema y todo funciona a la perfección.

    La forma de crearlo es siguiendo este Walkthrough del msdn http://msdn.microsoft.com/en-us/library/y8c0cxey(v=VS.90).aspx

    El problema es cuando en la cabecera en vez de un datagridview quiero poner un conjunto de controles enlazados al bindingsource del maestro.

    Mi idea es, en la cabecera poder tener un conjunto de Textbox y labels con los nombres de los campos.

    Pues bien , el mismo código que funciona bien con un datagridview en la cabecera falla al modificarlo por un panel con un conjunto de controles y un databinding.

    public void BindControls(DataSet ds ) {
                txtRNUM.DataBindings.Add("Text", bsHead, "RNUM");
                dtRFEC.DataBindings.Add("Text", bsHead, "RFEC");
                dtRFEP.DataBindings.Add("Text", bsHead, "RFEP");
                txtID.DataBindings.Add("text", bsHead, "ID");
    }
    


    El error aparece al insertar el detalle , indicando que la referencia a maestro debe existir. ( osease violación de la foreign key).

    Lo curioso es que usando un datagridview en el maestro funciona bien!

    ¿ que diferéncias hay entre el datagridivew y el DataBinding de un control ?

    Entiendo que el datagridivew "graba los datos" al momento en el binding source ?

    Alguna pista ? 

    Alguien con experiencia en el mismo tipo de problema ?

    Gracias!!!!

    jueves, 20 de octubre de 2011 9:50

Respuestas

  • Hola:
    En un Form con 1 ComboBox (cboCustomers) y 1 DataGridView (dgvOrders),
    copia y pega el siguiente codigo.


    Option Explicit On
    Option Strict On
    Imports System.Data.SqlClient

    Public Class Form1
        Private msCadenaSQL As String = "Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True"
        Private mDataSet As DataSet

        Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            Try
                ' Configuramos una conexión con el origen de datos.
                Using loConexion As New SqlConnection(msCadenaSQL)
                    ' crear adaptadores
                    Dim daCustomers As New SqlDataAdapter("SELECT * FROM Customers", loConexion)
                    Dim daOrders As New SqlDataAdapter("SELECT * FROM Orders", loConexion)
                    ' instanciar dataset
                    mDataSet = New DataSet()
                    ' utilizar los dataadapters para llenar el dataset con tablas
                    daCustomers.Fill(mDataSet, "Customers")
                    daOrders.Fill(mDataSet, "Orders")
                    ' relacionar las dos tablas del dataset por campo común
                    mDataSet.Relations.Add("Customers_Orders", mDataSet.Tables("Customers").Columns("CustomerID"), mDataSet.Tables("Orders").Columns("CustomerID"))
                    ' llenar el combobox con los nombres de cliente
                    For Each oDataRow As DataRow In mDataSet.Tables("Customers").Rows
                        Me.cboCustomers.Items.Add(CStr(oDataRow("CustomerID")) & "-" & CStr(oDataRow("CompanyName")))
                    Next
                End Using
            Catch ex As Exception
                ' Devolvemos la excepción al procedimiento llamador.
                Throw
            End Try
        End Sub

        Private Sub cboCustomers_SelectionChangeCommitted(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboCustomers.SelectionChangeCommitted
            ' limpiar los valores del DataGridView
            Me.dgvOrders.DataSource = Nothing
            Dim drFilaPadre As DataRow
            ' obtener la fila de la tabla maestra: Customers
            drFilaPadre = mDataSet.Tables("Customers").Rows(Me.cboCustomers.SelectedIndex)
            Dim drFilasHijas() As DataRow
            ' obtener las filas hijas de la tabla Orders, gracias a la relación Customers-Orders
            drFilasHijas = drFilaPadre.GetChildRows("Customers_Orders")
            Dim dt As New DataTable
            dt.TableName = "Orders"
            ' Creamos tres columnas, y las añadimos al objeto DataTable.
            Dim dc As DataColumn
            dc = New DataColumn("CustomerID", GetType(String))
            dc.MaxLength = 5
            dt.Columns.Add(dc)
            dc = New DataColumn("OrderID", GetType(Int64))
            dt.Columns.Add(dc)
            dc = New DataColumn("OrderDate", GetType(DateTime))
            dt.Columns.Add(dc)
            ' rellenar el datatable con valores de las filas hijas
            Dim dr As DataRow
            For Each drFila In drFilasHijas
                dr = dt.NewRow
                ' Añadimos los datos
                dr.Item("CustomerID") = CStr(drFila("CustomerID"))
                dr.Item("OrderID") = CInt(drFila("OrderID"))
                dr.Item("OrderDate") = CDate(drFila("OrderDate"))
                ' Agregamos el registros a la colección Rows
                dt.Rows.Add(dr)
            Next
            ' cargar los valores al DataGridView
            Me.dgvOrders.DataSource = dt
        End Sub
    End Class

    Un saludo desde Bilbo
    Carlos

    jueves, 20 de octubre de 2011 11:05
  • hola

    y si haces algo como esto

    [N-Tier] – Desarrollo en capas - Ejemplo Facturacion - parte1

    en este no uso databinding, pero si aplico lo que comentas de mostrar una cabecera con controles y detalle con un grid

    por ahi te interece la parte 2

    [N-Tier] – Desarrollo en capas - Ejemplo Facturacion - parte 2

     

    como veras la idea es programar en capas para separar resposabilidades y fomentar la reutilizacion

     

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    jueves, 20 de octubre de 2011 12:18

Todas las respuestas

  • Hola:
    En un Form con 1 ComboBox (cboCustomers) y 1 DataGridView (dgvOrders),
    copia y pega el siguiente codigo.


    Option Explicit On
    Option Strict On
    Imports System.Data.SqlClient

    Public Class Form1
        Private msCadenaSQL As String = "Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True"
        Private mDataSet As DataSet

        Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            Try
                ' Configuramos una conexión con el origen de datos.
                Using loConexion As New SqlConnection(msCadenaSQL)
                    ' crear adaptadores
                    Dim daCustomers As New SqlDataAdapter("SELECT * FROM Customers", loConexion)
                    Dim daOrders As New SqlDataAdapter("SELECT * FROM Orders", loConexion)
                    ' instanciar dataset
                    mDataSet = New DataSet()
                    ' utilizar los dataadapters para llenar el dataset con tablas
                    daCustomers.Fill(mDataSet, "Customers")
                    daOrders.Fill(mDataSet, "Orders")
                    ' relacionar las dos tablas del dataset por campo común
                    mDataSet.Relations.Add("Customers_Orders", mDataSet.Tables("Customers").Columns("CustomerID"), mDataSet.Tables("Orders").Columns("CustomerID"))
                    ' llenar el combobox con los nombres de cliente
                    For Each oDataRow As DataRow In mDataSet.Tables("Customers").Rows
                        Me.cboCustomers.Items.Add(CStr(oDataRow("CustomerID")) & "-" & CStr(oDataRow("CompanyName")))
                    Next
                End Using
            Catch ex As Exception
                ' Devolvemos la excepción al procedimiento llamador.
                Throw
            End Try
        End Sub

        Private Sub cboCustomers_SelectionChangeCommitted(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboCustomers.SelectionChangeCommitted
            ' limpiar los valores del DataGridView
            Me.dgvOrders.DataSource = Nothing
            Dim drFilaPadre As DataRow
            ' obtener la fila de la tabla maestra: Customers
            drFilaPadre = mDataSet.Tables("Customers").Rows(Me.cboCustomers.SelectedIndex)
            Dim drFilasHijas() As DataRow
            ' obtener las filas hijas de la tabla Orders, gracias a la relación Customers-Orders
            drFilasHijas = drFilaPadre.GetChildRows("Customers_Orders")
            Dim dt As New DataTable
            dt.TableName = "Orders"
            ' Creamos tres columnas, y las añadimos al objeto DataTable.
            Dim dc As DataColumn
            dc = New DataColumn("CustomerID", GetType(String))
            dc.MaxLength = 5
            dt.Columns.Add(dc)
            dc = New DataColumn("OrderID", GetType(Int64))
            dt.Columns.Add(dc)
            dc = New DataColumn("OrderDate", GetType(DateTime))
            dt.Columns.Add(dc)
            ' rellenar el datatable con valores de las filas hijas
            Dim dr As DataRow
            For Each drFila In drFilasHijas
                dr = dt.NewRow
                ' Añadimos los datos
                dr.Item("CustomerID") = CStr(drFila("CustomerID"))
                dr.Item("OrderID") = CInt(drFila("OrderID"))
                dr.Item("OrderDate") = CDate(drFila("OrderDate"))
                ' Agregamos el registros a la colección Rows
                dt.Rows.Add(dr)
            Next
            ' cargar los valores al DataGridView
            Me.dgvOrders.DataSource = dt
        End Sub
    End Class

    Un saludo desde Bilbo
    Carlos

    jueves, 20 de octubre de 2011 11:05
  • Hola:
    En un Form con 1 ComboBox (cboCustomers) y 1 DataGridView (dgvOrders),
    copia y pega el siguiente codigo.


    Option Explicit On
    Option Strict On
    Imports System.Data.SqlClient

    Public Class Form1
        Private msCadenaSQL As String = "Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True"
        Private mDataSet As DataSet

        Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            Try
                ' Configuramos una conexión con el origen de datos.
                Using loConexion As New SqlConnection(msCadenaSQL)
                    ' crear adaptadores
                    Dim daCustomers As New SqlDataAdapter("SELECT * FROM Customers", loConexion)
                    Dim daOrders As New SqlDataAdapter("SELECT * FROM Orders", loConexion)
                    ' instanciar dataset
                    mDataSet = New DataSet()
                    ' utilizar los dataadapters para llenar el dataset con tablas
                    daCustomers.Fill(mDataSet, "Customers")
                    daOrders.Fill(mDataSet, "Orders")
                    ' relacionar las dos tablas del dataset por campo común
                    mDataSet.Relations.Add("Customers_Orders", mDataSet.Tables("Customers").Columns("CustomerID"), mDataSet.Tables("Orders").Columns("CustomerID"))
                    ' llenar el combobox con los nombres de cliente
                    For Each oDataRow As DataRow In mDataSet.Tables("Customers").Rows
                        Me.cboCustomers.Items.Add(CStr(oDataRow("CustomerID")) & "-" & CStr(oDataRow("CompanyName")))
                    Next
                End Using
            Catch ex As Exception
                ' Devolvemos la excepción al procedimiento llamador.
                Throw
            End Try
        End Sub

        Private Sub cboCustomers_SelectionChangeCommitted(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboCustomers.SelectionChangeCommitted
            ' limpiar los valores del DataGridView
            Me.dgvOrders.DataSource = Nothing
            Dim drFilaPadre As DataRow
            ' obtener la fila de la tabla maestra: Customers
            drFilaPadre = mDataSet.Tables("Customers").Rows(Me.cboCustomers.SelectedIndex)
            Dim drFilasHijas() As DataRow
            ' obtener las filas hijas de la tabla Orders, gracias a la relación Customers-Orders
            drFilasHijas = drFilaPadre.GetChildRows("Customers_Orders")
            Dim dt As New DataTable
            dt.TableName = "Orders"
            ' Creamos tres columnas, y las añadimos al objeto DataTable.
            Dim dc As DataColumn
            dc = New DataColumn("CustomerID", GetType(String))
            dc.MaxLength = 5
            dt.Columns.Add(dc)
            dc = New DataColumn("OrderID", GetType(Int64))
            dt.Columns.Add(dc)
            dc = New DataColumn("OrderDate", GetType(DateTime))
            dt.Columns.Add(dc)
            ' rellenar el datatable con valores de las filas hijas
            Dim dr As DataRow
            For Each drFila In drFilasHijas
                dr = dt.NewRow
                ' Añadimos los datos
                dr.Item("CustomerID") = CStr(drFila("CustomerID"))
                dr.Item("OrderID") = CInt(drFila("OrderID"))
                dr.Item("OrderDate") = CDate(drFila("OrderDate"))
                ' Agregamos el registros a la colección Rows
                dt.Rows.Add(dr)
            Next
            ' cargar los valores al DataGridView
            Me.dgvOrders.DataSource = dt
        End Sub
    End Class

    Un saludo desde Bilbo
    Carlos

    El problema no esta en cargar los datos ni en mostrarlos,  eso ya funciona bien, si no al añadir un registro.

    j.Carlos tu master-detail es de sólo lectura, mi problema esta al guardar

    Aparte no usas bindingSources te bastas con el método getChilds() de la relación.

     

    jueves, 20 de octubre de 2011 11:38
  • hola

    y si haces algo como esto

    [N-Tier] – Desarrollo en capas - Ejemplo Facturacion - parte1

    en este no uso databinding, pero si aplico lo que comentas de mostrar una cabecera con controles y detalle con un grid

    por ahi te interece la parte 2

    [N-Tier] – Desarrollo en capas - Ejemplo Facturacion - parte 2

     

    como veras la idea es programar en capas para separar resposabilidades y fomentar la reutilizacion

     

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    jueves, 20 de octubre de 2011 12:18
  •  

    Parece que el datagridview al añadir una nueva linea hacer un bindingSource.EndEdit() o algo asi, debo hacerlo manualmente yo al salir de los textbox ?

     

    viernes, 21 de octubre de 2011 7:01