Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: VB.NET: vb.net: datagridview ja validointi

Sivun loppuun

ari kood [24.01.2017 10:34:04]

#

Moi,

Formilla datagridview controlli jonka tietolähteenä taulu (table1) sql serveriltä.

table1:

CREATE TABLE [dbo].[Table1](
	[id] [int] IDENTITY(1,1) NOT NULL,
	[nimi] [nvarchar](4) NOT NULL,
	[selitys] [nvarchar](100) NULL,
 CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED
(
	[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
 CONSTRAINT [UK_table1_nimi] UNIQUE NONCLUSTERED
(
	[nimi] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

VB-koodi:

Public Class Form1


    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        'TODO: This line of code loads data into the 'Testi1DataSet.Table1' table. You can move, or remove it, as needed.
        Me.Table1TableAdapter.Fill(Me.Testi1DataSet.Table1)
    End Sub





    Private Sub DGV1_RowValidating(sender As Object, e As DataGridViewCellCancelEventArgs) Handles DGV1.RowValidating
        Dim dgv As DataGridView = sender
        Dim row As DataGridViewRow = dgv.Rows(e.RowIndex)
        Dim cell As DataGridViewCell = row.Cells(e.ColumnIndex)

        If dgv.IsCurrentRowDirty Then 'jos riviä on muokattu
            For Each c As DataGridViewCell In row.Cells 'käydään läpi jokainen rivin solu
                If c.ColumnIndex = 1 Or c.ColumnIndex = 2 Then 'jos solun indexi on 1(nimi) tai 2(selitys)



                    If c.Value IsNot DBNull.Value Then 'jos solua ei ole jätetty tyhjäksi
                        c.Value = Trim(c.Value) 'trimmataan solu
                    End If

                    If c.ColumnIndex = 1 Then 'jos solun indexi on 1(nimi)
                        c.ErrorText = "" 'nollataan solun errortext
                        If c.Value Is DBNull.Value Or c.Value Is String.Empty Then 'jos solu on trimmauksen jälkeen tyhjä...
                            c.ErrorText = "nimi on tyhjä" 'asetetaan soluun virheteksti
                            e.Cancel = True 'keskeytetään tapahtuma
                        End If
                    End If
                End If
            Next


            If row.Cells(1).ErrorText = "" Then 'jos nimessä ei ole virhettä, eli siihen on kirjoitettu jotain
                Try 'yritetään...

                    Me.Table1BindingSource.EndEdit() 'tiedot datasettiin
                    Me.TableAdapterManager.UpdateAll(Me.Testi1DataSet) 'päivitetään tiedot tietokantaan
                Catch ex As Exception 'jos ei onnistu
                    row.Cells(1).ErrorText = ex.Message 'kerrotaan ongelma rivin virheviestissä
                    e.Cancel = True '...ja perutaan tapahtuma
                End Try
            End If
        End If
    End Sub




End Class

Haluaisin, että käyttäjä ei voisi poistua riviltä ennen kuin on antanut siihen kelvolliset tiedot: eli nimi on max neljä merkkiä pitkä ja uniikki, ja että, rivin tieto tallentuisi tietokantaan heti kun riviltä poistutaan. Lisäksi nimestä pitäisi trimmata tyhjät merkit edestä ja takaa (jonka nyt tekee vb).

Toki voisin hoitaa nuo pituus- ja uniikkitarkistukset itse koodissa, mutta kun sql serveri nyt tekee sen kuitenkin, niin haluan käyttää sitä. (Voihan olla että joskus haluan vaihtaa esim. pituusrajoitusta vaikka 5 merkkiin.)

Ongelma on nyt ainakin se, että jos nimi ei ole kelvollinen ja käyttäjä on klikannut rivillä jotain toista kenttää tai painanut enteriä, ja painaa sen jälkeen esciä, voi hän sirtyä toiselle riville vaikka nimi ei ole kelvollinen.

Joitain "toimivia" kötöstyksiä olen saanut aikaan mutta koodi on ollut sellaista sillisalaattia etten tajua siitä itsekään mitään jälkikäteen ;).

Mikä eteen? Kuinka tämä tehdään niinkuin oikeasti?

Grez [24.01.2017 13:07:25]

#

ari kood kirjoitti:

Toki voisin hoitaa nuo pituus- ja uniikkitarkistukset itse koodissa, mutta kun sql serveri nyt tekee sen kuitenkin, niin haluan käyttää sitä. (Voihan olla että joskus haluan vaihtaa esim. pituusrajoitusta vaikka 5 merkkiin.)

Ottamatta muuhun kantaa, mutta eihän sinun kannata koodissa tarkistaa "onko teksti pidempi kuin 4 merkkiä", vaan "onko teksti pidempi kuin tietokantaan määritelty maksimipituus".

groovyb [24.01.2017 13:24:13]

#

Grez, toki tapauskohtaisesti voidaan haluta validoida eri määrein, mitä kanta sallii. Jos samaa kenttää käytetään eri määrein, eri tarkoituksissa. Vaikka nyt sitten postinumerokenttä, jossa suomessa on eri määreet, kuin vaikka ulkomaalaisessa postinumerossa ja kantaan asetetaan maksimiksi suurimman mahdollisen postinumeron mukainen arvo.

Yleisesti tuosta ylläolevasta, mikäli annat kannan suorittaa validoinnin, saat takaisin vain transaktiovirheen. Eli kanta ei varsinaisesti "validoi" mitään, kanta palauttaa virheen. toki voit näyttää itse virhettä lomakkeellasi, mutta lähtökohtaisesti parempi tapa on käyttää erillistä luokkaa itse datalle, ja asettaa propertyille omat validointiattribuutit. Näin estät a) virheellisen tiedon tallentamisen yrityksen b) saat kenttäkohtaisesti tiedon epäonnistuneesta validoinnista. Mikäli otat virheen transaktiossa, palautuu virhe taulussa olevan sarakkeen mukaan ja käyttäjälle taatusti epäselvänä. Tämäkin tietysti on ok, jos käyttäjät ovat sen verran valveutuneita että tietävät mitä tarkoittaa vaikka palautunut virhe "Violation of UNIQUE KEY constraint 'UQ__osastot__AB6E61641273C1CD'. Cannot insert duplicate key in object 'dbo.osastot'."

Grez [24.01.2017 13:40:43]

#

groovyb kirjoitti:

Grez, toki tapauskohtaisesti voidaan haluta validoida eri määrein, mitä kanta sallii.

Tottakai, mutta kommenttini koski tuota lainaamaani alkuperäisen kirjoittajan pohdintaa että haluaisi pystyä muuttamaan määritystä nimenomaan kannan määrityksiä muuttamalla.

ari kood [25.01.2017 08:17:06]

#

Ok, onko ratkaisu siis tarkistaa kelvollisuus koodissa?

Haluaisin kuitenkin tietää, onko purkkaviritetty koodi ainoa tapa estää käyttäjää siirtymään toiselle riville, vai onko tähän olemassa jokin "oikea" keino?

groovyb [25.01.2017 09:46:30]

#

Tähän on ihan oikeakin keino. Datagridview:n tapauksessa, oikea tapa on hanskata validointi CellValidating -eventissä.

How to: Validate Data in the Windows Forms DataGridView Control

Linkin ohje on hyvin pelkistetty, mutta ajatus varmasti aukeaa tuota kautta.

ari kood [26.01.2017 20:07:08]

#

Kiitos vastauskesta Groovyb, mutta olen kyllä tuotakin jo yrittänyt, ja paljon muitakin vaihtoehtoja. Onko sillä edes väliä tässä tapauksessa validoidaanko solun tieto RowValidating- vai CellValidating-eventissä?

Ongelmani tulee CellValidating eventissä olemaan sama, eli käyttäjä voi siirtyä toiseen soluun esc näppäimen painamisen jälkeen vaikka solun tieto ei olisi validi.

Toki voisin ehkä jotenkin estää esc näppäimen käytön, mutta silloinhan se olisi se ei haluttu purkkaviritys. Ellei sitten juuri esc-näppäimen estäminen ole se "oikea keino".

Grez [26.01.2017 21:06:29]

#

Mikäs sen esc-näppäimen painamisen funktio oikeastaan on? Voisi kuvitella (en jaksa testata) että "en haluakaan tallentaa tätä riviä".

Mielestäni ei todellisuudessa ole, eikä pitäisikään olla mitään keinoa estää käyttäjää poistumasta jostain solusta ennen kuin siihen on syötetty "validi tieto". Viimeisenä oljenkortena käyttäjä voi vaikka poistua solusta sammuttamalla tietokoneen.

Itseäni ainakin ottaisi aika suunnattomasti päähän jos käyttöön tulisi ohjelma jolla johonkin soluun eksymällä saisi lukittua esim. koko koneen tai edes ko. sovelluksen.

ari kood [27.01.2017 09:01:25]

#

Grez kirjoitti:

Mikäs sen esc-näppäimen painamisen funktio oikeastaan on? ...

Hyvä huomio. Hauluaisinkin esc-näppäimen toimivan tuossa tehtävässä, mutta tässä tapauksessa olen virheellisesti alkanut syyttämään esc näppäintä ongelmastani joka oikeasti onkin nyt se, että;

Jos käyttäjä on kirjoittanut soluun duplikaatin, ja saanut siitä virheilmoituksen, pääse hän esc-näppäimen painamisen jälkeen siirtymään toiselle riville, ja saa nyt virheilmoituksen myös tästä solusta jos tekee siihen muutoksia, vaikka muutos olisi validi.

Grez [27.01.2017 11:03:38]

#

Usein ei ole hyvä käyttöliittymä, että käyttäjän kirjoittamat muutokset tallentuvat suoraan kantaan ilman erillistä "tallenna" painallusta, tai sitten olisi hyvä olla "undo" -toiminto.

Tuollaiset tiedot, jotka käyttäjä on syöttänyt, mutta joita ei ole vielä tallennettu, olisi hyvä korostaa esim. jollain värillä. Virheelliset vielä erityisemmin.

ari kood [27.01.2017 22:05:33]

#

Tässä tapauksessa se kuitenkin on hyvä ratkaisu.

groovyb [28.01.2017 12:24:15]

#

voithan toki validoinnin yhteydessä asettaa kaikkien rivien solut read only -tilaan, lukuunottamatta juuri muokattua. Näin muokattavaksi jäisi vain ko. rivi. Jos validointi menee läpi, poistat read only -tilat.

ari kood [29.01.2017 20:12:40]

#

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Me.Table1TableAdapter.Fill(Me.Testi1DataSet.Table1)
    DataGridViewTextBoxColumn2.MaxInputLength = Testi1DataSet.Table1.Columns("nimi").MaxLength
End Sub

Private Sub Table1DataGridView_RowValidating(sender As Object, e As DataGridViewCellCancelEventArgs) Handles Table1DataGridView.RowValidating
    Dim dgv As DataGridView = sender
    Dim row As DataGridViewRow = dgv.CurrentRow
    Dim cell As DataGridViewCell = row.Cells(e.ColumnIndex)


    If dgv.IsCurrentRowDirty Or row.ErrorText <> "" Then
        Try
            row.ErrorText = ""

            cell.Value = Trim(cell.Value)

            If cell.Value = "" Then
                Throw New Exception
            End If

            Me.Table1BindingSource.EndEdit()
            Me.TableAdapterManager.UpdateAll(Me.Testi1DataSet)

        Catch ex As Exception
            row.ErrorText = ex.Message
        End Try
    End If


    If row.ErrorText <> "" Then
        e.Cancel = True
    End If

End Sub

Vihdoin sain aikaan tuollaisen. Näyttäisi näin äkkiseltään toimivan kuten halusinkin. Maksimipituus rajoitettu kuten Grez tuossa aiemmin vinkkasi. Virheilmoitukset tosin pitää vielä säätää käyttäjäystävällisemmäksi, mutta se ei ole ongelma.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta