Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια
σε

 

Αρχική σελίδα Ιστολόγια Συζητήσεις Εκθέσεις Φωτογραφιών Αρχειοθήκες

Binding και Converters

Îåêßíçóå áðü ôï ìÝëïò Geysser. Τελευταία δημοσίευση από το μέλος KelMan στις 12-04-2011, 11:01. Υπάρχουν 10 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  10-04-2011, 22:33 65109

    Binding και Converters

    Δεν ξέρω κατά πόσο ηλίθια μπορεί να χαρακτηριστεί η απορία μου αλλά το σενάριο έχει ως εξής:
    Κάνω binding της value μιας scrollbar στην text ενός textbox.Όλα καλά και άγια αλλά η value είναι double και εγώ θέλω integer. Η λύση προφανώς είναι να βάλω έναν converter.Αλλά  ποιόν; Πρέπει να γράψω δικόν μου ή υπάρχει κάποιος ήδη έτοιμος;
    Ο κωδικας είναι ο εξής:

                <TextBox Name="AlphaText" Width="40"
                     TextAlignment="Right"
                     HorizontalAlignment="Right" VerticalAlignment="Bottom"
                     Margin="0,0,4,64">
                <TextBox.Text>
                    <Binding>
                        <Binding.Path>Value</Binding.Path>
                        <Binding.ElementName>AlphaBar</Binding.ElementName>
                        <Binding.UpdateSourceTrigger>PropertyChanged</Binding.UpdateSourceTrigger>
                    </Binding>
                </TextBox.Text>
            </TextBox>

    Κάθε βοήθεια ή ιδέα είναι ευπρόσδεκτη.
  •  11-04-2011, 09:50 65110 σε απάντηση της 65109

    Απ: Binding και Converters

    Καταρχήν, χρεάζεται να ορίσεις τον converter:

    public class StringConverter : IValueConverter
    {
    	public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    	{
    		return value == null ? null : value.ToString();
    	}
    
             public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    	{
    		throw new NotImplementedException();
    	}
    }

    Κατόπιν, πας στη φόρμα σου ή στο user control και το δηλώνεις ως resource:

    <UserControl ...
    	     xmlns:local="clr-namespace:[your assembly here]"
                 ...>
    <UserControl.Resources>
    	...
    	<local:StringConverter x:Key="StringConverter" />
    </UserControl.Resources>

    Και πλέον μπορείς να το χρησιμοποιήσεις κατά το binding:

    <TextBox Name="AlphaText" Width="40"
             TextAlignment="Right"  
             HorizontalAlignment="Right" VerticalAlignment="Bottom"
             Margin="0,0,4,64"
    	Text="{Binding Path=Value, ElementName=AlphaBar, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource StringConverter}}">

     

     


    Vir prudens non contra ventum mingit
  •  11-04-2011, 12:29 65116 σε απάντηση της 65110

    Απ: Binding και Converters

    Thanks! Κερνάω ουζάκι!
  •  11-04-2011, 14:45 65118 σε απάντηση της 65116

    Απ: Binding και Converters

    Δεν νομίζω ότι χρειάζεται καν ο converter, εξάλλου μπορείς να κάνεις το binding πολύ ευκολότερα. Καταρχήν, δεν υπάρχει λόγος να ορίσεις ξεχωριστά triggers ή να δώσεις ένα-ένα τα properties. Ο απλούστερος τρόπος, και αυτός που υποστηρίζει το Visual Studio, είναι να χρησιμοποιήσεις ένα binding expression. Επιπλέον, στο binding expression μπορείς να δώσεις το string format που θα χρησιμοποιηθεί. Αν το σκεφτείς λίγο, δεν έχεις μετατροπή από double σε int αλλά από double σε string. Το Text property δέχεται μόνο string τιμές, ή τις τιμές που προέρχονται από την ToString() της τιμής που δίνεις. 

    Αυτό που ζητάς μπορεί να γίνει απλούστατα με το παρακάτω XAML:

            <ScrollBar Height="249" HorizontalAlignment="Left" Margin="455,27,0,0" Name="scrollBar1" VerticalAlignment="Top" Width="21" Maximum="100" Value="50" />
            <TextBox Height="32" HorizontalAlignment="Left" Margin="34,40,0,0" Name="textBox1" VerticalAlignment="Top" Width="192" Text="{Binding ElementName=scrollBar1, Path=Value, StringFormat=\{0:F0\}}" />
    Το παραπάνω binding το έφτιαξα με το designer του Visual Studio, δεν χρειάστηκε καν να προσθέσω κάτι με το χέρι.

    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  11-04-2011, 18:04 65123 σε απάντηση της 65110

    Απ: Binding και Converters

    KelMan:

    Καταρχήν, χρεάζεται να ορίσεις τον converter:

    ...
    
    	public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    	{
    		return value == null ? null : value.ToString();
    	}
    
     

    Μήπως χάνω κάτι? Η default συμπεριφορά δεν είναι η κλήση της ToString() ? Το αποτέλεσμα δεν θα είναι πάλι αριθμός με δεκαδικά αντί για ακέραιο? Η μόνη διαφορά που βλέπω είναι ότι η default συμπεριφορά χρησιμοποιεί το Invariant Culture ενώ η απευθείας κλήση της ToString() χρησιμοποιεί το locale του χρήστη. Ενώ πχ. το απλό bind θα γυρίσει "46.75" με τον converter θα γυρίσει "46,75" για ελληνικό locale

    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  11-04-2011, 18:55 65124 σε απάντηση της 65123

    Απ: Binding και Converters

    Όχι, δεν είναι κάτι άλλο... Απλά έδωσα την λύση με τον converter γιατί υπέθεσα ότι υπάρχει γενικότερο ενδιαφέρον από τον Geysser να μάθει πώς δουλεύουν. Ως προς τον trigger, σαφώς δεν είναι απαραίτητος αλλά και πάλι υπέθεσα ότι τον χρειάζεται για να περνάει άμεσα την τιμή πίσω στο ScrollBar και να μην περιμένει το lost focus, οπότε το άφησα as is.

     


    Vir prudens non contra ventum mingit
  •  12-04-2011, 07:35 65133 σε απάντηση της 65124

    Απ: Binding και Converters

    Ειναι γεγονός ότι ο τρόπος του KelMan δουλευει (χρειάστηκε λίγη δουλίτσα παραπάνω γιατί γράφω σε VB και όχι σε C#).Η λύση του Παναγιώτη απαιτεί λιγότερο κώδικα αλλά η λύση του KelMan αντιμετωπίζει το ζήτημα των converters το οποίο σίγουρα θα αντιμετωπίσω στο μέλλον. Και ο KelMan έχει δίκιο: χρειάζομαι τον trigger.Και οι δυο με βοηθήσατε πολύ οπότε...δύο ουζάκια.
  •  12-04-2011, 08:22 65135 σε απάντηση της 65124

    Απ: Binding και Converters

    Μα δεν χάνεται το focus από το scrollbar. Εξάλλου, η default συμπεριφορά του binding είναι να αντιδρά στο PropertyChanged event. Με άλλα λόγια, το trigger είναι πλεονασμός γιατί ήδη έτσι συμπεριφέρεται το binding.

    Οι converters χρειάζονται για πιο σοβαρά conversions όπως π.χ. από status τιμή σε χρώμα όπως δείχνει αυτό το tutorial, από string σε Color όπως δείχνει το documentation για τους converters στο MSDN, ή από string σε Visibility όπως δείχνει αυτό το tutorial για data binding

    Geysser, αντί να ψάχνεις στα τυφλά ρίξε μία ματιά στο documentation και τα tutorials για να καταλάβεις γενικά πως δουλεύει το data binding. Το data binding είναι πάρα πολύ σημαντικό στο WPF και είναι απαραίτητο (πως λέμε 250%) να το καταλάβεις για να μπορέσεις να προχωρήσεις και να καταλάβεις πως δομούνται εφαρμογές σε WPF και πως δουλεύουν patterns όπως το MVVM ή βιβλιοθήκες όπως το Caliburn.  Μπορείς να βρεις πολλά χρήσιμα tutorials και videos στο WindowsClient.net. Πολλά από αυτά προέρχονται από τον Pete Brown ο οποίος έχει γράψει και το καταπληκτικό Silverlight 4 in Action. Μπορεί να λέει Silverlight το βιβλίο αλλά όσα γράφει ισχύουν και για WPF. Το βιβλίο αυτό έχει πάρα πολύ καλή εισαγωγή στο data binding και μία από τις καλύτερες εισαγωγές στο MVVM που έχω διαβάσει. Αξίζει να παρακολουθείς το blog του, στο http://10rem.net/

    Τέλος, ρίξε και μία ματιά σε αυτό το project στο Codeplex. Περιέχει μερικούς πολύ ενδιαφέροντες converters, όπως ο FormatConverter που χρησιμοποιουν πολλές παραμέτρους ταυτόχρονα. Είναι ένα παράδειγμα του τί μπορεί να κάνει κάποιος όταν χρησιμοποιεί σωστά τους converters.



    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  12-04-2011, 09:44 65139 σε απάντηση της 65135

    Απ: Binding και Converters

    Παναγιώτη έχεις πάρει φόρα. Ο trigger είναι είπαμε για να περάσει η τιμή από το textbox πίσω στο scrollbar. Σε κάποια controls όπως το textbox που είναι πιο aggressive στο πώς χειρίζονται το input του χρήστη, το default στο UpdateSourceTrigger δεν είναι το PropertyChanged αλλά το LostFocus. Άρα λοιπόν, αν θέλουμε να γράφουμε στο textbox και να βλέπουμε το scrollbar να αλλάζει, υποχρεωτικά θα πρέπει να πούμε UpdateSourceTrigger=PropertyChanged. Το ίδιο ισχύει και για το Mode (OneWay, TwoWay, OneWayToSource, OneTime).

    Γενικά, όσο περίεργο κι αν ακούγεται, οι default τιμές για το UpdateSourceTrigger και το Mode δεν είναι και τόσο default αλλά αλλάζουν ανάλογα με το property. Και αυτό γιατί δεν είναι απλά properties αλλά depedency properties τα οποία όταν ορίζονται, μπορεί να καθοριστεί η "default" συμπεριφορά ανάλογα με την περίσταση. Αυτό μπορεί από την μία να δημιοργεί πονοκέφαλο αλλά από την άλλη, σε σενάρια όπως αυτό με το textbox, αποφεύγεται το να γίνεται συνεχώς update η τιμή. Γι αυτό εγώ πάντοτε ορίζω explicitly αυτά τα values για να μην ψάχνομαι με το τι είναι default και τι όχι.

     


    Vir prudens non contra ventum mingit
  •  12-04-2011, 10:25 65141 σε απάντηση της 65139

    Απ: Binding και Converters

    Τότε πάλι δεν παίζει ο converter γιατί η ConvertBack ρίχνει exception αν αλλάξεις την τιμή του textbox, κάτι το οποίο είμαι απολύτως σίγουρος ότι κανένας δεν θέλει. Θα πρέπει να υλοποιηθεί κάτι σαν το παρακάτω

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
                double v;
                if (double.TryParse((string)value, out v))
                    return v;
                return null;
    }


    Ακόμα και στην περίπτωση που λες, να θέλει κάποιος να αλλάζει η τιμή του Scrollbar αλλάζοντας την τιμή του textbox, o converter είναι πάλι περιττός καθώς το binding δουλεύει άνετα χωρίς αυτόν. Μπορείς απλά να αλλάξεις το UpdateSourceTrigger. Η συμπεριφορά όμως θα είναι λίγο περίεργη καθώς γράφοντας "80" το αποτέλεσμα θα είναι να πεταχτεί το scrollbar πρώτα στο 8 και μετά στο 80. 

    Τέλος, προσωπικά προτιμώ να χρησιμοποιώ τη default συμπεριφορά ενός control εκτός και αν χρειάζεται κάτι διαφορετικό. Μάλλον πιο περίπλοκο κάνεις το XAML έτσι παρά κερδίζεις κάτι.  Συνήθως ο δημιουργός του control κάτι έχει υπόψη του όταν ορίζει το ένα ή το άλλο event.

    Άσε που όταν χρησιμοποιείς  κάποιο framework το οποίο διευκολύνει το binding, όπως το Caliburn, αυτά τα χειρίζεται το framework και όχι εσύ, ή τα ορίζεις σε κάποιο configuration ή bootstrapper αντί για κάθε μία περίπτωση που χρησιμοποιείς το κάθε control.

    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  12-04-2011, 11:01 65142 σε απάντηση της 65141

    Απ: Binding και Converters

    Ρε Παναγιώτη πρέπει να το τραβήξεις από τα μαλιά ε? Ναι, ρίχνει exception θα το δει ο άνθρωπος, θα το διορθώσει. To UpdateSourceTrigger=PropertyChanged, φυσικά και έχει περίεργη συμπεριφορά, γι αυτόν τον λόγο και οι τύποι που το έφτιαξαν έκαναν default το LostFocus. Μην τα μπερδεύεις όλα μαζί. Ένα πράγμα το UpdateSourceTrigger, ένα άλλο πράγμα ο converter. Είπα ποτέ ότι το ένα χρειάζεται το άλλο; Εσύ είπες ότι ο trigger είναι περιττός και σου απάντησα ότι δεν είναι εφόσον θες το συγκεκριμένο functionality.

    Από εκεί και πέρα, το θέμα με τις διαφορετικές default τιμές μπερδεύει πολύ κόσμο και θα δεις ότι έχει αρκετές ερωτήσεις στα forums. Προσωπικά, προτιμώ να έχω να θυμάμαι κάτι άλλο πάρα να θυμάμαι τις default τιμές του binding *ανά control και property*. Άσε που βάζω στοίχημα ότι μπορείς να θυμάσαι μόνο αυτά που χρησιμοποιείς πολύ συχνά οπότε τελικά καταλήγεις να κοιτάς στο documentation. Εξάλλου, πόόόσο περίπλοκη γίνεται η XAML; Εγώ δεν τη βλέπω ως περίοπλοκη, ίσα-ίσα, όταν κάνω review, εντοπίζω αμέσως αυτό που θέλω. Τώρα, ως προς το framework, δεν χρησιμοποιούν όλοι Caliburn, αν υποθέσουμε ότι κάποιος χρησιμοποιεί framework. Στα περισσότερα frameworks έχεις ευθύνη να φτιάξεις τον XAML κώδικα, οπότε δεν γλυτώνεις κάτι.

    [Edit]

    Δεν έχω παίξει με Caliburn αλλά ρίχνοντας μια ματιά στο documentation δεν είδα πώς το framework ορίζει τα bindings στα Views. Μπορείς να το αναλύσεις λίγο;

     


    Vir prudens non contra ventum mingit
Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems