Hei,
Tässä harjoittelen otsikon mukaista yhdistelmää ja usean tunnin googlaaminen ei tuottanut tulosta.
Public Class PGViewModel
Private PGL as ObservableCollection(Of PGModel) 'PGModel sisältää vain Id ja Name muuttujat
Public ReadOnly Property AddNewCommand As ICommand
Public Sub New()
PGL = New ObservableCollection(Of PGModel)(PGService.GetAll)
AddHandler PGL.CollectionChanged, AddressOf CollectionChanged
AddNewCommand = New AddNewPGCommand(PGL)
End Sub
Private Sub CollectionChanged(sender As Object, e As System.Collections.Specialized.NotifyCollectionChangedEventArgs)
If e.Action = Specialized.NotifyCollectionChangedAction.Add Then
Try
PGService.Insert(PGL(e.NewStartingIndex))
Catch ex As Exception
MsgBox(ex.Message)
End Try
End If
End Sub
End ClassPublic Class PGService
Public Sub Insert(ByRef PG As PGModel)
Using conn As New SQLiteConnection(My.Settings.ConnString)
Using cmd As New SQLiteCommand
With cmd
.CommandType = CommandType.Text
.CommandText = "INSERT INTO tblProcessGroup (Name) VALUES ('" & PG.Name & "');"
'.CommandText = "INSERT INTO tblProcessGroup (Name) VALUES ('" & PG.Name & "'); SELECT last_insert_rowid();"
.Connection = conn
End With
conn.Open()
cmd.ExecuteNonQuery()
'PG.Id = cmd.ExecuteScalar()
End Using
End Using
End Sub
End ClassPublic Class AddNewPGCommand
Inherits CommandBase
Private _PGL As ObservableCollection(Of PGModel)
Public Sub New(ByRef PGL As ObservableCollection(Of PGModel))
_PGL = PGL
End Sub
Public Overrides Sub Execute(parameter As Object)
Try
_PGL.Add(New PGModel With {.Name = "TestPG11"})
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
End ClassViewissä on DataGrid (bindattu PGViewModel.PGL ) ja Button(bindattu PGViewModel.AddNewCommand).
Eli button siis laukaisee AddNewCommand-komennon, joka lisää PGL kokoelmaan yhden rivin, joka taas laukaisee CollectionCanged eventin PGViewModelissa, joka kirjoittaa kyseisen tietueen tietokantaan.
Homma toimii ihan kivasti näin, mutta tarvisin tuon uuden rivin Id:n joka generoidaan automaattisesti tietokannassa(Nyt se on aina 0). Kokeilin asettaa sitä tuossa PGService.Insert metodissa (comment out rivit) mutta CollectionChanged Eventissä saan virheen (try catch message) -> "Cannot change ObservableCollection during a CollectionChanged event.". Id Muutos menee kuitenkin läpi pelkällä em. ilmoituksella. Ilman try-catch blokkeja prosessi ei mene läpi.
Miten tämä oikeaoppisesti toteutetaan?
Yleensä sen saa automaattisesti jostain. Netissä vihjataan, että SQLiteConnection-luokassa olisi LastInsertRowId. Näköjään System.Data.SQLite-kirjaston dokumentaatio on vain CHM-formaatissa ja lähdekoodiakaan ei saa netissä selattua, joten voit varmaan selailla näitä omalla koneellesi asian tarkistamiseksi.
Siis juuri tuotahan olen käyttänytkin, mutta saan tämän herjan:
"Cannot change ObservableCollection during a CollectionChanged event.".
Ihmettelen että se kuitenkin menee läpi kunhan poikkeus "käsitellään" (=MsgBox) Catch blokissa, enkä millään saata uskoa että tämä olisi se oikea tapa.
Public Class PGService
Public Sub Insert(ByRef PG As PGModel)
Using conn As New SQLiteConnection(My.Settings.ConnString)
Using cmd As New SQLiteCommand
With cmd
.CommandType = CommandType.Text
.CommandText = "INSERT INTO tblProcessGroup (Name) VALUES ('" & PG.Name & "');"
---------> '.CommandText = "INSERT INTO tblProcessGroup (Name) VALUES ('" & PG.Name & "'); SELECT last_insert_rowid();"
.Connection = conn
End With
conn.Open()
cmd.ExecuteNonQuery()
---------> 'PG.Id = cmd.ExecuteScalar()
End Using
End Using
End Sub
End ClassKyllähän SQL-kyselyn muuttaminen on ihan eri asia kuin valmis LastInsertRowId-ominaisuus. Kiva jos toimii kuitenkin.
Debuggausvinkkejä: Kun saamasi virheilmoitus valittaa muokkaamisesta, niin olisiko vika siinä, että PG.Id:tä ei saa muuttaa tuossa kohti? Eli jos laitat vaikka ihan PG.Id = 123, niin tuleeko virhe tästäkin? Sittenhän sinun pitää ratkaista tätä ihan ohjelman rakenteesta lähtien, että onko tuo oikea paikka laittaa tietoja kantaan tai mitä muuta reittiä id:n voisi välittää.
Mystinen PG aiheuttaa PääGipua, mutta MVVM jää tuosta lyhyestä koodista vielä aika epäselväksi. Nähdäkseni CollectionChanged olisi tarkoitettu enemmänkin siihen, että tietoa (ja ilmoitus muuttumisesta) välittyisi tietokannasta käyttöliittymän suuntaan. Sen sijaan napista tieto pitäisi lisätä ensin kantaan ja sitten vasta tuohon ObservableCollection-olioon.
Metabolix kirjoitti:
Sen sijaan napista tieto pitäisi lisätä ensin kantaan ja sitten vasta tuohon ObservableCollection-olioon.
Tuohan se ratkaisi ongelman, kiitos avusta.
Aihe on jo aika vanha, joten et voi enää vastata siihen.