Hello
I'm currently working on a custom graphical editor under Visual Studio. This editor uses the component model of the Framework with its services by implementing a DesignSurface.
All works well except some data persistense scenari. My selected component has a property like this one :
Private _Children As New List(Of Child)<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
Public ReadOnly Property Children() As List(Of Child)
Get
Return _Children
End Get
End PropertyWhen I edit this property inside the property window, I got the standard CollectionEditor run, and I can edit properly my collection. I valid the CollectionForm, and then, I don't see any undo inside VS, whereas all the other kind of properties works well (with SerializationVisibility set to Visible) for the basic undo process provided by the default UndoEngine.
I go deeper and discover that the EditValue method of the CollectionEditor class receive a provider parameter that can't reach the IComponentChangeService created by the DesignSurface. From there, I've found a way to acces this service by calling the GetService(GetType(IComponentChangeService)) from the Instance provided by the context parameter, but framework's editors don't intend to access this service this way...
As I think this is not like that it should work, I certainly have a main issue into my Package implementation. The problem is that the context and the provider parameters of the EditValue method are provided by the PropertyGrid in the property window of VS. So, it means that my package is unable to expose the DesignSurface services in order to make them reachable to this PropertyGrid, and it causes a persistense issue when I edit some properties (the Content ones I think).
I tried to read all possible documentation on how to manage services in a Package. I've even found a way to expose an IPropertyValueUIService at top level of the VS global service tree (Maybe not a good way, but an effective one), but I can't find a way to do that for services (especially IComponentChangeService) required by the PropertyGrid to make my component model work well...
All my experiments make me think that the PropertyGrid inside VS can only access the top level services (the promoted ones), but I guess I can't promote a service like an IComponentChangeService because it will bring a conflict if I open two or more instances of my custom editor inside VS.
So is there anyone who can tell me how the native Windows Form Editor can make its IComponentChangeService (among the other services provided by my DesignSurface) reachable by the VS PropertyGrid ?
My package declaration (I didn't paste all the attributes...) :
Public NotInheritable Class MyPackage
Inherits Package
#Region "Constructor"
Public Sub New()
' The IPropertyValueUIService should be created in the global service provider to be accessed by the VS Property Window
CType(Me, IServiceContainer).AddService(GetType(IPropertyValueUIService), AddressOf CreateService, True)
End Sub
#End Region
#Region "Initialization"
Private _Factory As MyEditorFactory
Protected Overrides Sub Initialize()
MyBase.Initialize()
_Factory = New MyEditorFactory(Me)
MyBase.RegisterEditorFactory(_Factory)
End Sub
#End Region
#Region "Services"
Private Function CreateService(ByVal Container As IServiceContainer, ByVal ServiceType As Type) As Object
If GetType(IPropertyValueUIService).Equals(ServiceType) Then Return New MyPropertyValueUIService
Return Nothing
End Function
#End Region
#Region "Dispose"
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
' Remove the IPropertyValueUIService service
CType(Me, IServiceContainer).RemoveService(GetType(IPropertyValueUIService), True)
' Dispose EditorFactory
If Not _Factory Is Nothing Then _Factory.Dispose()
Finally
MyBase.Dispose(disposing)
End Try
End Sub
#End Region
End ClassMy editor factory declaration :
Public NotInheritable Class MyEditorFactory
Implements IVsEditorFactory
Implements System.IServiceProvider
Implements IDisposable
#Region "Constructor"
Public Sub New(ByVal Package As MyPackage)
If Package Is Nothing Then Throw New ArgumentNullException("Package")
_Package = Package
End Sub
#End Region
#Region "Package"
Private _Package As MyPackage
#End Region
#Region "IVsEditorFactory Members"
Private _ServiceProvider As ServiceProvider
Private _trs As ITypeResolutionService
Private _tds As ITypeDiscoveryService
Private Function SetSite(ByVal psp As Microsoft.VisualStudio.OLE.Interop.IServiceProvider) As Integer Implements IVsEditorFactory.SetSite
_ServiceProvider = New ServiceProvider(psp)
Return VSConstants.S_OK
End Function
Public Function GetService(ByVal serviceType As Type) As Object Implements System.IServiceProvider.GetService
If GetType(ITypeResolutionService).Equals(serviceType) AndAlso Not _trs Is Nothing Then Return _trs
If GetType(ITypeDiscoveryService).Equals(serviceType) AndAlso Not _tds Is Nothing Then Return _tds
If _ServiceProvider Is Nothing Then Return Nothing
Return _ServiceProvider.GetService(serviceType)
End Function
Private Function MapLogicalView(ByRef rguidLogicalView As Guid, <System.Runtime.InteropServices.Out()> ByRef pbstrPhysicalView As String) As Integer Implements IVsEditorFactory.MapLogicalView
pbstrPhysicalView = Nothing
If VSConstants.LOGVIEWID_Primary = rguidLogicalView OrElse VSConstants.LOGVIEWID_Designer = rguidLogicalView Then
Return VSConstants.S_OK
ElseIf VSConstants.LOGVIEWID_Code = rguidLogicalView Then
pbstrPhysicalView = "Code"
Return VSConstants.S_OK
Else
Return VSConstants.E_NOTIMPL
End If
End Function
Private Function Close() As Integer Implements IVsEditorFactory.Close
Return VSConstants.S_OK
End Function
Private Function CreateEditorInstance(ByVal grfCreateDoc As UInteger, ByVal pszMkDocument As String, ByVal pszPhysicalView As String, ByVal pvHier As IVsHierarchy, ByVal itemid As UInteger, ByVal punkDocDataExisting As System.IntPtr, <System.Runtime.InteropServices.Out()> ByRef ppunkDocView As System.IntPtr, <System.Runtime.InteropServices.Out()> ByRef ppunkDocData As System.IntPtr, <System.Runtime.InteropServices.Out()> ByRef pbstrEditorCaption As String, <System.Runtime.InteropServices.Out()> ByRef pguidCmdUI As Guid, <System.Runtime.InteropServices.Out()> ByRef pgrfCDW As Integer) As Integer Implements IVsEditorFactory.CreateEditorInstance
' Initialize out parameters
ppunkDocView = IntPtr.Zero
ppunkDocData = IntPtr.Zero
pguidCmdUI = Constants.FactoryGuid
pgrfCDW = 0
pbstrEditorCaption = Nothing
' Validate input parameters
If (grfCreateDoc And (VSConstants.CEF_OPENFILE Or VSConstants.CEF_SILENT)) = 0 Then Return VSConstants.E_INVALIDARG
Dim pi As ProjectItem = GetProjectItem(pvHier, itemid)
If Not pi Is Nothing Then
If pszPhysicalView = "Code" Then
...
Else
' If the Designer DocData already exists, VS ask user to confirm for a Designer reloading
If Not punkDocDataExisting = IntPtr.Zero Then Return VSConstants.VS_E_INCOMPATIBLEDOCDATA
' Update services
Dim dts As DynamicTypeService = GetService(GetType(DynamicTypeService))
If Not dts Is Nothing Then
' Provide the right type resolution and discovery services
_trs = dts.GetTypeResolutionService(pvHier)
_tds = dts.GetTypeDiscoveryService(pvHier)
End If
' Create the document (editor)
Dim ds As New DesignSurface(Me)
ds.BeginLoad(New MyDesignerLoader(pi))
Dim NewEditor As New MyEditorPane(ds)
ppunkDocView = Marshal.GetIUnknownForObject(NewEditor)
ppunkDocData = Marshal.GetIUnknownForObject(NewEditor)
pbstrEditorCaption = ""
End If
End If
Return VSConstants.S_OK
End Function
#End Region
#Region "Dispose"
Public Sub Dispose() Implements IDisposable.Dispose
If Not _ServiceProvider Is Nothing Then _ServiceProvider.Dispose()
End Sub
#End Region
End ClassThanks for any help on that poorly documented part !