
I have a custom control that incorporates a tree view and a property grid for editing a set of operations. Each operation may have one or more parameters. For the parameters that only hold a single value the property grid is working perfectly. The trouble I am having is properly displaying the collection values. In the example below the extensions are a collection parameter.
The behavior I am trying to achieve in the property grid is similar to List1 in the Collection Read-Only Items quick start as shown below.
Here is the xaml for the property grid.
<propgrid:PropertyGrid Name="pgOperationCustom" Grid.Column="2"
CollectionDisplayMode="EditableInline"
SummaryCanAutoSize="True"
SummaryHeight="Auto" >
<propgrid:PropertyGrid.DataFactory>
<CtsControls:OperableTypeReflectionFactory />
</propgrid:PropertyGrid.DataFactory>
</propgrid:PropertyGrid>
Here is an xml representation of the operation object shown in the first screen shot above.
<ContentExtensionDecisionOperation Name="ContentExtensionDecision" Description="" LogResult="True" Scope="Source">
<Parameters>
<SingletonEnumParameter Name="VersionScope" DisplayName="Version Scope" Type="ecmEnum" EnumType="VersionScopeEnum" Description="Specifies which version(s) to use for the evaluation." Value="AllVersions" />
<SingletonLongParameter Name="ContentElementIndex" DisplayName="Content Element Index" Type="ecmLong" Description="" Value="0" />
<SingletonEnumParameter Name="Mode" DisplayName="Mode" Type="ecmEnum" EnumType="ModeEnum" Description="Specifies whether the mode is valid or invalid." Value="Valid" />
<SingletonEnumParameter Name="EvaluationAction" DisplayName="Evaluation Action" Type="ecmEnum" EnumType="EvaluationActionEnum" Description="Specifies the behavior following the evaluation." Value="Default" />
<MultiValueStringParameter Name="Extensions" DisplayName="Extensions" Type="ecmString" Description="The list of extensions to test for." Cardinality="ecmMultiValued">
<Values>
<Value>pdf</Value>
<Value>docx</Value>
</Values>
</MultiValueStringParameter>
</Parameters>
<RunBeforeBegin />
<RunAfterComplete />
<RunOnFailure />
<TrueOperations />
<FalseOperations />
</ContentExtensionDecisionOperation>
Here is the code for the custom data factory
Public Class OperableTypeReflectionFactory
Inherits TypeReflectionFactory
#Region "Public Methods"
Protected Overrides Function GetProperties(ByVal value As Object, ByVal options As DataFactoryOptions) As IList(Of IPropertyDataAccessor)
Try
Dim lobjDataAccessors As IList(Of IPropertyDataAccessor)
Dim lobjOperable As IOperable = TryCast(value, IOperable)
If lobjOperable IsNot Nothing Then
' Create a list of property data accessor results
lobjDataAccessors = New List(Of IPropertyDataAccessor)()
If TypeOf lobjOperable Is IProcess Then
'Return MyBase.GetProperties(value, options)
For Each lobjOperation In CType(lobjOperable, IProcess).Operations
lobjDataAccessors.Add(New OperableDataAccessor(lobjOperation, "Operations"))
Next
ElseIf TypeOf value Is IOperations Then
Dim lobjOperationAccessor As IPropertyDataAccessor = Nothing
Dim lobjDummyProperty As IProperty = PropertyFactory.Create(PropertyType.ecmObject, lobjOperable.Name, String.Empty)
For Each lobjOperation As IOperable In CType(lobjOperable, Cts.Operations.Operations)
lobjOperationAccessor = New CtsPropertyDataAccessor(lobjDummyProperty, "Operations")
lobjDataAccessors.Add(lobjOperationAccessor)
Next
ElseIf TypeOf lobjOperable Is IOperation Then
' Add the Scope
Dim lobjOperation As IOperation = lobjOperable
lobjDataAccessors.Add(New CustomPropertyDataAccessor(Of IOperation, String) _
(lobjOperation, Function(o) lobjOperation.ScopeString, "Scope", "Misc", _
Nothing, GetType(OperationScope), Helper.EnumerationDictionary(GetType(OperationScope)).Keys, _
"Specifies whether the operation executes against the source or destination document."))
End If
' Add the parameters
For Each lobjParameter As Parameter In lobjOperable.Parameters
Dim lobjDataAccessor As New CtsPropertyDataAccessor(lobjParameter, "Parameters")
lobjDataAccessors.Add(lobjDataAccessor)
Next
Else
' Fall back to using the base method's results for nested objects
lobjDataAccessors = MyBase.GetProperties(value, options)
End If
Return lobjDataAccessors
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Function
#End Region
End Class
Here is the code for the data accessor I am using for the parameters.
Public Class CtsPropertyDataAccessor
Inherits CachedPropertyDataAccessorBase
#Region "Class Variables"
Private mobjCtsProperty As IProperty
Private mstrCategory As String = String.Empty
Private mintValueIndex As Integer = -1
Dim mobjConverter As ExpandableCollectionConverter = Nothing
#End Region
#Region "Public Properties"
Public ReadOnly Property CtsProperty As IProperty
Get
Try
Return mobjCtsProperty
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Get
End Property
#End Region
#Region "Constructors"
Public Sub New(ByVal lpCtsProperty As IProperty, ByVal lpCategory As String)
Me.New(lpCtsProperty, lpCategory, -1)
End Sub
Public Sub New(ByVal lpCtsProperty As IProperty, ByVal lpCategory As String, lpValueIndex As Integer)
Try
If lpCtsProperty Is Nothing Then
Throw New ArgumentNullException("lpCtsProperty")
End If
mobjCtsProperty = lpCtsProperty
mintValueIndex = lpValueIndex
If Not String.IsNullOrEmpty(lpCategory) Then
mstrCategory = lpCategory
End If
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Sub
#End Region
#Region "CachedPropertyDataAccessorBase Overrides"
Public Overrides Sub Reset()
' No-op
End Sub
Public Overrides ReadOnly Property CanAddChild() As Boolean
Get
Try
If CtsProperty IsNot Nothing AndAlso CtsProperty.Cardinality = Cardinality.ecmMultiValued Then
Return True
Else
Return False
End If
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Get
End Property
Public Overrides ReadOnly Property CanReset As Boolean
Get
Return False
End Get
End Property
Public Overrides ReadOnly Property Category As String
Get
Try
If String.IsNullOrEmpty(mstrCategory) Then
Return MyBase.Category
Else
Return mstrCategory
End If
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Get
End Property
Public Overrides ReadOnly Property Description As String
Get
Try
If Not String.IsNullOrEmpty(Me.CtsProperty.Description) Then
Return Me.CtsProperty.Description
Else
Return String.Format("No description available for property {0}.", Me.CtsProperty.Name)
End If
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Get
End Property
Public Overrides ReadOnly Property DisplayName As String
Get
Try
If mintValueIndex = -1 Then
Return Me.CtsProperty.DisplayName
Else
Return String.Empty
End If
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Get
End Property
Public Overrides ReadOnly Property Target As Object
Get
Try
Return Me.CtsProperty
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Get
End Property
Protected Overrides ReadOnly Property IsLimitedToStandardValuesInternal As Boolean
Get
Try
Return Me.CtsProperty.HasStandardValues
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Get
End Property
Protected Overrides ReadOnly Property IsMergableInternal As Boolean
Get
Return False
End Get
End Property
Protected Overrides ReadOnly Property IsModifiedInternal As Boolean
Get
Return True
End Get
End Property
Protected Overrides ReadOnly Property IsReadOnlyInternal As Boolean
Get
Return False
End Get
End Property
Protected Overrides ReadOnly Property StandardValuesInternal() As IEnumerable
Get
Try
If TypeOf Me.CtsProperty Is SingletonEnumParameter Then
Return Helper.CreateDisplayNames(Me.CtsProperty.StandardValues)
Else
Return Me.CtsProperty.StandardValues
End If
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Get
End Property
Protected Overrides ReadOnly Property ConverterInternal As System.ComponentModel.TypeConverter
Get
Try
If TypeOf Me.CtsProperty Is IProperty Then
Dim lobjProperty As IProperty = Me.CtsProperty
If lobjProperty.Cardinality = Cardinality.ecmMultiValued Then
If mobjConverter Is Nothing Then
mobjConverter = New ExpandableCollectionConverter()
End If
Return mobjConverter
Else
Return Nothing
End If
End If
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Get
End Property
Protected Overrides Property ValueInternal As Object
Get
Try
If TypeOf Me.CtsProperty Is SingletonBooleanParameter Then
Return Boolean.Parse(Me.CtsProperty.Value)
ElseIf TypeOf Me.CtsProperty Is SingletonEnumParameter Then
Return Helper.CreateDisplayName(Me.CtsProperty.Value.ToString)
ElseIf TypeOf Me.CtsProperty Is IProperty Then
Dim lobjProperty As IProperty = Me.CtsProperty
If lobjProperty.Cardinality = Cardinality.ecmMultiValued Then
'Return Nothing
If Me.CtsProperty.HasValue Then
Return Me.CtsProperty.Values
Else
Return Nothing
End If
Else
Return Me.CtsProperty.Value
End If
Else
Return Nothing
End If
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Get
Set(value As Object)
Try
If TypeOf Me.CtsProperty Is SingletonBooleanParameter Then
Me.CtsProperty.Value = Boolean.Parse(value.ToString)
ElseIf TypeOf Me.CtsProperty Is SingletonEnumParameter Then
Me.CtsProperty.Value = Helper.NameFromDisplayName(value.ToString)
Else
Me.CtsProperty.Value = value
End If
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Set
End Property
Protected Overrides ReadOnly Property ValueNameInternal As String
Get
Try
If mintValueIndex = -1 Then
Return Me.CtsProperty.Name
Else
Return String.Empty
End If
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Get
End Property
Protected Overrides ReadOnly Property ValuesInternal As Object()
Get
Try
If Me.CtsProperty.Cardinality = Cardinality.ecmMultiValued Then
If Me.CtsProperty.Values IsNot Nothing Then
If Me.CtsProperty.Type = PropertyType.ecmString Then
Dim lobjValues As New List(Of Object)
If mobjConverter Is Nothing Then
mobjConverter = New ExpandableCollectionConverter()
End If
For Each lobjValue As Object In Me.CtsProperty.Values
Dim lobjItem As Object = mobjConverter.CreateItem(Me)
mobjConverter.AddItem(Me, lobjItem)
lobjValues.Add(lobjValue.ToString)
Next
Return lobjValues.ToArray
Else
Dim lobjValues As New List(Of Object)
lobjValues.AddRange(Me.CtsProperty.Values)
Return lobjValues.ToArray
End If
Else
Return MyBase.ValuesInternal
End If
Else
Return MyBase.ValuesInternal
End If
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Get
End Property
Protected Overrides ReadOnly Property ValueTypeInternal As Type
Get
Try
Select Case Me.CtsProperty.Cardinality
Case Cardinality.ecmSingleValued
Select Case Me.CtsProperty.Type
Case PropertyType.ecmString, PropertyType.ecmHtml, PropertyType.ecmUri, _
PropertyType.ecmXml, PropertyType.ecmUndefined
Return GetType(String)
Case PropertyType.ecmBoolean
Return GetType(Boolean)
Case PropertyType.ecmDate
Return GetType(DateTime)
Case PropertyType.ecmDouble
Return GetType(Double)
Case PropertyType.ecmEnum
Return GetType([Enum])
Case PropertyType.ecmGuid
If TypeOf Me.CtsProperty.Value Is Guid Then
Return GetType(Guid)
Else
Return GetType(String)
End If
Case PropertyType.ecmObject, PropertyType.ecmBinary
Return GetType(Object)
Case Else
Return GetType(String)
End Select
Case Cardinality.ecmMultiValued
Select Case Me.CtsProperty.Type
Case PropertyType.ecmString, PropertyType.ecmHtml, PropertyType.ecmUri, _
PropertyType.ecmXml, PropertyType.ecmUndefined
Return GetType(List(Of String))
Case Else
Return GetType(List(Of Object))
End Select
End Select
Catch ex As Exception
ApplicationLogging.LogException(ex, Reflection.MethodBase.GetCurrentMethod)
' Re-throw the exception to the caller
Throw
End Try
End Get
End Property
#End Region
End Class
What am I missing?