-
Notifications
You must be signed in to change notification settings - Fork 391
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Rules from code #7685
Add Rules from code #7685
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE.md file in the project root for more information. | ||
|
||
using System; | ||
using System.ComponentModel.Composition; | ||
using System.Threading.Tasks; | ||
using Microsoft.Build.Framework.XamlTypes; | ||
using Microsoft.VisualStudio.ProjectSystem.Properties; | ||
|
||
namespace Microsoft.VisualStudio.ProjectSystem.Rules.PropertyPages | ||
{ | ||
/// <remarks> | ||
/// We want to provide certain rules when the "MyCapability" capability is present, but remove them if it goes away. | ||
/// The <see cref="IProjectDynamicLoadComponent"/> is designed specifically for these situations. | ||
/// </remarks> | ||
[Export(ExportContractNames.Scopes.UnconfiguredProject, typeof(IProjectDynamicLoadComponent))] | ||
[AppliesTo("MyCapability")] | ||
internal class PropertyPageRuleProvider : IProjectDynamicLoadComponent | ||
{ | ||
/// <summary> | ||
/// A CPS-provided service that supports adding and removing in-memory <see cref="Rule"/>s. | ||
/// </summary> | ||
private readonly IAdditionalRuleDefinitionsService _additionalRuleDefinitionsService; | ||
/// <summary> | ||
/// Use a <see cref="Lazy{T}"/> so we don't create the <see cref="Rule"/> until we need it. | ||
/// Technically this is unnecessary, since the constructor won't be called until the first | ||
/// time the capabilities are satisified, and <see cref="LoadAsync"/> will be called shortly | ||
/// after that. As such, making this lazy really just makes it very clear that it definitely | ||
/// won't be created until it is needed, and will only be created once. | ||
/// </summary> | ||
private readonly Lazy<Rule> _rule; | ||
|
||
[ImportingConstructor] | ||
public PropertyPageRuleProvider( | ||
IAdditionalRuleDefinitionsService additionalRuleDefinitionsService) | ||
{ | ||
_additionalRuleDefinitionsService = additionalRuleDefinitionsService; | ||
_rule = new Lazy<Rule>(CreateRule); | ||
} | ||
|
||
/// <summary> | ||
/// Called when the specified capabilities are satisfied. | ||
/// We can add our rules. | ||
/// </summary> | ||
public Task LoadAsync() | ||
{ | ||
_additionalRuleDefinitionsService.AddRuleDefinition(_rule.Value, context: "Project"); | ||
|
||
return Task.CompletedTask; | ||
} | ||
|
||
/// <summary> | ||
/// Called when the specified capabilities are no longer satisfied. | ||
/// We can remove our rules. | ||
/// </summary> | ||
public Task UnloadAsync() | ||
{ | ||
_additionalRuleDefinitionsService.RemoveRuleDefinition(_rule.Value); | ||
|
||
return Task.CompletedTask; | ||
} | ||
|
||
private Rule CreateRule() | ||
{ | ||
Rule rule = new(); | ||
|
||
// Rule implements ISupportInitialize; we need to be sure to call BeginInit and EndInit. | ||
rule.BeginInit(); | ||
|
||
// Basic information | ||
|
||
rule.Name = "MyInMemoryPropertyPage"; | ||
rule.Description = "A Rule that is defined in memory and dynamically loaded and unloaded"; | ||
rule.DisplayName = Resources.MyPropertyPage_DisplayName; | ||
rule.PageTemplate = "generic"; | ||
rule.Order = 10; | ||
|
||
// Metadata | ||
|
||
// (no metadata) | ||
|
||
// Categories | ||
|
||
rule.Categories.Add(new Category { Name = "General", DisplayName = "General" }); | ||
rule.Categories.Add(new Category { Name = "OtherSettings", DisplayName = "Other Settings" }); | ||
|
||
// Data source | ||
|
||
rule.DataSource = new DataSource | ||
{ | ||
Persistence = "ProjectFile", | ||
SourceOfDefaultValue = DefaultValueSourceLocation.AfterContext, | ||
HasConfigurationCondition = false, | ||
}; | ||
|
||
// Properties | ||
|
||
rule.Properties.Add(new StringProperty | ||
{ | ||
Name = "MyProperty", | ||
DisplayName = "My Property", | ||
Description = Resources.MyPropertyPage_PropertyDescription, | ||
Category = "OtherSettings" | ||
}); | ||
|
||
rule.EndInit(); | ||
|
||
return rule; | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -194,4 +194,10 @@ This project was loaded using the wrong project type, likely as a result of rena | |
<value>(None)</value> | ||
<comment>Special value to show in the project property pages when a property has no value.</comment> | ||
</data> | ||
<data name="MyPropertyPage_DisplayName" xml:space="preserve"> | ||
<value>My In-Memory Page 😀</value> | ||
</data> | ||
<data name="MyPropertyPage_PropertyDescription" xml:space="preserve"> | ||
<value>🎉 Put anything you want here! It doesn't matter! 🎉</value> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we display emojis in the UI? :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes! Though WPF doesn't color them. |
||
</data> | ||
</root> |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you were doing this for real, you'd want to setup a direct data flow relationship between the capability change and the resulting rules. Otherwise, this is going to result in situations where the project and the rules associated with it are out of sync. You would do that by exporting IAdditionalRuleDefinitionsService and have AdditionalRuleDefinitions property return a data source that changed based on the capabilities changing (you'd need to delegate/listen to underlying IAdditionalRuleDefinitionsService as there can only be one).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We would want to create a new
IAdditionalRuleDefinitionsService
implementation anyway (or augment the existing one) in order to simplify the experience for anyone wishing to createRule
s in this manner. Ideally, they would just associate a set ofRule
s with a capability condition, and the underlying service would handle capability changes and pushing information through the data flow.Is it possible to replace the
IAdditionalRuleDefinitionsService
with a new one? The interface is defined as:So there's only supposed to be exactly one per unconfigured project. Would it be possible to MEF-export a different implementation that would replace it?