Finishing the Package

The package class already has all the basic code we need; with the user control/tool window UI and code finished, we are essentially done. If we run our package at this stage, a sandbox copy of Visual Studio will start up with the package loaded. We just need to know how to trigger our tool window to display. The launching code is already there inside the ShowToolWindow routine.


Note

A tool window, in Visual Studio parlance, is nothing more than a simple window that can be docked or floated within the IDE.


The custom tool window project item has already provided us with a straightforward routine that will display a tool window. This routine is already wired up to a menu command, and it is already configured to display our custom user control within the tool window. For reference, here is the default implementation you’ll find within the package class.

/// <summary>
/// This function is called when the user clicks the
/// menu item that shows the tool window. See the
/// Initialize method to see how the menu item is
/// associated to this function using the
/// OleMenuCommandService service and the MenuCommand class.
/// </summary>
private void ShowToolWindow(object sender, EventArgs e)
{
    //Get the instance number 0 of this tool window.
    //This window is single instance, so this instance
    //is actually the only one.
    //The last flag is set to true so that if the tool
    //window does not exist, it will be created.
    ToolWindowPane window = this.FindToolWindow(typeof(MyToolWindow), 0, true);

    if ((null == window) || (null == window.Frame))
    {
        throw new NotSupportedException(Resources.CanNotCreateWindow);
    }

    IVsWindowFrame windowFrame = (IVsWindowFrame)window.Frame;
    Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(windowFrame.Show());
}

The VSCT file has been built for you; here is the snippet inside the .vsct file that wires the command to show the tool window to a menu item and places it inside the Other Windows menu.

  <Button guid="guidColorSelectorCmdSet" id="cmdidColorSelectorToolWindow"
          priority="0x0100" type="Button">
    <Parent guid="guidSHLMainMenu" id="IDG_VS_WNDO_OTRWNDWS1"/>
    <Icon guid="guidImages" id="bmpPic1" />
    <Strings>
      <ButtonText>Color Selector Tool Window</ButtonText>
    </Strings>
  </Button>

If you examine the Parent element, you will see an id attribute set to IDG_VS_WNDO_OTRWNDWS1. This is a constant that references the standard Other Windows menu within Visual Studio. There are predefined GUIDs and IDs for every standard Visual Studio menu. Visit MSDN and search for “GUIDs and IDs of Visual Studio Menus” for the full reference.

Our package is fully functional. Figure 15.10 shows the package UI running as a tool window within an instance of Visual Studio. Listings are provided next for the key components of the tool window: Listing 15.4 provides the tool window extension code, and Listings 15.5 and 15.6 provide the XAML and code-behind (respectively) for the tool window control itself.

Image

FIGURE 15.10 The ColorSelector package running in Visual Studio.

LISTING 15.4 The ColorSelectorPackage Class


using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.ComponentModel.Design;
using Microsoft.Win32;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;

namespace VisualStudioUnleashed.ColorSelector
{
    /// <summary>
    /// This is the class that implements the package exposed by this
    /// assembly.
    ///
    /// The minimum requirement for a class to be considered a valid package
    /// for Visual Studio is to implement the IVsPackage interface and register
itself
    /// with the shell. This package uses the helper classes defined in the
    /// Managed Package Framework (MPF) to do it: it derives from the
    /// Package class that provides the implementation of the IVsPackage
    /// interface and uses the registration attributes defined in the
    /// framework to register itself and its components with the shell.
    /// </summary>
    //This attribute tells the PkgDef creation utility (CreatePkgDef.exe)
    //that this class is a package.
    [PackageRegistration(UseManagedResourcesOnly = true)]
    //This attribute is used to register the information needed to show
    //this package in the Help/About dialog of Visual Studio.
    [InstalledProductRegistration("#110", "#112", "1.0",
        IconResourceID = 400)]
    //This attribute is needed to let the shell know that this package
    //exposes some menus.
    [ProvideMenuResource("Menus.ctmenu", 1)]
    //This attribute registers a tool window exposed by this package.
    [ProvideToolWindow(typeof(MyToolWindow))]
    [Guid(GuidList.guidColorSelectorPkgString)]
    public sealed class ColorSelectorPackage : Package
    {
        /// <summary>
        /// Default constructor of the package.
namespace ColorSelectorExtension
{
    using System;
    using System.Runtime.InteropServices;
    using Microsoft.VisualStudio.Shell;

    /// <summary>
    /// This class implements the tool window exposed by this package
    /// and hosts a user control.
    /// </summary>
    /// <remarks>
    /// In Visual Studio, tool windows are composed of a frame
    /// (implemented by the shell) and a pane,
    /// usually implemented by the package implementer.
    /// <para>
    /// This class derives from the ToolWindowPane class provided
    /// from the MPF in order to use its
    /// implementation of the IVsUIElementPane interface.
    /// </para>
    /// </remarks>
    [Guid("a320ef24-e22a-41de-9d6b-7eece4f50e61")]
    public class ColorSelectorToolWindow : ToolWindowPane
    {
        /// <summary>
        /// Initializes a new instance of the
        /// <see cref="ColorSelectorToolWindow"/> class.
        /// </summary>
        public ColorSelectorToolWindow() : base(null)
        {
            this.Caption = "ColorSelectorToolWindow";

            //Set the image that will appear on the tab of the
            //window frame when docked with another window.
            //The resource ID corresponds to the one defined
            //in the resx file, while the Index is the offset
            //in the bitmap strip. Each image in the strip
            //is 16x16.
            this.BitmapResourceID = 301;
            this.BitmapIndex = 1;

            //This is the user control hosted by the tool
            //window; note that, even if this class implements
            //IDisposable, we are not calling Dispose on this object.
            //This is because ToolWindowPane calls Dispose on
            //the object returned by the Content property.
            this.Content = new ColorSelectorToolWindowControl();
        }
    }
}


LISTING 15.5 The UserControl XAML


<UserControl x:Class="ColorSelectorExtension.ColorSelectorToolWindowControl "
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   Background="{DynamicResource VsBrush.Window}"
   Foreground="{DynamicResource VsBrush.WindowText}"
   mc:Ignorable="d"
   d:DesignHeight="350" d:DesignWidth="300"
   Name="MyToolWindow">
    <Grid>
        <StackPanel Orientation="Vertical">
            <TextBlock Margin="10" HorizontalAlignment="Center">
            Color Selector Tool Window</TextBlock>
            <Image Name="ImagePalette" Source="color-spectrum.jpg"
             Margin="10" MouseMove="ImagePalette_MouseMove"
             MouseDown="ImagePalette_MouseDown" />
            <TextBlock Name="TextBlockRGB" HorizontalAlignment="Center"
            Margin="10">(R, G, B values)</TextBlock>
            <Border Name="BorderSelectedColor" Height="25"
             Margin="10,0,10,10" Background="Transparent" />
            <TextBlock Name="TextBlockCode" HorizontalAlignment="Center"
             Margin="10">(code goes here)</TextBlock>
        </StackPanel>

    </Grid>
</UserControl>


LISTING 15.6 The UserControl Code Behind (C#)


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace VisualStudioUnleashed.ColorSelector
{
    /// <summary>
    /// Interaction logic for MyControl.xaml
    /// </summary>
    public partial class MyControl : UserControl
    {

        public MyControl()
        {
            InitializeComponent();
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization",
"CA1300:SpecifyMessageBoxOptions")]

        private Color GetPointColor()
        {
            //Retrieve the coordinate of the mouse position in relation to
            //the window.
            Point point = Mouse.GetPosition(this);

            //Use RenderTargetBitmap to get the visual, in case the
            //image has been transformed.
            var renderTargetBitmap =
                new RenderTargetBitmap((int)this.ActualWidth,
                    (int)this.ActualHeight,
                    96, 96, PixelFormats.Default);
            renderTargetBitmap.Render(this);

            //Make sure that the point is within the dimensions of the
            //image.
            if ((point.X <= renderTargetBitmap.PixelWidth)
                && (point.Y <= renderTargetBitmap.PixelHeight))
            {
                //Create a cropped image at the supplied point coordinates.
                var croppedBitmap =
                    new CroppedBitmap(renderTargetBitmap,
                        new Int32Rect((int)point.X, (int)point.Y, 1, 1));

                //Copy the sampled pixel to a byte array.
                var pixels = new byte[4];
                croppedBitmap.CopyPixels(pixels, 4, 0);

                //Assign the sampled color to a SolidColorBrush and
                //return as conversion.
                Color SelectedColor =
                    Color.FromRgb(pixels[2], pixels[1], pixels[0]);

                return SelectedColor;
            }
            else
            {
                return Colors.Black;
            }

        }

        private void ImagePalette_MouseMove(object sender, MouseEventArgs e)
        {
            //Get the color under the current pointer position
            UIElement SelectedObject = e.Source as UIElement;

            Color color = GetPointColor();

            DisplayColor(color);
            DisplayCode(color, false);

        }

        /// <summary>
        /// Given a Color struct, update the UI controls
        /// to show the RGB values, and repeat the selected
        /// color within the BorderSelectedColor control.
        /// </summary>
        /// <param name="color">The current color under
        /// the mouse cursor.</param>
        private void DisplayColor(Color color)
        {
            //Set the border color to match
            //the selected color
            SolidColorBrush brush =
                        new SolidColorBrush(color);

            BorderSelectedColor.Background = brush;


            //Display the RGB values
            string rgb = color.R.ToString() + ", "
                        + color.G.ToString() + ", "
                        + color.B.ToString();

            TextBlockRGB.Text = rgb;

        }

        /// <summary>
        /// Display the VB or C# code to implement the
        /// provided color
        /// </summary>
        /// <param name="color">The color to implement</param>
        /// <param name="isVB">True to generate VB; false
        /// for C#</param>
        private void DisplayCode(Color color, bool isVB)
        {

            string code = "";

            if (isVB)
            {
                code = "Dim color As Color = ";
            }
            else
            {
                code = "Color color = ";
            }

            code = code + @"Color.FromArgb(" + color.R.ToString() + ", " +
                color.G.ToString() + ", " +
                color.B.ToString() + ");";

            _code = code;
            TextBlockCode.Text = _code;

        }

        private void ImagePalette_MouseDown(object sender, MouseButtonEventArgs e)
        {
            //On mouse click within the palette, copy
            //the Color code to the Clipboard
            Clipboard.Clear();
            Clipboard.SetText(TextBlockCode.Text);
        }
    }
}



Note

If you have previously written Visual Studio add-ins, it is a relatively straightforward conversion process to turn those into package extensions. Search MSDN for the article titled “Converting Add-Ins to VSPackage Extensions.”


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset