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

 

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

Object binding σε Win Forms (Vs 2003)

Îåêßíçóå áðü ôï ìÝëïò axaros. Τελευταία δημοσίευση από το μέλος SValsamis στις 16-06-2006, 13:23. Υπάρχουν 20 απαντήσεις.
Σελίδα 1 από 2 (21 εγγραφές)   1 2 >
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  22-05-2006, 14:54 13103

    Object binding σε Win Forms (Vs 2003)

    Γεια σας και χαρά σας !!!
    Μία ερώτηση : μπορώ να έχω τον έλεγχο σε ποιο event ενημερώνεται το binding;

    Πως μπορώ να αποφύγω το σκόπελο του (TextBox) Leave event για το πχ TextChanged ;

     

     


    Πάνος Αβραμίδης
  •  22-05-2006, 14:59 13105 σε απάντηση της 13103

    Απ: Object binding σε Win Forms (Vs 2003)

    Μπορείς να το εξηγήσεις λίγο καλύτερα;
    Vir prudens non contra ventum mingit
  •  22-05-2006, 15:08 13106 σε απάντηση της 13103

    Απ: Object binding σε Win Forms (Vs 2003)

    Έχω π.χ. το object Customer με τρία properties : Name, OriginalName και IsDirty.
    IsDirty = True αν Name <> του OriginalName

    Προσθέτω ένα binding σε κάποιο Text Box σε μία φόρμα.

    txtName.Databindings.Add("Text",MyOb,"Name")

    Θα ήθελα να κάνω Enable/Disable κάποιο button πιάνωντας το TextChanged event του control.
    Τώρα το binding ενημερώνεται μόνο στο Leave event ...

    Συγχωρέστε την άγνοια μου αν λέω κοτσάνες ...

    Γενικότερα πως δουλεύει ο binding μηχανισμός ;


    Πάνος Αβραμίδης
  •  23-05-2006, 00:57 13127 σε απάντηση της 13103

    Απ: Object binding σε Win Forms (Vs 2003)

    Άνοιξες μεγάλο θέμα...

    Λοιπόν, ας υποθέσουμε ότι ξεκινάς με αυτήν την κλάση:



    Public Class Customer1

        Private mName As String
        Private mOriginalName As String
        Private mDirty As Boolean

        Public Sub New()
            mName = ""
            mOriginalName = ""
            mDirty = False
        End Sub

        Public Property Name() As String
            Get
                Return mName
            End Get
            Set(ByVal Value As String)
                mName = Value
            End Set
        End Property

        Public Property OriginalName() As String
            Get
                Return mOriginalName
            End Get
            Set(ByVal Value As String)
                mOriginalName = Value
            End Set
        End Property

        Public ReadOnly Property Dirty() As Boolean
            Get
                Return mDirty
            End Get
        End Property

    End Class

    Υποθέτω ότι θα έχεις βάλει και λίγο κώδικα για να αλλάζεις το OriginalName ανάλογα, ωστόσο προς το παρόν αυτό δεν μας απασχολεί.

    Όταν τρέχεις το



    Dim b As Binding = TextBox1.DataBindings.Add("Text", c, "Name")

    συνδέεις το text property του TextBox1 με το Name property του c object (instance του Customer). Οι αλλαγές που κάνεις στο textbox περνάνε "μαγικά" στο αντίστοιχο property, ωστόσο αυτό συμβαίνει πριν το validate event, δηλαδή στην περίπτωση του textbox, μετά το lost focus του. Άρα το θέμα είναι πως θα προκαλέσουμε το update του datasource νωρίτερα. Και φυσικά, τη λύση έρχονται να δώσουν (τα-νταααααν!!!) τα interfaces. Πριν όμως φτάσουμε εκεί, θα πρέπει να λύσουμε ένα άλλο μικρό πρόβλημα.

    Το data binding μέχρι στιγμής είναι μονόδρομο, δηλαδή το μαγικό δεν συμβαίνει όταν θα πειράξουμε μέσω κώδικα την τιμή του property. To textbox θα παραμείνει απαθές και θα συνεχίσει να δείχνει την παλιά τιμή. Για να διορθώσουμε αυτή τη συμπεριφορά, θα πρέπει να ακολουθήσουμε ένα design pattern που αναγνωρίζει το binding object. Αυτό το design pattern λέει ότι θα πρέπει το datasource να κάνει expose ένα public event τύπου EventHandler που θα πρέπει επίσης να ονομάζεται "property"Changed (δηλαδή εδώ εφόσον μας ενδιαφέρει το Name property, θα πρέπει να λέγεται NameChanged). Αυτό το event θα πρέπει να γίνεται raise όταν αλλάζει το bounded property. Έτσι λοιπόν, η κλάση σου θα γίνει κάπως έτσι:

    Public Class Customer2
        Private mName As String
        Private mOriginalName As String
        Private mDirty As Boolean

        Public Event NameChanged As EventHandler

        Private Sub OnNameChanged()
            RaiseEvent NameChanged(Me, EventArgs.Empty)
        End Sub

        Public Sub New()
            mName = ""
            mOriginalName = ""
            mDirty = False
        End Sub

        Public Property Name() As String
            Get
                Return mName
            End Get
            Set(ByVal Value As String)
                mName = Value
                OnNameChanged()
            End Set
        End Property

        Public Property OriginalName() As String
            Get
                Return mOriginalName
            End Get
            Set(ByVal Value As String)
                mOriginalName = Value
            End Set
        End Property

        Public ReadOnly Property Dirty() As Boolean
            Get
                Return mDirty
            End Get
        End Property
    End Class

    Τώρα, αν δοκιμάσεις να αλλάξεις το property μέσα από κώδικα, θα αλλάξει και το text του textbox. Θα έχεις δηλαδή "two-way databinding".

    Ας δούμε λοιπόν τι χρειάζεται για να φτάσουμε στο τελικό αποτέλεσμα. Υπάρχει ένα interface που λέγεται IEditableObject το οποίο μας δίνει έλεγχο στην διαδικασία εισαγωγής τιμών στα properties ενός object όταν αυτό χρησιμοποιείται ως datasource. To interface αυτό ορίζει τρία methods, τα BeginEdit, EndEdit, και CancelEdit. Οπότε η κλάση σου, γίνεται κάπως σαν την παρακάτω:

    Public Class Customer
        Implements IEditableObject

        Private mName As String
        Private mOriginalName As String
        Private mDirty As Boolean

        Public Event NameChanged As EventHandler

        Private Sub OnNameChanged()
            RaiseEvent NameChanged(Me, EventArgs.Empty)
        End Sub

        Public Sub New()
            mName = ""
            mOriginalName = ""
            mDirty = False
        End Sub

        Public Property Name() As String
            Get
                Return mName
            End Get
            Set(ByVal Value As String)
                mName = Value
                If Not mDirty Then
                    mOriginalName = mName
                End If
                OnNameChanged()
            End Set
        End Property

        Public Property OriginalName() As String
            Get
                Return mOriginalName
            End Get
            Set(ByVal Value As String)
                mOriginalName = Value
            End Set
        End Property

        Public ReadOnly Property Dirty() As Boolean
            Get
                Return mDirty
            End Get
        End Property

        Sub BeginEdit() Implements IEditableObject.BeginEdit
            If Not mDirty Then
                mOriginalName = mName
                mDirty = True
            End If
        End Sub

        Sub CancelEdit() Implements IEditableObject.CancelEdit
            If mDirty Then
                mName = mOriginalName
                mDirty = False
            End If
        End Sub

        Sub EndEdit() Implements IEditableObject.EndEdit
            OnNameChanged()
        End Sub

    End Class

    Η προσθήκη αυτού του interface στην κλάση, μας δίνει τη δυνατότητα να χρησιμοποιήσουμε τις μεθόδους BindingManagerBase.EndCurrentEdit() και BindingManagerBase.CancelCurrentEdit(). Που βρίσκεται το BindingManagerBase; Φυσικά στο b (Dim b As Binding ) που ορίσαμε στην αρχή. Έτσι λοιπόν, μπορείς να πεις



        Private Sub TextBox1_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles TextBox1.KeyUp
            b.BindingManagerBase.EndCurrentEdit()
        End Sub

        ' Just a button to cancel the editing
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
            b.BindingManagerBase.CancelCurrentEdit()
        End Sub

    Και έχεις την επιθυμητή συμπεριφορά! Ενδεχομένως να χρειάζεται λίγο ραφινάρισμα στο συγχρονισμό Name - OriginalName, εγώ έκανα μια υποθετική υλοποίηση... Όταν υλοποιήσεις σε μία κλάση το IEditableObject, πρέπει υποχρεωτικά να παρέχεις το δικό σου μηχανισμό για να κρατάς τις προηγούμενες τιμές (ώστε να μπορεί να γίνει rollback σε αυτές, κατά το CancelEdit). Όπως καταλαβαίνεις, με το OriginalName και το Dirty πέτυχες ακριβώς αυτό το requirement Smile [:)]. H κλάση που κατεξοχήν υλοποιεί το IEditableObject είναι η DataRow και με αυτόν τον τρόπο επιτυγχάνει στο να κρατάει τις προηγούμενες εκδόσεις.

    Τέλος, τα καλά νέα είναι ότι στο ΝΕΤ 2.0 η DataBindings.Add υποστηρίζει μία έξτρα παράμετρο που καθορίζει ακριβώς αυτό, το πότε θα περνάνε οι αλλαγές στο datasource.


    Vir prudens non contra ventum mingit
  •  23-05-2006, 11:41 13161 σε απάντηση της 13103

    Απ: Object binding σε Win Forms (Vs 2003)

    Μάνο να είσαι καλά !!!
    Ευχαριστώ πάρα πολύ !!!! 

    Αλλά μου άνοιξες την όρεξη :

    Αν έχω μία σχέση master-details ας πούμε Customer και Orders πως θα μπορούσα να υλοποιήσω
    ένα μηχανισμό binding έτσι ώστε το dirty του parent object να αλλάζει αν αλλάξει οτιδήποτε στα
    children (διαγραφή, προσθήκη ή κάποιο update οποιοδήποτε property - αντίστοιχα τα children obs
    θα έχουν και original value properties);


    Πάνος Αβραμίδης
  •  23-05-2006, 14:33 13181 σε απάντηση της 13103

    Απ: Object binding σε Win Forms (Vs 2003)

    Μία δική μου πρόταση για το master-detail με collection στο detail

    Αν υποθέσουμε ότι το Class των Orders θα είναι κάπως έτσι ΠΧ Collection

    Public Class Orders
             
    Inherits CollectionBase

             'To ίδιο μπορείς να κάνεις και στο Class Customer (δηλαδή να προεσθέσεις ένα event σαν αυτό)

            Public event DirtyChanged(DirtyFlag as boolean)

            Public Function Add(ByVal ID As String) As Order
                   Dim ordr As Order = New Order(Me)
                   list.Add(ordr)
                   Return ordr

             End Function

            'Overrides από το CollectionBase για Insert,Remove,Clear

             Protected Overrides Sub OnInsertComplete(ByVal index As Integer, ByVal value As Object)
                         SetDirty(
    True)
             
    End Sub

             Protected Overrides Sub OnRemoveComplete(ByVal index As Integer, ByVal value As Object)
                      SetDirty(
    True)
             End Sub

             Protected Overrides Sub OnClearComplete()
                   SetDirty(
    True)
             
    End Sub

             '----------------------------

             Friend Sub SetDirty(ByVal DirtyFlag As Boolean)
                Raiseevent DirtyChanged(DirtyFlag)
             End Sub

    End Class

    Αν υποθέσουμε ότι το Class Order Item θα είναι κάπως έτσι ΠΧ Collection

    Public Class Order
             Private _Parent As Orders
             Friend Sub New(ByVal Parent As Orders)
                      _Parent = Parent

             End Sub

             Private _Date As DateTime
             Public Property [Date]() As DateTime
                      
    Get
                         Return _Date

                      End Get
                      Set(ByVal Value As DateTime)
                         
       _Date = Value
                            SetDirty(
    True)

                      End Set

             End Property

             Friend Sub SetDirty(ByVal DirtyFlag As Boolean)

                If not _Parent is nothing then
                   _Parent.SetDirty(DirtyFlag)
                End If

             End Sub

    End Class

    Αν μέσα στο Customers προσθέσεις τα παρακάτω

    Private Withevents _Orders As Orders

    Private Sub _Orders_DirtyChanged(ByVal DirtyFlag As Boolean) Handles _Orders.DirtyChanged
                   mDirty = DirtyFlag

    End Sub

    Τώρα αν θέλεις μπορείς να προσθέσεις στο Master object και ένα event

     Public event DirtyChanged(DirtyFlag as boolean)

    και να το κάνεις Raise όπου θέλεις

    ΠΧ
    Private Sub _Orders_DirtyChanged(ByVal DirtyFlag As Boolean) Handles _Orders.DirtyChanged
                   mDirty = DirtyFlag
                   Raiseevent DirtyChanged(DirtyFlag)
     
    End Sub


    Σταύρος Βαλσάμης
    Προγραμματιστής
  •  23-05-2006, 14:47 13183 σε απάντηση της 13103

    Απ: Object binding σε Win Forms (Vs 2003)

    Σταύρο σε ευχαριστώ θερμά !!!
    Μου έπεσαν λίγο μαζεμένα ...
    Θα μελετήσω και θα τα ξαναπούμε.


    Πάνος Αβραμίδης
  •  23-05-2006, 17:56 13196 σε απάντηση της 13103

    Απ: Object binding σε Win Forms (Vs 2003)

     KelMan wrote:
    Το data binding μέχρι στιγμής είναι μονόδρομο, δηλαδή το μαγικό δεν συμβαίνει όταν θα πειράξουμε μέσω κώδικα την τιμή του property. To textbox θα παραμείνει απαθές και θα συνεχίσει να δείχνει την παλιά τιμή. Για να διορθώσουμε αυτή τη συμπεριφορά, θα πρέπει να ακολουθήσουμε ένα design pattern που αναγνωρίζει το binding object. Αυτό το design pattern λέει ότι θα πρέπει το datasource να κάνει expose ένα public event τύπου EventHandler που θα πρέπει επίσης να ονομάζεται "property"Changed (δηλαδή εδώ εφόσον μας ενδιαφέρει το Name property, θα πρέπει να λέγεται NameChanged). Αυτό το event θα πρέπει να γίνεται raise όταν αλλάζει το bounded property.

    Μάνο πριν περάσω στα λεγόμενα του Σταύρου αναγκαστικά ένας ανά property; Βασικά θα ήθελα έναν και μόνο handler τον PropertyChanged αλλά να έχω και bidirectional binding ... Πολλά θέλω ε ;

    Public Event PropertyChanged As EventHandler

    Private Sub OnPropertyChanged()
       
    RaiseEvent PropertyChanged(Me, EventArgs.Empty)
    End Sub

    και αντίστοιχα:

    Public Property Name() As String
       
    Get
          
    Return mName
       
    End Get
       
       
    Set(ByVal Value As String)
          mName = Value
       
    If Not mDirty Then
          
    mOriginalName = mName
       
    End If
       
    OnPropertyChanged()
       
    End Set
    End Property

    Επίσης μια μικρή αλλαγή ατην EndEdit (προστέθηκε και το Surname property):

    Sub EndEdit() Implements IEditableObject.EndEdit
       
    mDirty = (mName <> mOriginalName) Or _
                    (mSurname <> mOriginalSurname)
       OnPropertyChanged()
    End Sub


    Πάνος Αβραμίδης
  •  23-05-2006, 21:42 13214 σε απάντηση της 13196

    Απ: Object binding σε Win Forms (Vs 2003)

    Δεν το έχω δοκιμάσει, αλλά δε νομίζω να γίνεται... Απ' όσο ξέρω, ο binding μηχανισμός ψάχνει ακριβώς αυτό, ένα event τύπου EventHandler που να ονομάζεται με πρώτο συνθετικό το όνομα του property και δεύτερο το "Changed". Μπορείς όμως να το δοκιμάσεις να μας πεις...

     axaros wrote:

    Αν έχω μία σχέση master-details ας πούμε Customer και Orders πως θα μπορούσα να υλοποιήσω
    ένα μηχανισμό binding έτσι ώστε το dirty του parent object να αλλάζει αν αλλάξει οτιδήποτε στα
    children (διαγραφή, προσθήκη ή κάποιο update οποιοδήποτε property - αντίστοιχα τα children obs
    θα έχουν και original value properties);

    Δεν έχει μεγάλες διαφορές, μπορείς στο implementation του IEditableObject να κάνεις ό,τι θέλεις...

    Πάντως, να σου πω, αν περάσεις σε τέτοια πιο δύσκολα σενάρια, εξέτασε ως εναλλακτική λύση να παίξεις με dataset ή με κάποιο O/R framework.


    Vir prudens non contra ventum mingit
  •  29-05-2006, 14:58 13450 σε απάντηση της 13181

    Απ: Object binding σε Win Forms (Vs 2003)

     SValsamis wrote:

    Τώρα αν θέλεις μπορείς να προσθέσεις στο Master object και ένα event

     Public event DirtyChanged(DirtyFlag as boolean)

    και να το κάνεις Raise όπου θέλεις

    ΠΧ
    Private Sub _Orders_DirtyChanged(ByVal DirtyFlag As Boolean) Handles _Orders.DirtyChanged
                   mDirty = DirtyFlag
                   Raiseevent DirtyChanged(DirtyFlag)
     
    End Sub

    Σταύρο ακολουθώντας τις οδηγίες σου "πιάνω" την όποια αλλαγή στο Children collection (Insert, Delete, Clear κλπ).
    Πως θα "πιάσω" και το Update κάποιου property ενός Child; 


    Πάνος Αβραμίδης
  •  29-05-2006, 15:05 13452 σε απάντηση της 13214

    Απ: Object binding σε Win Forms (Vs 2003)

     KelMan wrote:

    Δεν το έχω δοκιμάσει, αλλά δε νομίζω να γίνεται... Απ' όσο ξέρω, ο binding μηχανισμός ψάχνει ακριβώς αυτό, ένα event τύπου EventHandler που να ονομάζεται με πρώτο συνθετικό το όνομα του property και δεύτερο το "Changed". Μπορείς όμως να το δοκιμάσεις να μας πεις...

    Δεν παίζει όπως τα είπες Μάνο ... Βέβαια εγώ κάνω τη δουλειά μου γιατί ουσιαστικά ελέγχω σε ένα σημείο ότι κάποιο (δεν με ενδιαφέρει ποιό συγκεκριμένα) property έχει αλλάξει σε σχέση με την original τιμή που είχε όταν το διάβασα ... 


    Πάνος Αβραμίδης
  •  29-05-2006, 17:29 13455 σε απάντηση της 13181

    Απ: Object binding σε Win Forms (Vs 2003)

     SValsamis wrote:

    Αν υποθέσουμε ότι το Class Order Item θα είναι κάπως έτσι ΠΧ Collection

             Private _Parent As Orders
             Friend Sub New(ByVal Parent As Orders)
                      _Parent = Parent

             End Sub

    Σταύρο νομίζω ότι σε πιάνω ...
    Μου είχε φύγει το Parent property ....

    Και επειδή

     Kelman wrote:
    ωστόσο αυτό συμβαίνει πριν το validate event
    ενώ εγώ το θέλω στο KeyPress ή TextChanged με το UltraGrid (Infragistics) για τα children έχω το εξής στο CellChange event :

    UltraGrid1.UpdateData()

    ΚΑΙ

    Παίζει άψογα !!!! Σας ευχαριστώ για άλλη μια φορά για τη βοήθεια και τους δύο !!!!

     

     


    Πάνος Αβραμίδης
  •  07-06-2006, 11:29 13752 σε απάντηση της 13455

    Απ: Object binding σε Win Forms (Vs 2003)

    Να "ψυρίσω λίγο την μαιμού" ;

    Όπως σας είπα παίζει μια χαρά ... Αλλά το children collection μου "γυρνάει" dirty για οποιοδήποτε action
    πχ addition, deletion, update. Ως εδώ καλά ...

    Αν κρατούσα ένα ξεχωριστό collection δηλαδή το OriginalChildren ανα Parent object και ήλεγχα σε κάθε
    επέμβαση στο Children collection αν τα δύο collections είναι ίδια (ακόμη και το index που βρίσκεται το κάθε child)
    θα βάδιζα στην σωστή κατεύθυνση;

    Αν ναι πως θα κάνω compare τα δύο collections;


     


    Πάνος Αβραμίδης
  •  07-06-2006, 12:47 13759 σε απάντηση της 13752

    Απ: Object binding σε Win Forms (Vs 2003)

    Δεν είμαι σίγουρος αν το να κρατήσεις OriginalChildren ανά Parent είναι καλή λύση.

    Αν θέλεις να ξέρεις ποιο Item του child Collection έχει αλλάξει μπορείς να το περάσεις σαν παράμετρο στο event.

    Μπορείς μέσα στο property Set του κάθε proprety σε κάθε item του child collection να καλέσεις την SetDirty(true).

    Δηλαδή αν το event DirtyChanged στο Parent το κάνεις

    Public event DirtyChanged(DirtyFlag as boolean, Item as Order)

    και το SetDirty Sub το κάνεις

     Friend Sub SetDirty(ByVal DirtyFlag As Boolean,Item as Order)
                Raiseevent DirtyChanged(DirtyFlag,Item)
    End Sub

    και το SetDirty στο Order Κάνεις

    Friend Sub SetDirty(ByVal DirtyFlag As Boolean)

                If not _Parent is nothing then
                   _Parent.SetDirty(DirtyFlag,me)
                End If

    End Sub

    Το event Handler του master διαμορφώνεται ως εξής:

    Private Withevents _Orders As Orders

    Private Sub _Orders_DirtyChanged(ByVal DirtyFlag As Boolean,Item as Order) Handles _Orders.DirtyChanged
                   mDirty = DirtyFlag

    End Sub

    To ίδιο και στο master object

    Public event DirtyChanged(DirtyFlag as boolean,Item as Order)

    Private Sub _Orders_DirtyChanged(ByVal DirtyFlag As Boolean,Item as Order) Handles _Orders.DirtyChanged
                   mDirty = DirtyFlag
                   Raiseevent DirtyChanged(DirtyFlag,Item)
     
    End Sub

     


    Σταύρος Βαλσάμης
    Προγραμματιστής
  •  07-06-2006, 13:21 13760 σε απάντηση της 13759

    Απ: Object binding σε Win Forms (Vs 2003)

    Σταύρο σε ευχαριστώ και πάλι ...
    Πρόσεξε ένα σενάριο :

    Ο χρήστης μου φέρνει ένα parent με δύο children ...
    Διαγράφει τα δυο children και τα ξαναεισάγει με ακριβώς την ίδια σειρά στο collection
    (Πριν κάνει το update της βάσης).
    Σε αυτήν την περίπτωση δεν έχω dirty ...

    Γι' αυτό ρωτάω αν θα πρέπει να κρατήσω το OriginalChildren collection ...


    Πάνος Αβραμίδης
Σελίδα 1 από 2 (21 εγγραφές)   1 2 >
Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems