I have a custom item template that I am adding to a Sharepoint project. I need to ensure that my modules are only associated with my feature, even if the project already contains other features.
Replacing IDs in projectItemReference elements within .feature files is trivial to do by modifying the replacementsDictionary in the RunStarted method.
For example, I have the following SampleModule_WebParts.feature file:
<?xml version="1.0" encoding="utf-8"?>
<feature xmlns:dm0="http://schemas.microsoft.com/VisualStudio/2008/DslTools/Core" dslVersion="1.0.0.0" Id="$SampleFeatureID$" activateOnDefault="false" description="Sample Web Part" featureId="$SampleFeatureID$" scope="Site" solutionId="00000000-0000-0000-0000-000000000000" title="Contoso Intranet Sample Module Web Parts" version="" deploymentPath="$SharePoint.Project.FileNameWithoutExtension$_$SharePoint.Feature.FileNameWithoutExtension$" xmlns="http://schemas.microsoft.com/VisualStudio/2008/SharePointTools/FeatureModel">
<projectItems>
<projectItemReference itemId="$SampleModuleID$" />
</projectItems>
</feature>
Replacing $SampleModuleID$ and $SampleFeatureID$ by modifying the replacementsDictionary in the IWizard.RunStarted method is trivial. But how can I modify the generated .csproj file snippet?
<None Include="Features\SampleModule_WebParts\SampleModule_WebParts.feature">
<FeatureId>{78185D58-6398-4ED2-B0D0-3DC20946FF8F}</FeatureId>
</None>
<Compile Include="SPItems\SampleModule\SampleWebPart\SampleWebPart.cs" />
<Compile Include="SPItems\SampleModule\SampleWebPart\SampleWebPartUserControl.ascx.cs">
<DependentUpon>SampleWebPartUserControl.ascx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="SPItems\SampleModule\SampleWebPart\SampleWebPartUserControl.ascx.designer.cs">
<DependentUpon>SampleWebPartUserControl.ascx.cs</DependentUpon>
</Compile>
<None Include="SPItems\SampleModule\SampleWebPart\SampleWebPart.webpart" />
<None Include="SPItems\SampleModule\SampleWebPart\SharePointProjectItem.spdata">
<SharePointProjectItemId>{D982D304-E7FB-4E8C-899B-7D4096A55892}</SharePointProjectItemId>
</None>
In this case, I’d need to set the FeatureId and SharePointProjectItemId properties for the .feature and .spdata items. If I don’t do anything, Visual Studio will autogenerate those GUIDs, but they won’t match what I have in my replacementsDictionary. And that in turn leads to a broken reference in my .feature file and my module may get associated with the wrong feature.
How can I set those custom properties so that they are persisted into the .csproj file when the user saves it? IWizard.ProjectItemFinishedGenerating seems like the correct method to implement and I can inspect the ProjectItem parameter to figure out when the .spdata and .feature files have been generated, but what should I do there to set the FeatureId and SharePointProjectItemId properties?
The solution was to convert the
Projectreference into anISharePointProjectand callingISharepointProject.Synchronize(). After that I could traverse the SharePoint project’s object model.After finding the my module and my feature from the collections returned by the
ProjectItemsandFeaturesproperties, I could simply associate the module with the feature:Because I can fix the references programmatically, I can leave the old module GUID in the
.featurefile and clean up the invalid association by modifying thesampleFeature.Model.ProjectItemscollection.Finally, I need to remove my module from any other features that the project might have, because Visual Studio automatically associates a new module with the first feature with an appropriate scope.