ReSharper doesn’t have a really clean way of getting at this information right now (there are new APIs in 9.0 to access and cache arbitrary properties from msbuild files). You have two options. You can implement IProjectFileDataCache, which allows you to extract data from the msbuild xml file and cache it. This is quite simple – take a look at ShouldUseHostCompilerProvider for a good example.
The downside is that it doesn’t help with properties that have a condition applied to them – it just provides the raw xml of the msbuild file. From your example, it looks like this will be ok for you. If you do need to get at a property that is conditional, you can use ProjectModelSynchronizer.GetProjectInfoByProject(iproject) to return an instance of VSProjectInfo. From here, you can use the VsHierarchy property to get at the Visual Studio defined IVsHierarchy interface. This is Visual Studio’s representation of the items in a project, including files, folders and references – it maps to the solution explorer, essentially. From this, you can use the MSBuildExtensions.GetBoolValue extension method to retrieve a build property.
Regards
Matt
--
Matt Ellis
Technical Evangelist
JetBrains
“Develop with pleasure!”
--
You received this message because you are subscribed to the Google Groups "resharper-plugins" group.
To unsubscribe from this group and stop receiving emails from it, send an email to resharper-plug...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
public static bool IsSandbox(this IProject project)
{
bool result = false;
if (project.ProjectFile != null)
using (Stream stream = project.ProjectFile.CreateReadStream())
{
XDocument document = XDocument.Load(stream);
XElement sandboxedSolutionNode = document.Descendants().FirstOrDefault(p => p.Name.LocalName == "SandboxedSolution");
if (sandboxedSolutionNode != null && !String.IsNullOrEmpty(sandboxedSolutionNode.Value))
result = sandboxedSolutionNode.Value.ToLower() == "true";
}
return result;
}
It might be worth switching to IProjectFileDataCache. This prevents the need to re-read the file – ReSharper already has it loaded, and you’ll be notified when the file changes, otherwise you can use your cached value.
Matt
public Action OnDataChanged(IProjectFile projectFile, object oldData, object newData)
{
if (oldData != null)
{
bool oldValue = (bool)oldData;
bool newValue = (bool)newData;
if (newValue != oldValue)
return () => myLocks.ExecuteWithWriteLock(() =>
{
IProject project = projectFile.GetProject();
Assertion.AssertNotNull(project, "project must not be null");
ProjectModelChangeUtil.OnChange(projectFile.GetSolution().BatchChangeManager,
new ProjectItemChange(EmptyList<ProjectModelChange>.InstanceList, project,
project.ParentFolder, ProjectModelChangeType.PROPERTIES, project.Location,
project.GetPersistentID()));
});
}
return null;
}
You should implement OnDataChanged only if you need to do something when the data changes. E.g., if you need to re-run some analyses when the sandbox value changes, you should handle that in OnDataChanged. If there’s no way for the user to change this value while the project is open, then I suspect it’ll be fine to ignore the method and just return null.
The way the IProjectFileDataCache works is like this:
1. In your constructor, inject a ProjectFileDataCache instance, store it in a field and call cache.RegisterCache(lifetime, this)
2. Implement CanHandle to see if you should handle the project file (e.g. get the project and check to see if it’s sharepoint)
3. BuildData is called with the xml of the project file, you return an object that represents your cached value(s). This could be a boolean, or a class. Don’t store anything in your class fields. ReSharper will cache this value
4. If the object instance is different to the previously cached instance, your OnDataChanged method is called. You can decide what needs to happen in response to this change, and you should return it as an action that will get executed later (after all processing of the file completes)
5. ReSharper will call your Write method, passing in the cached object. You serialise this to the BinaryWriter however you want to
6. ReSharper will also call Read method at the appropriate time, and you should use the Binary Reader to recreate the object that you need to cache. Again, don’t store anything in class fields here
7. To get at your cached data, call projectFileDataCache.GetData(this, project, default), passing in the project and a default value for your cached object (true/false, complex object, etc)
ProjectModelChangeUtil.OnChange is just a helper function that will batch up changes to the change manager. It ensures that all changes are “propagated”, e.g. if given a change notification for a project item, it makes sure that gets propagated up to the project itself. It then uses IProjectModelBatchChangeManager to post the notification, which will either add the change to a current transaction, or execute it in its own, new transaction. I.e. the change happens as part of a new batch, of gets added to the existing batch. The batch manager then posts it to the change manager, which is an event bus that components can subscribe to in order to be notified of changes.
You can see the change manager subscriptions as a graph from the internal menu (ReSharper -> Internal -> View Change Manager Graph). This will create and try to open a .graphml file, which you can view with a tool like yEd (you’ll need to reformat it in hierarchical layout to be any use). You can see how events will flow from one component to another. Once one component accepts a change, it can create a new change and broadcast it. For example the solution will broadcast “project model change” events such as when a reference is added or removed. Various components will subscribe to these events, and convert them to PSI events, which are published to any subscribers, and used to add assembly metadata to the PSI cache, to populate code completion, etc.
Unless you’re adding new subscribers, or need to notify existing components of a project change, you probably don’t need to do anything here.
Regards