Skip to content

Commit

Permalink
Add sample for Settings API
Browse files Browse the repository at this point in the history
  • Loading branch information
Charles Willis committed Aug 20, 2024
1 parent 2331763 commit 4936780
Show file tree
Hide file tree
Showing 10 changed files with 525 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"SettingsSample.MyToolWindowCommand.DisplayName": "Sample Text Tool Window",
"SettingsSample.Settings.Category.DisplayName": "Settings Sample",
"SettingsSample.Settings.Category.Description": "Settings for the LoremIpsum sample generator.",
"SettingsSample.Settings.AutoUpdate.DisplayName": "Auto Update",
"SettingsSample.Settings.AutoUpdate.Description": "Whether to update the sample text when a setting changes.",
"SettingsSample.Settings.TextLength.DisplayName": "Text Length",
"SettingsSample.Settings.TextLength.Description": "Number of characters to include in the generated text.",
"SettingsSample.Settings.QuoteStyle.DisplayName": "Quote Style",
"SettingsSample.Settings.QuoteStyle.Description": "Style of quotes to enclose the generated text.",
"SettingsSample.Settings.QuoteStyle.None": "None",
"SettingsSample.Settings.QuoteStyle.Single": "Single",
"SettingsSample.Settings.QuoteStyle.Double": "Double"
}
49 changes: 49 additions & 0 deletions New_Extensibility_Model/Samples/SettingsSample/MyToolWindow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace SettingsSample;

using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.Commands;
using Microsoft.VisualStudio.Extensibility.ToolWindows;
using Microsoft.VisualStudio.RpcContracts.RemoteUI;

/// <summary>
/// A sample tool window.
/// </summary>
[VisualStudioContribution]
public class MyToolWindow : ToolWindow
{
private object? dataContext;

/// <summary>
/// Initializes a new instance of the <see cref="MyToolWindow" /> class.
/// </summary>
public MyToolWindow()
{
this.Title = "Settings Sample Tool Window";
}

/// <inheritdoc />
public override ToolWindowConfiguration ToolWindowConfiguration => new()
{
Placement = ToolWindowPlacement.DocumentWell,
AllowAutoCreation = false,
};

/// <inheritdoc />
public override Task InitializeAsync(CancellationToken cancellationToken)
{
this.dataContext = new MyToolWindowData(this.Extensibility);

return Task.CompletedTask;
}

/// <inheritdoc />
public override Task<IRemoteUserControl> GetContentAsync(CancellationToken cancellationToken)
{
return Task.FromResult<IRemoteUserControl>(new MyToolWindowControl(this.dataContext));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace SettingsSample;

using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.Commands;

/// <summary>
/// A sample command for showing a tool window.
/// </summary>
[VisualStudioContribution]
public class MyToolWindowCommand : Command
{
/// <inheritdoc />
public override CommandConfiguration CommandConfiguration => new("%SettingsSample.MyToolWindowCommand.DisplayName%")
{
Placements = [CommandPlacement.KnownPlacements.ToolsMenu],
Icon = new(ImageMoniker.KnownValues.ToolWindow, IconSettings.IconAndText),
};

/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
await this.Extensibility.Shell().ShowToolWindowAsync<MyToolWindow>(activate: true, cancellationToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace SettingsSample;

using System.Threading;
using Microsoft.VisualStudio.Extensibility.UI;

/// <summary>
/// A sample remote user control to use as tool window UI content.
/// </summary>
internal class MyToolWindowControl : RemoteUserControl
{
/// <summary>
/// Initializes a new instance of the <see cref="MyToolWindowControl" /> class.
/// </summary>
/// <param name="dataContext">
/// Data context of the remote control which can be referenced from xaml through data binding.
/// </param>
/// <param name="synchronizationContext">
/// Optional synchronizationContext that the extender can provide to ensure that <see cref="IAsyncCommand"/>
/// are executed and properties are read and updated from the extension main thread.
/// </param>
public MyToolWindowControl(object? dataContext, SynchronizationContext? synchronizationContext = null)
: base(dataContext, synchronizationContext)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<DataTemplate xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vs="http://schemas.microsoft.com/visualstudio/extensibility/2022/xaml"
xmlns:styles="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.15.0"
xmlns:colors="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0">
<Border Background="{DynamicResource {x:Static colors:EnvironmentColors.ToolWindowBackgroundBrushKey}}"
TextElement.Foreground="{DynamicResource {x:Static colors:EnvironmentColors.ToolWindowTextBrushKey}}"
Padding="5">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock Margin="0,0,5,0"
Text="Sample Text:"
VerticalAlignment="Center" />
<TextBlock x:Name="SampleTextBlock"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding SampleText, Mode=OneWay}"
Style="{StaticResource {x:Static styles:VsResourceKeys.TextBlockEnvironment155PercentFontSizeStyleKey}}">
</TextBlock>
<Button x:Name="UpdateButton"
Content="Update Sample Text From Settings"
IsEnabled="{Binding ManualUpdate}"
Margin="0,10,0,0"
MinHeight="25"
MinWidth="60"
Style="{StaticResource {x:Static styles:VsResourceKeys.ButtonStyleKey}}"
Command="{Binding UpdateCommand}" />
</StackPanel>
</Border>
</DataTemplate>
131 changes: 131 additions & 0 deletions New_Extensibility_Model/Samples/SettingsSample/MyToolWindowData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace SettingsSample;

using System;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.Settings;
using Microsoft.VisualStudio.Extensibility.UI;
using Microsoft.VisualStudio.Threading;

/// <summary>
/// A sample data context object to use with tool window UI content.
/// </summary>
[DataContract]
internal class MyToolWindowData : NotifyPropertyChangedObject
{
internal static readonly string LoremIpsumText = """
Lorem ipsum dolor sit amet consectetur adipiscing elit dignissim lacinia donec,
praesent diam ac mattis morbi nisi dictum dapibus. Convallis natoque interdum
curabitur malesuada tellus aliquam dignissim hendrerit tempor, primis sem nulla
neque cubilia rutrum mollis nisl, eleifend imperdiet lacinia fames gravida sed mus
magnis. Pretium aliquet consequat curabitur eros eleifend praesent, nostra malesuada
hendrerit ornare volutpat, cubilia aptent at mollis convallis.
""";

private readonly VisualStudioExtensibility extensibility;
private string sampleText = LoremIpsumText;
private bool manualUpdate = false;

/// <summary>
/// Initializes a new instance of the <see cref="MyToolWindowData" /> class.
/// </summary>
/// <param name="extensibility">
/// Extensibility object instance.
/// </param>
public MyToolWindowData(VisualStudioExtensibility extensibility)
{
this.extensibility = Requires.NotNull(extensibility, nameof(extensibility));

this.UpdateCommand = new AsyncCommand(this.UpdateAsync);

this.InitializeSettingsAsync(extensibility).Forget();
}

/// <summary>
/// Gets the async command used to show a message prompt.
/// </summary>
[DataMember]
public IAsyncCommand UpdateCommand
{
get;
}

/// <summary>
/// Gets or sets a value indicating whether the user must
/// click the "Update" button to refresh the sample text.
/// </summary>
[DataMember]
public bool ManualUpdate
{
get => this.manualUpdate;
set => this.SetProperty(ref this.manualUpdate, value);
}

/// <summary>
/// Gets or sets the message to display in the message prompt.
/// </summary>
[DataMember]
public string SampleText
{
get => this.sampleText;
set => this.SetProperty(ref this.sampleText, value);
}

#pragma warning disable VSEXTPREVIEW_SETTINGS // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.

private async Task InitializeSettingsAsync(VisualStudioExtensibility extensibility)
{
await extensibility.Settings().SubscribeAsync(
[SettingDefinitions.SettingsSampleCategory],
CancellationToken.None,
values =>
{
if (values.TryGetValue(SettingDefinitions.AutoUpdateSetting.FullId, out ISettingValue? autoUpdateValue))
{
this.ManualUpdate = !autoUpdateValue.Value<bool>();
}

if (!this.ManualUpdate)
{
this.UpdateSampleTextFromSettings(values);
}
});
}

private async Task UpdateAsync(object? commandParameter, CancellationToken cancellationToken)
{
SettingValues values = await this.extensibility.Settings().ReadEffectiveValuesAsync(
[SettingDefinitions.SettingsSampleCategory],
cancellationToken);

this.UpdateSampleTextFromSettings(values);
}

private void UpdateSampleTextFromSettings(SettingValues values)
{
string text = LoremIpsumText;

if (values.TryGetValue(SettingDefinitions.TextLengthSetting.FullId, out ISettingValue? textLengthValue))
{
int length = textLengthValue.Value<int>();
text = LoremIpsumText[..Math.Min(length, LoremIpsumText.Length)];
}

if (values.TryGetValue(SettingDefinitions.QuoteStyleSetting.FullId, out ISettingValue? quoteStyleValue))
{
this.SampleText = quoteStyleValue.Value<string>() switch
{
"single" => $"'{text}'",
"double" => $"\"{text}\"",
_ => text,
};
}
}
#pragma warning restore VSEXTPREVIEW_SETTINGS // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
}
Loading

0 comments on commit 4936780

Please sign in to comment.