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

 

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

Custom control property, design-time

Îåêßíçóå áðü ôï ìÝëïò cap. Τελευταία δημοσίευση από το μέλος SValsamis στις 09-12-2005, 14:32. Υπάρχουν 7 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  07-12-2005, 18:40 7632

    Custom control property, design-time

    Φτιάχνω ένα custom control και θέλω ένα από τα properties του να εμφανίζεται στο designer ως combo (δηλ. για την τιμή του - string property είναι - ) να επιλέγω από διακριτές τιμές. Μπορώ να το κάνω αυτό και αν ναι, με ποιά attributes;

     


    Σωτήρης Φιλιππίδης

    DotSee Web Services

    View Sotiris Filippidis's profile on LinkedIn

    DotNetNuke them!
  •  07-12-2005, 18:55 7633 σε απάντηση της 7632

    Απ: Custom control property, design-time

    Νομίζω ότι θα πρέπει να φτιάξεις δικό σου editor για να ξέρει από που θα πάρει ή να περιέχει τις τιμές που θέλεις να έχεις. Δεν είναι τόσο δύσκολο, απλά είναι περίπτωση που δεν τη βλέπεις συχνά και ξενίζουν λίγο τα attributes. Ρίξε μια ματιά με το reflector σε κάποιο παρόμοιο control μέσα στο framework (που να χρησιμοποιεί dropdown για κάποιο property), κάνε copy paste τα attributes που βάζει και κάνε inherit τον editor που χρησιμοποιεί για να παίξεις με τις τιμές που θέλεις.
    Χρήστος Γεωργακόπουλος
  •  07-12-2005, 20:29 7638 σε απάντηση της 7632

    Απ: Custom control property, design-time

    Μιας και σε απασχολεί απ'ότι βλέπω αρκετά το θέμα των custom controls, σταμάτα ό,τι κάνεις ΤΩΡΑ και διάβασε/δούλεψε αυτό το άρθρο (σε δύο συνέχειες).

    http://msdn.microsoft.com/msdnmag/issues/03/04/Design-TimeControls/default.aspx

    http://msdn.microsoft.com/msdnmag/issues/03/05/Design-TimeControls/default.aspx

    Απαντά σε αυτό που ρωτάς αλλά όχι μόνο αφού σου δείχνει πως να φτιάχνεις όλα αυτά τα κόλπα που έχουν τα καλοπληρωμένα controls. Είναι τόσο καλό (δες τους authors) που κάποτε στην Compact τo είχαμε κάνει (μαζί με μερικά άλλα) crash-course. Έχει ένα μικρό learning-curve γι αυτό μην προσπαθήσεις να εφαρμόσεις αυτά που λέει κατευθείαν σε ό,τι φτιάχνεις, αλλά σε ένα proof-of-point control.


    Vir prudens non contra ventum mingit
  •  08-12-2005, 13:05 7664 σε απάντηση της 7633

    Απ: Custom control property, design-time

    Αν κατάλαβα καλά θέλεις κάποιο property από το Control σου, στο Design Time, να εμφανίζει στον property editor ένα combo box με κάποιες τιμές από τις οποίες μπορείς να επιλέξεις.
    Αν έχω καταλάβει καλά,  γ
    ια να το κάνεις αυτό θα πρέπει να δημιουργήσεις έναν Custom TypeConverter (ΠΧ MylistConverter βλέπε πιο κάτω).
    To property του Control σου (ΠΧ MyListProperty) που θέλεις να παίρνει τιμές από List θα πρέπει να το δηλώσεις όπως παρακάτω:

    'Το property
    <System.ComponentModel.TypeConverter(
    GetType(MyListConverter))> _
    Property myListProperty as Object
    ' ......
    End Property

    'O Custom TypeConverter
    Class
    MyListConverter
          Inherits System.ComponentModel.StringConverter

    'Αυτό το Function είναι που φορτώνει τις τιμές στο List του Combo
    Public Overloads Overrides Function GetStandardValues(ByVal context As System.ComponentModel.ITypeDescriptorContext) As System.ComponentModel.TypeConverter.StandardValuesCollection

    'Αν θέλεις να πάρεις ένα Instance του Object που είναι συνδεδεμένο με τον TypeConverter (δηλαδή το Instance
    'του Control σου θα πρέπει να χρησιμοποιήσεις το Context.Instanse
    'ΠΧ αν θέλεις να πάρεις ενα Collection από Components του Control σου θα τα πάρεις με Context.Container.Components
    'ή αν θέλεις να πάρεις ένα Collection από Components της φόρμας που βρίσκεται το Control σου (Container.Instanse.Parent)

    'Εδώ απλά φορτώνεις τις τιμές σε ένα Collection
    Dim C As Collection = New Collection
    For i as integer = 1 to 10 
       c.Add("Value" & trim(str(i)), Str(i))

    Next
    'Δημιουργείς ένα Instance toy System.ComponentModel.TypeConverter.StandardValuesCollection
    'και το επιστρέφεις
    Return New StandardValuesCollection(C)

    End Function

    Public Overloads Overrides Function GetStandardValuesExclusive(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
    Return True

    End Function

    Public Overloads Overrides Function GetStandardValuesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
    Return True
    End Function

    End Class

    Ελπίζω να σε βοήθησα λίγο.

     

    Σταύρος Βαλσάμης

     


    Σταύρος Βαλσάμης
    Προγραμματιστής
  •  08-12-2005, 13:57 7668 σε απάντηση της 7664

    Απ: Custom control property, design-time

    Οχι μόνο με βοήθησε, Σταύρο, αλλά μου έλυσε το θέμα! Ευχαριστώ και εσένα και το Μανο για το reference στα πολύ advanced αρθρα του MSDN Magazine. Η αλήθεια είναι πως δεν έχω καθόλου εμπειρία με αυτό το κομμάτι, οπότε εν καιρώ θα ...καταλάβω περισσότερα πράγματα (ήδη κατάλαβα ορισμένα).

    Ευκαιρία για κάποιον να γράψει ένα λεπτομερές (Ελληνικό) αρθράκι για το design-time, για τους TypeConverters και τους Editors..:) (Βλεπω από τώρα το Μανο να ακονίζει το katana του :) )

    Σωτήρης Φιλιππίδης

    DotSee Web Services

    View Sotiris Filippidis's profile on LinkedIn

    DotNetNuke them!
  •  08-12-2005, 14:05 7669 σε απάντηση της 7664

    Απ: Custom control property, design-time

    Cap
    Οταν βρώ λίγο χρόνο θα κάνω ένα post, με λίγο κώδικα, για το πως μπορείς να κάνεις τα properties ενός object να εμφανίζονται σε design time στον property editor στα ΕΛΛΗΝΙΚΑ ή σε άλλη γλώσσα ανάλογα με τo Culture.
    Ελπίζω αυτό το Σαββατοκύριακο.
    Σταύρος Βαλσάμης
    Προγραμματιστής
  •  08-12-2005, 14:20 7671 σε απάντηση της 7668

    Απ: Custom control property, design-time

    Βεβαίως και να το κάνεις! Οποιαδήποτε πληροφορία επάνω στο θέμα είναι καλοδεχούμενη! Βεβαια όταν έλεγα Ελληνικά, εννούσα το άρθρο ή το post να είναι, οπως και το προηγούμενο άλλωστε, στην Ελληνική γλώσσα. Απλά να καλύπτει μεγαλύτερο εύρος και για άλλους συναδέλφους που πιθανόν να έχουν τις ίδιες απορίες με μένα (ευχή είναι αυτό, όχι απαίτηση, δεν θελω να πιστεψεις οτι ξαφνικά σου ζητάω να γράψεις βιβλιό, ε; :) )

    Παντως και στα μέχρι τώρα ήταν θαυμάσια η κάλυψή σου. Πάντα τέτοια!
    Σωτήρης Φιλιππίδης

    DotSee Web Services

    View Sotiris Filippidis's profile on LinkedIn

    DotNetNuke them!
  •  09-12-2005, 14:32 7739 σε απάντηση της 7671

    Απ: Custom control property, design-time

    Συνημμένα: CustomPropertyDescriptor.zip

    Ελληνικό displayname στα properties ενός Class

     

    Με αυτό το post θα προσπαθήσω να καλύψω το System.Attribute Class καθώς επίσης και τον TypeDescriptor και PropertyDescriptor.

     

    Επίσης επισυνάπτω ένα Zip File με τον κώδικα και το testProject.

     

    Γενικά

    Kάθε Class που δημιουργούμε περιγράφεται από τον System.ComponentModel. Typedescriptor με τα shared methods του (πχ GetProperties).

    Κάθε property του Class περιγράφεται από τoν System.Componentmodel.propertyDescriptor και τα properties του (πχ DisplayName, Description).

     

    Κάθε member (property, method, event κλπ) του Class μπορεί έχει διάφορα Attributes τα οποία διαβάζει ο TypeDescriptor για να περιγράψει το Class.

     

    ΠΧ. Η περιγραφή ενός property στο propertyGrid συμπληρώνεται από το Attribute System.Componentmodel.Description(<Description>).
    Αν ο
    PropertyDescriptor βρεί αυτό το attribute το εμφανίζει στην περιγραφή στο property Grid.

    Αλλο attribute είναι το System.Drawing.ToolBoxBitmapAttribute που αναφέρεται στο Control Class και δηλώνει στο toolBoxitem του designer το εικονίδιο που θα εμφανίσει στο toolbox.

    Ενα άλλο πολύ σημαντικό Atrribute είναι ο TypeConverter.

    Αυτό το χρησιμοποιούμε κυρίως στα Custom Collections για να μπορεί ο Collection Editor να περιγράψει τα Collection Items. (Σε κάποιο άλλο post θα προσπαθήσω να καλύψω αυτό το πολύ σημαντικό κομμάτι)

     

    Στο θέμα

    Στην περίπτωση τη δική μας χρειαζόμαστε από τον PropertyDescriptor να διαβάσει το property DisplayName με τα ελληνικά. Ομως δεν υπάρχει τέτοιο attribute (δεν γνωρίζω αν στο .Net Framework 2.0 έχει προστεθεί).

     

    Γι’ αυτό πρέπει να το δημιουργήσουμε.

     

    Για να γίνει αυτό πρέπει να δημιουργήσουμε ένα Class με Inheritance στο System.Attribute.

     

    'To Attribute System.AttributeUsageAttribute δηλώνει ότι

    'μπορώ να το χρησιμοποιήσω για Members τύπου property.

    'Άλλα AttributeTargets enums είναι to All,το Assembly το Class κλπ.

    <System.AttributeUsage(AttributeTargets.Property)> _

    Public Class DisplayNameAttribute

        Inherits System.Attribute

        Private _DisplayName As String = ""

        Public Sub New(ByVal DisplayName As String)

            _DisplayName = DisplayName

        End Sub

        Public Property DisplayName() As String

            Get

                Return _DisplayName

            End Get

            Set(ByVal Value As String)

                _DisplayName = Value

            End Set

        End Property

     

    End Class

     

    Κάθε Class που δημιουργούμε (αν θέλουμε κάποιο property να έχει DisplayName διαφορετικό από το ίδιο του το όνομα) πρέπει να συμπληρώνει (να κάνει Implementation) το Interface System.Componentmodel.ICustomTypeDescriptor ή (όπως στο παράδειγμά μου) να είναι inherited ενός άλλου Class που κάνει το Implementation.

    Μεταφορικά θα έλεγα ότι “του φοράμε τη στολή με τα διακριτικά μας”.

     

    Imports SValsamis

    Public Class TestDisplayNamePropertyObject

        Inherits CustomDisplayPropertyName
       
    'To Class  CustomDisplayPropertyName κάνει Implementation του Interface  

        'ΙCustomTypeDescriptor

        Private _Property1 As String

        Private _Property2 As String

        <SValsamis.DisplayName("Ιδιότητα πρώτη"), _

         System.ComponentModel.Description("Η πρώτη ιδιότητα του TestDisplayNamePropertyObject")> _

        Public Property property1() As String

            Get

                Return _Property1

            End Get

            Set(ByVal Value As String)

                _Property1 = Value

            End Set

        End Property

     

       <SValsamis.DisplayName("Ιδιότητα δεύτερη"), _

       System.ComponentModel.Description("Η δεύτερη ιδιότητα του TestDisplayNamePropertyObject")> _

        Public Property property2() As String

            Get

                Return _Property2

            End Get

            Set(ByVal Value As String)

                _Property2 = Value

            End Set

        End Property

    End Class

     

     

     

    Το Class που κάνει Implementation στο ICustomTypeDescriptor “η στολή με τα διακριτικά μας”

    Ο κύριος σκοπός αυτού του Class είναι να δημιουργήσει ένα Instance του δικού μας

    propertyDescriptor τύπου "CustomDisplayNamePropertyDescriptor"

     

     

    Imports System

    Imports System.ComponentModel

    Public Class CustomDisplayPropertyName

        Implements ICustomTypeDescriptor

        Private Props As PropertyDescriptorCollection

     

     

    'Αυτά τα Implementations δεν αλλάζουν τίποτα 
    '
    από το αρχικό Class και δεν χρειάζεται κάποιο άλλο σχόλιο

    'γιατί απλά μεταφέρουν τα αντίστοιχα members από το TypeDescriptor

    #Region "ΙCustomTypeDescriptor Implementations"

         Public Function GetAttributes() As AttributeCollection Implements ΙCustomTypeDescriptor.GetAttributes

            Return TypeDescriptor.GetAttributes(Me, True)

        End Function

     

        Public Function GetClassName() As String Implements ICustomTypeDescriptor.GetClassName

            Return TypeDescriptor.GetClassName(Me, True)

        End Function

     

        Public Function GetComponentName() As String _

                      Implements ICustomTypeDescriptor.GetComponentName

            Return TypeDescriptor.GetComponentName(Me, True)

        End Function

     

        Public Function GetConverter() As TypeConverter _

                         Implements ICustomTypeDescriptor.GetConverter

            Return TypeDescriptor.GetConverter(Me, True)

        End Function

     

        Public Function GetDefaultEvent() As EventDescriptor _

                         Implements ICustomTypeDescriptor.GetDefaultEvent

            Return TypeDescriptor.GetDefaultEvent(Me, True)

        End Function

     

        Public Function GetDefaultProperty() As PropertyDescriptor _

                      Implements ICustomTypeDescriptor.GetDefaultProperty

            Return TypeDescriptor.GetDefaultProperty(Me, True)

        End Function

     

        Public Function GetEditor(ByVal editorBaseType As System.Type) As Object _

                      Implements ICustomTypeDescriptor.GetEditor

            Return TypeDescriptor.GetEditor(Me, editorBaseType, True)

        End Function

     

        Public Overloads Function GetEvents() As EventDescriptorCollection _

                      Implements ICustomTypeDescriptor.GetEvents

            Return TypeDescriptor.GetEvents(Me, True)

        End Function

     

        Public Overloads Function GetEvents(ByVal attributes() As Attribute) As _

                                                       EventDescriptorCollection _

                      Implements System.ComponentModel.ICustomTypeDescriptor.GetEvents

            Return TypeDescriptor.GetEvents(Me, attributes, True)

        End Function

     

        Public Function GetPropertyOwner(ByVal pd As PropertyDescriptor) As Object _

               Implements System.ComponentModel.ICustomTypeDescriptor.GetPropertyOwner

     

            Return Me

     

        End Function

    #End Region

     

     

    'Εδώ σημβαίνει αυτό που θέλουμε να κάνουμε

    #Region "Get Properties"

         Public Overloads Function GetProperties() As PropertyDescriptorCollection _

                          Implements ICustomTypeDescriptor.GetProperties

     

            If Props Is Nothing Then

                'Παίρνουμε τα properties του πρωτότυπου Class

                Dim baseproperties As PropertyDescriptorCollection = _

                            TypeDescriptor.GetProperties(Me, True)

     

                'Δημιουργούμε ένα κενό propertiesCollection

                Props = New PropertyDescriptorCollection(Nothing)

     

                'και από κάθε property του πρωτότυπου δημιουργούμε 

                'ένα δικό μας propertyDescriptor

                'ο οποίος θα διαβάσει το DisplayName property

                'του DisplayNameAttribute και του περνάμε στον constructor το αυθεντικό property

                For Each prp As PropertyDescriptor In baseproperties

                    Props.Add(New SValsamis.CustomDisplayNamePropertyDescriptor(prp))

                Next

            End If

     

            'επιστρέφουμε το νέο Collection

            Return Props

     

        End Function

        'To ίδιο σημβαίνει και εδώ με τη μόνη διαφορά

        'ότι γίνεται φιλτράρισμα με τα attributes του propertyDescriptor

        Public Overloads Function GetProperties(ByVal attributes() As Attribute) As _

                                                 PropertyDescriptorCollection _

                         Implements System.ComponentModel.ICustomTypeDescriptor.GetProperties

     

            If Props Is Nothing Then

                Dim baseproperties As PropertyDescriptorCollection = _

                TypeDescriptor.GetProperties(Me, attributes, True)

               

                Props = New PropertyDescriptorCollection(Nothing)

                For Each prp As PropertyDescriptor In baseproperties

                    Props.Add(New CustomDisplayNamePropertyDescriptor(prp))

                Next

            End If

            Return Props

        End Function

    #End Region

     

    End Class

     

     


    Τέλος δημιουργούμε ένα Class τύπου propertyDescriptor και κάνουμε override το property displayname με την τιμή που θα βρεί από το δηλωμένο attribute τύπου SValsamis.DisplayNameAttribute

     

    Imports System

    Imports System.ComponentModel

    'Αυτό το Class κάνει override το DisplayName του propertyDescriptor

    'με το DisplayName property του DisplayNameAttribute μας

    Public Class CustomDisplayNamePropertyDescriptor

        Inherits PropertyDescriptor

        'Instance του PropertyDescriptor που έρχεται στον Constructor 
        '
    από το ICustomTypeDescriptor και περιέχει το πρωτότυπο property

        Private _BasePropertyDescriptor As PropertyDescriptor

        Public Sub New(ByVal BasePropertyDescriptor As PropertyDescriptor)

            MyBase.New(BasePropertyDescriptor)

            _BasePropertyDescriptor = BasePropertyDescriptor

        End Sub

     

     

     

     

    #Region "MustOverrides απο το Base Class"

        'Ολα τα παρακάτω Members λειτουργούν ακριβώς όπως το πρωτότυπο και είναι MustOverride

        Public Overrides Function CanResetValue(ByVal component As Object) As Boolean

            Return _BasePropertyDescriptor.CanResetValue(component)

        End Function

     

        Public Overrides ReadOnly Property ComponentType() As System.Type

            Get

                Return _BasePropertyDescriptor.ComponentType

            End Get

        End Property

     

        Public Overrides Function GetValue(ByVal component As Object) As Object

            Return _BasePropertyDescriptor.GetValue(component)

        End Function

     

        Public Overrides ReadOnly Property IsReadOnly() As Boolean

            Get

                Return _BasePropertyDescriptor.IsReadOnly

            End Get

        End Property

     

        Public Overrides ReadOnly Property PropertyType() As System.Type

            Get

                Return _BasePropertyDescriptor.PropertyType

            End Get

        End Property

     

        Public Overrides Sub ResetValue(ByVal component As Object)

            _BasePropertyDescriptor.ResetValue(component)

        End Sub

     

        Public Overrides Sub SetValue(ByVal component As Object, ByVal value As Object)

            _BasePropertyDescriptor.SetValue(component, value)

        End Sub

     

        Public Overrides Function ShouldSerializeValue(ByVal component As Object) As Boolean

            Return _BasePropertyDescriptor.ShouldSerializeValue(component)

        End Function

    #End Region

     

     

     

    'Εδώ διαβάζουμε το property DisplayName του
    'Attribute "DisplayNameAttribute"
    και κάνουμε Override το

    'DisplayName του πρωτότυπου propertyDescriptor

     Public Overrides ReadOnly Property DisplayName() As String

            Get

                'Διαβάζουμε το Attribute SValsamis.DisplayNameAttribute

                Dim attr As Attribute = _BasePropertyDescriptor.Attributes(GetType(SValsamis.DisplayNameAttribute))

                'Αν δεν υπάρχει επιστρέφουμε το displayName του πρωτότυπου

                'το οποίο είναι το όνομα του property

                If attr Is Nothing Then

                    Return _BasePropertyDescriptor.DisplayName

                Else

                    'Αν υπάρχει τότε επιστρέφουμε το DisplayName property του Attribute

                    Return CType(attr, SValsamis.DisplayNameAttribute).DisplayName

                End If

     

            End Get

        End Property

     

        Public Overrides ReadOnly Property Description() As String

            Get

                Return _BasePropertyDescriptor.Description

            End Get

     

        End Property

     

    End Class

     

     

    Επίλογος

    Ελπίζω το άρθρο αυτό να βοήθησε λίγο στο να κατανοήσει κάποιος τα Attributes, Typedescriptor και propertyDescriptor.

    Εγώ χρησιμοποιώ αυτό το σενάριο για να μπορώ να δίνω στους χρήστες των εφαρμογών μου δυνατότητες παραμετροποίησης. Δημιουργώ κάποια Classes πχ Report properties και σε ένα propertyGrid Control αφήνω τον χρήστη να συμπληρώσει τα properties, τα οποία όμως είναι φιλικά σε αυτόν και κυρίως ΕΛΛΗΝΙΚΑ.

    Σε κάποιο άλλο post θα μετατρέψουμε τo attribute να μιλάει σε διάφορες γλώσσες ανάλογα με το cultrure της εφαρμογής και θα αναφερθούμε αναλυτικότερα στον TypeConverter.


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