Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1458
  • Last Modified:

How to Make one property in a property grid control read only by code in run time (in VB.NET)

***i'm writing my code in VB.NET

Im using a Property Grid control in my form.
I need to display different properties in the grid according to the Situation. So I predefined classes of the required categories, and required properties.
In run time, depending on the user inputs I Build the property grid according to one of my predefined classes, and in the NEW function I plant the required default values to each property (according to some configuration files). then the user can change those default values.

I need to make some fields read only during run time according to the values they have, so the user wont be able to change them.

For example:
The user presses a button and I ENABLE the property grid control
1.      I build the property grid with the required properties (Name, Age, Degree)
2.      In the new event I read some configuration files and initialize the values of each property  
PropertyGrid1.SelectedObject = New MyProperties(MyName, MyAge, MyDegree)

Now this is how my property grid looks like:
Name      MrX
Age              30
Degree       NA

You can see that I dont have a degree, thus the value of the Degree property is NA

In this point I want BY CODE to make the property Degree read only, so the user couldnt edit it.

I cant find a way to loop all the properties, and if a properties value = NA than to make it read only
0
InsProf
Asked:
InsProf
  • 4
2 Solutions
 
Stephan_SchrandtCommented:
I don't think there's a way to make a griditem readonly because it just reflects the properties of the selected object. You can loop through the properties of the object by the code shown below. There's an event called PropertyValueChanged, this might be your best chance to avoid editing some properties.

Dim c as MyProperties = New MyProperties(MyName, MyAge, MyDegree)
PropertyGrid1.SelectedObject = c
Dim pv As Object
Dim pi As System.Reflection.PropertyInfo() = c.GetType.GetProperties()
For i As Integer = 0 To pi.Length - 1
      With pi(i)
            pv = .GetValue(c, Nothing)
      End With
Next i
0
 
Meir RivkinFull stack Software EngineerCommented:
@InsProf

The way to achieve this is using custom ICustomTypeDescriptor and PropertyDescriptor.
the only drawback is that in the background ur actually remove the property and add it again with the "new" attribute (in your case ReadonlyAttribute).
let me know if u need a full source code.



0
 
Meir RivkinFull stack Software EngineerCommented:
add the following classes to your code:
Imports System.ComponentModel

''' <summary>
''' CustomClass (Which is binding to property grid)
''' </summary>
Public Class CustomClass
    Inherits CollectionBase
    Implements ICustomTypeDescriptor

    ''' <summary>
    ''' Add CustomProperty to Collectionbase List
    ''' </summary>
    ''' <param name="Value"></param>
    Public Sub Add(ByVal Value As CustomProperty)
        MyBase.List.Add(Value)
    End Sub

    ''' <summary>
    ''' Remove item from List
    ''' </summary>
    ''' <param name="Name"></param>
    Public Sub Remove(ByVal Name As String)
        For Each prop As CustomProperty In MyBase.List
            If prop.Name = Name Then
                MyBase.List.Remove(prop)
                Exit Sub
            End If
        Next
    End Sub

    ''' <summary>
    ''' Indexer
    ''' </summary>
    Default Public Property Item(ByVal index As Integer) As CustomProperty
        Get
            Return DirectCast(MyBase.List(index), CustomProperty)
        End Get
        Set(ByVal value As CustomProperty)
            MyBase.List(index) = DirectCast(value, CustomProperty)
        End Set
    End Property

    Public Function GetAttributes() As System.ComponentModel.AttributeCollection Implements System.ComponentModel.ICustomTypeDescriptor.GetAttributes
        Return TypeDescriptor.GetAttributes(Me, True)
    End Function

    Public Function GetClassName() As String Implements System.ComponentModel.ICustomTypeDescriptor.GetClassName
        Return TypeDescriptor.GetClassName(Me, True)
    End Function

    Public Function GetComponentName() As String Implements System.ComponentModel.ICustomTypeDescriptor.GetComponentName
        Return TypeDescriptor.GetComponentName(Me, True)
    End Function

    Public Function GetConverter() As System.ComponentModel.TypeConverter Implements System.ComponentModel.ICustomTypeDescriptor.GetConverter
        Return TypeDescriptor.GetConverter(Me, True)
    End Function

    Public Function GetDefaultEvent() As System.ComponentModel.EventDescriptor Implements System.ComponentModel.ICustomTypeDescriptor.GetDefaultEvent
        Return TypeDescriptor.GetDefaultEvent(Me, True)
    End Function

    Public Function GetDefaultProperty() As System.ComponentModel.PropertyDescriptor Implements System.ComponentModel.ICustomTypeDescriptor.GetDefaultProperty
        Return TypeDescriptor.GetDefaultProperty(Me, True)
    End Function

    Public Function GetEditor(ByVal editorBaseType As System.Type) As Object Implements System.ComponentModel.ICustomTypeDescriptor.GetEditor
        Return TypeDescriptor.GetEditor(Me, editorBaseType, True)
    End Function

    Public Function GetEvents() As System.ComponentModel.EventDescriptorCollection Implements System.ComponentModel.ICustomTypeDescriptor.GetEvents
        Return TypeDescriptor.GetEvents(Me, True)
    End Function

    Public Function GetEvents(ByVal attributes() As System.Attribute) As System.ComponentModel.EventDescriptorCollection Implements System.ComponentModel.ICustomTypeDescriptor.GetEvents
        Return TypeDescriptor.GetEvents(Me, attributes, True)
    End Function

    Public Function GetProperties() As System.ComponentModel.PropertyDescriptorCollection Implements System.ComponentModel.ICustomTypeDescriptor.GetProperties
        Return TypeDescriptor.GetProperties(Me, True)
    End Function

    Public Function GetProperties(ByVal attributes() As System.Attribute) As System.ComponentModel.PropertyDescriptorCollection Implements System.ComponentModel.ICustomTypeDescriptor.GetProperties
        Dim newProps As PropertyDescriptor() = New PropertyDescriptor(Me.Count - 1) {}
        For i As Integer = 0 To Me.Count - 1
            Dim prop As CustomProperty = DirectCast(Me(i), CustomProperty)
            newProps(i) = New CustomPropertyDescriptor(prop, attributes)
        Next
        Return (New PropertyDescriptorCollection(newProps))
    End Function

    Public Function GetPropertyOwner(ByVal pd As System.ComponentModel.PropertyDescriptor) As Object Implements System.ComponentModel.ICustomTypeDescriptor.GetPropertyOwner
        Return Me
    End Function
End Class

Public Class CustomProperty
    Private sName As String = String.Empty
    Private bReadOnly As Boolean = False
    Private bVisible As Boolean = True
    Private objValue As Object = Nothing

    Public Sub New(ByVal sName As String, ByVal value As Object, ByVal type As Type, ByVal bReadOnly As Boolean, ByVal bVisible As Boolean)
        Me.sName = sName
        Me.objValue = value
        Me.m_type = type
        Me.bReadOnly = bReadOnly
        Me.bVisible = bVisible
    End Sub

    Private m_type As Type
    Public ReadOnly Property Type() As Type
        Get
            Return m_type
        End Get
    End Property

    Public ReadOnly Property [ReadOnly]() As Boolean
        Get
            Return bReadOnly
        End Get
    End Property

    Public ReadOnly Property Name() As String
        Get
            Return sName
        End Get
    End Property

    Public ReadOnly Property Visible() As Boolean
        Get
            Return bVisible
        End Get
    End Property

    Public Property Value() As Object
        Get
            Return objValue
        End Get
        Set(ByVal value As Object)
            objValue = value
        End Set
    End Property

End Class

Imports System.ComponentModel

''' <summary>
''' Custom PropertyDescriptor
''' </summary>
Public Class CustomPropertyDescriptor
    Inherits PropertyDescriptor
    Private m_Property As CustomProperty
    Public Sub New(ByRef myProperty As CustomProperty, ByVal attrs As Attribute())
        MyBase.New(myProperty.Name, attrs)
        m_Property = myProperty
    End Sub

#Region "PropertyDescriptor specific"

    Public Overloads Overrides Function CanResetValue(ByVal component As Object) As Boolean
        Return False
    End Function

    Public Overloads Overrides ReadOnly Property ComponentType() As Type
        Get
            Return Nothing
        End Get
    End Property

    Public Overloads Overrides Function GetValue(ByVal component As Object) As Object
        Return m_Property.Value
    End Function

    Public Overloads Overrides ReadOnly Property Description() As String
        Get
            Return m_Property.Name
        End Get
    End Property

    Public Overloads Overrides ReadOnly Property Category() As String
        Get
            Return String.Empty
        End Get
    End Property

    Public Overloads Overrides ReadOnly Property DisplayName() As String
        Get
            Return m_Property.Name
        End Get
    End Property

    Public Overloads Overrides ReadOnly Property IsReadOnly() As Boolean
        Get
            Return m_Property.[ReadOnly]
        End Get
    End Property

    Public Overloads Overrides Sub ResetValue(ByVal component As Object)
        'Have to implement
    End Sub

    Public Overloads Overrides Function ShouldSerializeValue(ByVal component As Object) As Boolean
        Return False
    End Function

    Public Overloads Overrides Sub SetValue(ByVal component As Object, ByVal value As Object)
        m_Property.Value = value
    End Sub

    Public Overloads Overrides ReadOnly Property PropertyType() As Type
        Get
            Return m_Property.Type
        End Get
    End Property

#End Region


End Class

Open in new window

0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
Meir RivkinFull stack Software EngineerCommented:
now, instead of using class MyProperties, create a member field in your Form of type CustomClass:
Dim myProperties As CustomClass = New CustomClass()

in the form_load, initialize your properties collection and propertygrid:

 myProperties.Add(New CustomProperty("Name", "Sven", GetType(String), False, True))
        myProperties.Add(New CustomProperty("IsCool", "True", GetType(Boolean), False, True))
        myProperties.Add(New CustomProperty("DateTime", DateTime.Now, GetType(DateTime), False, True))
propertyGrid1.SelectedObject = myProperties

last thing is the ability to change the readonly attribute:
    Sub SetReadonly(ByVal propName As String, ByVal isReadOnly As Boolean)
        Dim customProp As CustomProperty = myProperties.Cast(Of CustomProperty)().Where(Function(n) n.Name = propName).FirstOrDefault()

        myProperties.Remove(customProp.Name)
        myProperties.Add(New CustomProperty(customProp.Name, customProp.Value, customProp.Type, isReadOnly, customProp.Visible))
        propertyGrid1.Refresh()
    End Sub

enjoy.
0
 
InsProfAuthor Commented:
If I understand you correctly,
What you are really saying is that I have to remove the property and then Create it again as read only&.
Meaning there is no way to set an existing property as read only by code in run time.
0
 
Meir RivkinFull stack Software EngineerCommented:
@InsProf

as far as i know there's no descent way to achieve this.
0

Featured Post

Efficient way to get backups off site to Azure

This user guide provides instructions on how to deploy and configure both a StoneFly Scale Out NAS Enterprise Cloud Drive virtual machine and Veeam Cloud Connect in the Microsoft Azure Cloud.

  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now