|
-
19-12-2006, 23:52
|
|
Αυτό δεν θα το συνιστούσα σε καμμία περίπτωση. Η αλλαγή των regional settings δεν είναι καλύτερη λύση από το να προσπαθείς να "καρφώσεις" την τελεία σαν υποδιαστολή. Είναι ακριβώς αυτό που εννοούσα να "διορθώσει" κανείς τον τρόπο λειτουργίας του .ΝΕΤ. Θα πρέπει να ελέγχεις συνέχεια ότι χρησιμοποιείς το σωστό locale και δεν έχει ξεφύγει κατά λάθος το ένα ή το άλλο locale. Εξάλλου, ο τελικός χρήστης μπορεί να χρησιμοποιήσει οποιοδήποτε locale θέλει. Όσο δεν πειράζεις το locale από τον κώδικα, η επιλογή του χρήστη δεν σε επηρεάζει. Μόλις αρχίσεις να τα πειράζεις, θα πρέπει να κάνεις συνεχώς μετατροπές από το ένα locale στο άλλο.
Στην περίπτωση εδώ, πέρα από την περίπτωση το PPrice να είναι string, μπορεί τα regional settings να είναι ελληνικά και ο χρήστης να δίνει "3.14" σε κάποιο textbox. Αυτό βάση των ελληνικών regional settings ΕΙΝΑΙ 314. Αν γράψει κανείς Convert.ToDecimal("3.14") και έχει ελληνικά regional settings, θα πάρει πίσω 314. Το ίδιο θα συμβεί αν έχει αμερικάνικα settings και γράψει Convert.ToDecimal("3,14"). Αλλάζοντας με κώδικα τα regional settings από το ένα locale στο άλλο, το μόνο που πετυχαίνει κανείς είναι να αποτύχει η μία ή η άλλη μορφή του 3.14.
Το πρόβλημα πλέον είναι διαφορετικό. Δεν είναι πλέον το πως γίνεται η μετατροπή από string σε decimal, αλλά πως εξασφαλίζουμε ότι ο χρήστης θα δώσει τη σωστή υποδιαστολή, ή τί κάνουμε αν δώσει λάθος υποδιαστολή. Εδώ τώρα υπάρχουν διάφορες επιλογές, με τα υπέρ και τα κατά τους. Μία λύση, είναι να χρησιμοποιηθεί ένα Masked Text Box, αντί για απλό text box, έτσι ώστε να μην επιτρέπεται ο χρήστης να δώσει λάθος κείμενο. Δυστυχώς, το Masked Text Box είναι λίγο δύσχρηστο. Άλλη λύση είναι να επιτρέπεται μόνο η εισαγωγή υποδιαστολής και όχι του διαχωριστικού χιλιάδων. Αυτό μπορεί να γίνει στο KeyDown του Textbox. Αυτή η λύση είναι καλή αν ξέρουμε ότι θα εισαχθούν μόνο μικρά νούμερα. Αν έχουμε εκατοντάδες χιλιάδες, ο χρήστης σίγουρα θα θέλει να βάλει και διαχωριστικά. Μία επιπλέον λύση, λίγο πιο περίπλοκη, είναι να θεωρούμε ότι η υποδιαστολή είναι το τελευταίο "." ή "," από δεξιά. Μόνο που έτσι μπλέκουμε πάλι με τις χιλιάδες. Ίσως, η καλύτερη λύση θα ήταν να επιτρέπουμε την εισαγωγή μόνο της υποδιαστολής, αλλά να φορμάρουμε τον αριθμό έτσι ώστε να φαίνονται οι χιλιάδες.
Παναγιώτης Καναβός, Freelancer Twitter: http://www.twitter.com/pkanavos
|
|
-
20-12-2006, 09:57
|
|
Παναγιώτη η PPrice έχει οριστεί σαν decimal
επίσης στην access το αντίστοιχο πεδίο είναι decimal
Ο Μ Ω Σ
το πρόβλημά μου είναι ότι στην vb το μετατρέπω στο κανονικό φορμά ενός δεκαδικού(0.00)
ΑΛΛΑ η access
σύμφωνα με τα settings το παίρνει σαν ακέραιο!!! (000)
τι γίνεται με τα settings και την access???
όταν έλεγα για region settings δεν εννοούσα αλλαγή αλλά
ανάλογα με τη ρύθμιση να έστελνα τον αντίστοιχο τύπο δεκαδικού δηλ είτε "0,00" είτε
"0.00"
όμως δεν υπάρχει κάτι πιο σωστό από αυτό...?
|
|
-
20-12-2006, 11:39
|
|
Ε, λοιπόν, φαίνεται ότι το πρόβλημα είναι της Access, και δεν έχει να κάνει με τα regional settings της εφαρμογής!
Δοκίμασα κι εγώ να φτιάξω ένα command που εισάγει decimals, και διαπίστωσα ότι παρότι έδινα ένα decimal variable με τιμή 3,14, στη βάση κατέληγε 314! Ψάχνοντας βρήκα το PRB: Incorrect NUMERIC and DECIMAL conversions with non-English locales το οποίο εξηγεί ότι το πρόβλημα βρίσκεται σε ένα function της Oleaut32.dll και έχει διορθωθεί με το Windows 2000 Service Pack 2. Μόνο που εγώ έχω Windows XP!
Το άρθρο περιέχει μία κάπως υποφερτή λύση, να καλέσει κανείς από τον κώδικα του την SetVarConversionLocaleSetting(1) για να αναγκάσει την oleaut32.dll να χρησιμοποιήσει το locale του thread. Yuck!
Παναγιώτης Καναβός, Freelancer Twitter: http://www.twitter.com/pkanavos
|
|
-
20-12-2006, 13:56
|
|
χμμμ
αυτό ακριβώς εννοούσα
σε ευχαριστώ πολύ που ασχολήθηκες Παναγιώτη...
κι εγώ σε XP Pro SP2 δουλεύω...
θα κάτσω να διαβάσω το άρθρο αλλά δε φαντάζομαι να με καλύψει...
|
|
-
20-12-2006, 18:23
|
-
20-12-2006, 19:09
|
|
Pak wrote: | pkanavos wrote: |
Στην περίπτωση εδώ, πέρα από την περίπτωση το PPrice να είναι string, μπορεί τα regional settings να είναι ελληνικά και ο χρήστης να δίνει "3.14" σε κάποιο textbox. Αυτό βάση των ελληνικών regional settings ΕΙΝΑΙ 314. Αν γράψει κανείς Convert.ToDecimal("3.14") και έχει ελληνικά regional settings, θα πάρει πίσω 314. Το ίδιο θα συμβεί αν έχει αμερικάνικα settings και γράψει Convert.ToDecimal("3,14"). Αλλάζοντας με κώδικα τα regional settings από το ένα locale στο άλλο, το μόνο που πετυχαίνει κανείς είναι να αποτύχει η μία ή η άλλη μορφή του 3.14.
|
|
Δυστυχώς αν και πιο άπειρος θα διαφωνήσω γιατί αυτό που αναφέρεις δεν είναι λογικο και επειδή το πρόβλημα παρουσιάζεται συχνά σε εφαρμογές θα εξηγήσω. Φυσικά και δεν θα αλλάξεις καρφωτά τα Regional Settings... Μπορείς να κάνεις ελέγχους αν σε ικανοποιούν τα settings του user και αν όχι, τα αλλάζεις κάνεις τη δουλειά σου, και μετά επαναφέρεις τα αρχικά. Άρα η εργασία που θέλεις να εκτελέσεις εκτελείται υπό τις συνθήκες που εσύ ορίζεις και όχι από τη διάθεση του χρήστη. Και επειδή έχω δουλέψει σε εφαρμογές τιμολόγησης όπου εισάγονται τιμές από textbox γνωρίζω τι βάσανο είναι για την υποστήριξη του πελάτη τα προβλήματα με τα regional settings...
|
|
Πως ακριβώς αλλάζεις τα Regional Settings; Μπορείς να δώσεις λίγο κώδικα; Η τακτική να τα αλλάζεις δεν είναι σωστή, γιατί δεν τα αλλάζεις μόνο για την εφαρμογή σου, αλλά για όλο το σύστημα, στο οποίο εκτελούνται πολλά άλλα processes εκτός από τα δικά σου. Αν θέλεις δώσε ένα παράδειγμα για το οποίο μπορεί να θέλεις να τα αλλάξεις και θα δεις ότι μάλλον μπορεί να γίνει και διαφορετικά. π.χ. αν θέλεις να μετατρέψεις έναν αριθμό σε string χρησιμοποιώντας το # σαν υποδιαστολή τότε κάνεις το ακόλουθο (και δεν αλλάζεις την υποδιαστολή στα regional options) : Dim myNumber as Decimal = 4.234 Dim provider = new System.Globalization.NumberFormatInfo() provider.NumberDecimalSeparator = "#" Dim myString = myNumber.ToString(provider)
Οι απαντήσεις παρέχονται για συγκεκριμένες ερωτήσεις και χωρίς καμιά εγγύηση. Διαβάστε επίσης τους όρους χρήσης.
|
|
-
20-12-2006, 22:22
|
|
Προφανώς ο Pak εννοεί να αλλάξει κανείς το CultureInfo του Thread. Αλλά όπως ήδη βρήκαμε, δεν είναι εκεί το πρόβλημα. Ίσα-ίσα, αν το δοκίμαζε αυτό ο Efthimis, δεν υπήρχε περίπτωση να βρει ποιό είναι το πραγματικό πρόβλημα και τη λύση του. Όσο για το "σε ικανοποιούν τα setting του user", όλο το πρόβλημα δημιουργείται γιατί το θέμα είναι να ικανοποιηθεί ο χρήστης, όχι να αναγκαστεί να κάνει ότι ζητάει η εφαρμογή. Τί θα του πεις, "γύρνα σε αγγλικά γιατί αυτό υποστηρίζει η εφαρμογή"? "Μήν χρησιμοποιείς το κόμμα" ή "Μή χρησιμοποιείς την τελεία"? Εξάλλου το πρόβλημα μας εδώ δεν είναι η μετατροπή από string σε decimal, αλλά το ότι ο OLEDB driver κάνει μερικές μυστήριες μετατροπές στα ίδια τα decimals. Στην περίπτωση μας, θα πρέπει αντί να χρησιμοποιείς parameterized query ή stored procedures, να χρησιμοποιήσεις χύμα SQL για να μπορέσεις να δώσεις το κατάλληλο string αντί για decimal.
Και καλά, πες ότι "διόρθωσες" το πρόβλημα αλλάζοντας το Thread.CurrentCulture, ή ακόμα καλύτερα, χρησιμοποίησες τη μορφή της Parse η οποία δέχεται συγκεκριμένο CultureInfo. Τί θα γίνει αν κάποια στιγμή ο χρήστης περάσει σε SQL Server, ή εγκαταστήσει ένα Service Pack που διορθώνει το πρόβλημα? Τότε το "fix" θα σκάσει και θα πρέπει να γράψεις ξανά-μανά κι άλλο κώδικα για να "διορθώσεις" τη "διόρθωση", ή να αφαιρέσεις όλες τις "διορθώσεις".
Παναγιώτης Καναβός, Freelancer Twitter: http://www.twitter.com/pkanavos
|
|
-
20-12-2006, 22:42
|
-
Pak
-
-

-
Μέλος από τις 24-11-2006
-
Κύπρος, Λεμεσός
-
Δημοσιεύσεις 432
-
-
|
papadi wrote: | Πως ακριβώς αλλάζεις τα Regional Settings; Μπορείς να δώσεις λίγο κώδικα; Η τακτική να τα αλλάζεις δεν είναι σωστή, γιατί δεν τα αλλάζεις μόνο για την εφαρμογή σου, αλλά για όλο το σύστημα, στο οποίο εκτελούνται πολλά άλλα processes εκτός από τα δικά σου. Αν θέλεις δώσε ένα παράδειγμα για το οποίο μπορεί να θέλεις να τα αλλάξεις και θα δεις ότι μάλλον μπορεί να γίνει και διαφορετικά. π.χ. αν θέλεις να μετατρέψεις έναν αριθμό σε string χρησιμοποιώντας το # σαν υποδιαστολή τότε κάνεις το ακόλουθο (και δεν αλλάζεις την υποδιαστολή στα regional options) : Dim myNumber as Decimal = 4.234 Dim provider = new System.Globalization.NumberFormatInfo() provider.NumberDecimalSeparator = "#" Dim myString = myNumber.ToString(provider)
|
|
ΛΑΘΟΣ!!! ο εξής κώδικας αλλάζει το cultureinfo σε επίπεδο application
System.Threading. Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
ενοοώ το εξής
string OriginalInfo = System.Threading. Thread.CurrentThread.CurrentCulture.ToString();
if(System.Threading.Thread.CurrentThread.CurrentUICulture.ToString()!="el-GR")
{
System.Threading. Thread.CurrentThread.CurrentUICulture = new CultureInfo("el-GR");
//DO YOUR JOB...
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(OriginalInfo);
}
else
{
//DO YOUR JOB...
}
Έτσι τήν ώρα της εκτέλεσης της κρίσιμης λειτουργίας είσαι βέβαιος ότι το cultureInfo είναι αυτό το οποίο έχεις υπ όψην...
Coding at Mediterranean Acoustics
|
|
-
20-12-2006, 22:47
|
-
20-12-2006, 22:48
|
-
21-12-2006, 01:08
|
|
Τελικά το βρήκα! Το πρόβλημα εμφανίζεται μόνο αν ο τύπος της παραμέτρου είναι OleDbType.Decimal!
Αν η παράμετρος οριστεί ως OleDbType.Currency ή OleDbType.Double, όλα δουλεύουν ρολόι. Η συμπεριφορά αυτή δεν επηρεάζεται από το culture του thread ούτε από την κλήση της SetVarConversionLocaleSetting, αλλά από το locale του συστήματος, το οποίο χρειάζεται reboot για να αλλάξει. Μάλλον πέσαμε σε bugάκι του driver, ή του oleaut32.dll! Δυστυχώς, το πρόβλημα αυτό επηρεάζει και τους data adapters που χρησιμοποιούμε. Αν χρησιμοποιούμε datasets με Access, θα πρέπει να αλλάξουμε τις παραμέτρους τύπου Decimal σε Currency στους data adapters για να μην έχουμε το ίδιο πρόβλημα.
Παρακάτω είναι ο κώδικας που χρησιμοποίησα για τις δοκιμές:
Imports System.Data Imports System.Data.OleDb Imports System.Threading Imports System.Globalization
Public Class Form1 Declare Auto Function SetVarConversionLocaleSetting Lib "oleaut32.dll" (ByVal flags As UInt32) As UInt32
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load '*** Uncomment to see that the thread's culture doesn't affect the results 'SetVarConversionLocaleSetting(1) 'Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-US") 'Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US")
Using con As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=c:\db1.mdb") con.Open() Dim deleteCmd As New OleDbCommand("Delete from Books ") deleteCmd.Connection = con deleteCmd.ExecuteNonQuery()
Dim insertCmd As New OleDbCommand("Insert Into Books (Title,Price) VALUES(@title,@price)") insertCmd.Parameters.Add("@title", OleDbType.Char).Value = "Zonk1" insertCmd.Parameters.Add("@price", OleDbType.Currency).Value = 3.14 '*** Uncomment to reproduce error 'insertCmd.Parameters.Add("@price", OleDbType.Decimal).Value = 3.14 insertCmd.Connection = con insertCmd.ExecuteNonQuery()
Dim selectCmd As New OleDbCommand("select * from Books") selectCmd.Connection = con Using reader As OleDbDataReader = selectCmd.ExecuteReader While reader.Read() Console.WriteLine("{0} {1}", reader(0).ToString(), reader(1).ToString()) End While End Using End Using
End Sub End Class
Pak, μπορείς να ξεκινήσεις νέο topic αν θέλεις. Όπως όμως βλέπεις, το πρόβλημα του Efthimis δεν είχε να κάνει με το αν πρέπει ή δεν πρέπει να αλλάζουμε το locale της εφαρμογής.
Παναγιώτης Καναβός, Freelancer Twitter: http://www.twitter.com/pkanavos
|
|
-
21-12-2006, 09:52
|
|
Να συμπληρώσω ότι το ίδιο ακριβώς πρόβλημα με τους decimals παρουσιάζεται σε .ΝΕΤ 1.1 (τουλάχιστον) με τον Odbc provider της Oracle.
Νατάσα Μανουσοπούλου
|
|
-
21-12-2006, 10:01
|
|
Pak wrote: | papadi wrote: | Πως ακριβώς αλλάζεις τα Regional Settings; Μπορείς να δώσεις λίγο κώδικα; Η τακτική να τα αλλάζεις δεν είναι σωστή, γιατί δεν τα αλλάζεις μόνο για την εφαρμογή σου, αλλά για όλο το σύστημα, στο οποίο εκτελούνται πολλά άλλα processes εκτός από τα δικά σου. Αν θέλεις δώσε ένα παράδειγμα για το οποίο μπορεί να θέλεις να τα αλλάξεις και θα δεις ότι μάλλον μπορεί να γίνει και διαφορετικά. π.χ. αν θέλεις να μετατρέψεις έναν αριθμό σε string χρησιμοποιώντας το # σαν υποδιαστολή τότε κάνεις το ακόλουθο (και δεν αλλάζεις την υποδιαστολή στα regional options) : Dim myNumber as Decimal = 4.234 Dim provider = new System.Globalization.NumberFormatInfo() provider.NumberDecimalSeparator = "#" Dim myString = myNumber.ToString(provider)
|
|
ΛΑΘΟΣ!!! |
|
Που ακριβώς είναι το λάθος;
Οι απαντήσεις παρέχονται για συγκεκριμένες ερωτήσεις και χωρίς καμιά εγγύηση. Διαβάστε επίσης τους όρους χρήσης.
|
|
-
21-12-2006, 10:13
|
|
Είναι πολύ σημαντικό, σε αυτή τη δουλειά μου κάνουμε, να είμαστε όσο το δυνατόν πιο ακριβής στις εκφράσεις μας. Γι αυτό και σου ζήτησα να δώσεις λίγο κώδικα για να καταλάβω τι εννοείς λέγοντας "αλλαγή των regional options για να γίνει η δουλειά και μετά επαναφορά". Ο κώδικας που έγραψες δεν αλλάζει τα regional options αλλά το cultureinfo του currentthread. Δεν είναι το ίδιο.
Οι απαντήσεις παρέχονται για συγκεκριμένες ερωτήσεις και χωρίς καμιά εγγύηση. Διαβάστε επίσης τους όρους χρήσης.
|
|
-
21-12-2006, 11:15
|
Σελίδα 2 από 3 (38 εγγραφές)
2
|
|
|