in

dotNet Umbria [DNU]

Il primo User Group in Umbria sul mondo .Net
Latest post 06-20-2008 12:50 PM by Paolo Possanzini. 4 replies.
Page 1 of 1 (5 items)
Sort Posts: Previous Next
  • 06-05-2008 10:42 PM

    • dardino
    • Top 10 Contributor
    • Joined on 05-19-2008
    • Perugia

    Finestra di dettaglio (Padre - Figlio) e databind refresh

     Ho creato una ListView (nella form "Padre") che carica i dati da un datacontext di LINQ,

    ho creato una form figlio a cui passo un codice che carica i dati in campi di dettaglio relativi a quel codice,
    quando li salvo e torno indietro mi fa vedere le modifiche sulla listview.

    invece se creo un nuovo elemento per la tabella (sempre con LINQ) ed eseguo insertOnSubmit, la ListView non mi si aggiorna. cosa posso fare?

    il codice è simile a quello dell'esempio nella mia lezione.

    Come si fa a "refreshare" il contenuto di una listview?

    esiste qualche altro modo per creare nuove righe?

    Per essere precisi io ho fatto (su OnClick del pulsante Nuovo):

    Dim mydetfrm As New MiaFormDet
    mydetfrm.MioRecord = New TabTipi
    mydetfrm.MioRecord.Flag = "M"
    mydetfrm.MioRecord.Codice = ""
    mydetfrm.MioRecord.Descrizione = "Inserire una descrizione"

    If mydetfrm.ShowDialog = True Then

        Dim myDataProvider As ObjectDataProvider = DirectCast(Me.Resources("MsSqlDbDataContextDS"), ObjectDataProvider)

        Dim myDataContext As MsSqlDbDataContext = DirectCast(myDataProvider.ObjectInstance, MsSqlDbDataContext)

        myDataContext.TabTipis.InsertOnSubmit(mydetfrm.MioRecord)

        Try

            myDataContext.SubmitChanges()

        Catch ex As Exception

            MsgBox(ex.Message)

        End Try

    End If

    Dove "MioRecord" è una classe interna a mydetform che ha la struttura di una riga della tabella tipi di LINQ (infatti non ha la "s" in fondo Smile )

    La routine di modifica dettaglio è praticamente identica (su click del pulsante modifica dettaglio):

    Dim myDataProvider As ObjectDataProvider = DirectCast(Me.Resources("MsSqlDbDataContextDS"), ObjectDataProvider)

    Dim myDataContext As MsSqlDbDataContext = DirectCast(myDataProvider.ObjectInstance, MsSqlDbDataContext)
    Dim mydetfrm As New MiaFormDet
    mydetfrm.MioRecord = (From t In myDataContext.TabTipis Where t.Codice.Equals(ListaElementi.SelectedValue)).First

    If mydetfrm.ShowDialog = True Then

        Try

            myDataContext.SubmitChanges()

        Catch ex As Exception

            MsgBox(ex.Message)

        End Try

    End If

    Dove "ListaElementi" è la listview della form padre (ho notato inoltre che in VB posso omettere la clausola SELECT in LINQ)

    La form figlio mette i valori dal video alla classe MioRecord e infatti quando esco che ho premuto "OK" sulla form figlio, se avevo premuto "MODIFICA" mi si aggiorna correttamente anche la ListView mentre invece se avevo premuto "NUOVO" non mi si aggiorna e devo chiudere e riaprire la finestra per vedere le modifiche.

    Come posso fare?

    Grazie

  • 06-06-2008 1:45 AM In reply to

    Re: Finestra di dettaglio (Padre - Figlio) e databind refresh

    Il problema che hai sollevato con questo tuo post è un problema che hanno tutti coloro che si apprestano ad utilizzare Linq con WPF.

    Di fatto è un problema dovuto al modo in cui Linq solleva ( o in questo caso è meglio dire NON solleva) gli eventi di notifica.

    L'interfaccia utente infatti si accorge che qualcosa è cambiato nella lista perchè quando modifichi un elemento viene sempre sollevato l'evento PropertyChanged con relative indicazioni della proprietà che è cambiata.
    Quando utilizziamo oggetti del tipo ObservableCollection<T> oppure BindingList<T> oltre all'evento di prima viene sollevato anche un'altro evento CollectionChanged oppure ListChanged.

    Quest'ultimo evento informa il layer di presentazione che è stato Aggiunto/Rimosso/Refreshato/Spostato un elemento all'interno della collection e quindi non deve aggiornare una sola proprietà, ma l'intera riga o l'intera collection.
    Se utilizziamo questi oggetti la nostra interfaccia utente non soffrirà del problema che hai descritto.

    Come puoi facilmente intuire dalla mia premessa, Linq non implementa l'interfaccia INotifyCollectionChanged (o altre interfaccie che farebbero quel tipo di notifica) che contiene l'evento CollectionChanged e quindi di fatto non notifica alla UI che qualcosa è cambiato quando io aggiungo, rimuovo o sposto un elemento nella collection.

    TI chiederai : perchè? ...... me lo sto chiedendo anche io!

    Resta di fatto che Linq to SQL attualmente non implementa questa interfaccia e quindi dobbiamo notificare noi che "qualcosa è cambiato".

    Per farlo abbiamo una serie di possibilità:

    1. Fare un Wrapper delle nostre classi Linq
    2. Mettere sempre i risultati in delle ObservableCollection o simili e tenerle aggiornate
    3. Rieseguire la Select
    4. Invocare direttamente i metodi di refresh del binding come spiegato in questo mio post (http://dotnetumbria.org/blogs/articoli/archive/2008/04/10/wpf-invalidate-binding.aspx)
    5. Modifcare l'implementazione del DataContext facendo in modo che implementi INotifyCollectionChanged
    6. Utilizzare Bindable Linq, una estenzione di Linq che ti permette di risolvere i tuoi problemi. (http://www.codeplex.com/bindablelinq)
    7. Invocare il metodo Refresh dell' ObjectDataProvider (non sono sicuro del risultato).

    E' una parte che mi interessa particolarmente, io penso che sceglierò per le mie applicazioni la 5a possibilita. Infatti il Designer di VS mi permette di specificare da quale classe ereditare il DataContext, a quel punto non diventa difficile implementare un Wrapper che faccia gli update al posto nostro, senza dover installare codice di terze parti e specialmente senza dover cambiare , anche se di pochissimo, la nostra sintassi Linq.

     

    Ciao

  • 06-06-2008 3:23 PM In reply to

    • dardino
    • Top 10 Contributor
    • Joined on 05-19-2008
    • Perugia

    Re: Finestra di dettaglio (Padre - Figlio) e databind refresh

    Paolo Possanzini:

    1. Fare un Wrapper delle nostre classi Linq
    2. Mettere sempre i risultati in delle ObservableCollection o simili e tenerle aggiornate
    3. Rieseguire la Select
    4. Invocare direttamente i metodi di refresh del binding come spiegato in questo mio post (http://dotnetumbria.org/blogs/articoli/archive/2008/04/10/wpf-invalidate-binding.aspx)
    5. Modifcare l'implementazione del DataContext facendo in modo che implementi INotifyCollectionChanged
    6. Utilizzare Bindable Linq, una estenzione di Linq che ti permette di risolvere i tuoi problemi. (http://www.codeplex.com/bindablelinq)
    7. Invocare il metodo Refresh dell' ObjectDataProvider (non sono sicuro del risultato).

     

    Grazie 1000 Paolo!!

    c'è qualcosa ancora che non mi è chiara, potresti illustrarmi il punto 5 nel dettaglio?
    Cosa comporta?

    grazie

    P.S. il punto 7 è la prima cosa che ho provato a fare ma nn da risultati!

  • 06-18-2008 11:24 AM In reply to

    • dardino
    • Top 10 Contributor
    • Joined on 05-19-2008
    • Perugia

    Re: Finestra di dettaglio (Padre - Figlio) e databind refresh

     Sto cercando di risolvere il problema tramite il punto 5

    ho fatto in questo modo:

    Partial Class MsSqlDbDataContext

     

        Public Event CollectionChanged(ByVal sender As Object, ByVal e As System.ComponentModel.CollectionChangeEventArgs)

     

        Public Sub raiseCollectionChanged(ByVal Table As Object)

            RaiseEvent CollectionChanged(Me, New ComponentModel.CollectionChangeEventArgs(ComponentModel.CollectionChangeAction.Add, Table))

        End Sub

     

    End Class

    Perché facendo così posso, ogni volta che voglio, richiamare il metodo.

    Purtroppo però non funziona lo stesso!!

    Dove sbaglio?

    Qualcuno può aiutarmi?

     

  • 06-20-2008 12:50 PM In reply to

    Re: Finestra di dettaglio (Padre - Figlio) e databind refresh

     Ho avuto un po' da fare. preparo un piccolo esempio e lo posto.

    Ciao

Page 1 of 1 (5 items)
dotNet Umbria 2007-2008
Powered by Community Server (Commercial Edition), by Telligent Systems