Inside Microsoft® Visual Studio® .NET 2003 [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Inside Microsoft® Visual Studio® .NET 2003 [Electronic resources] - نسخه متنی

Brian Johnson

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید










Creating Custom Tool Windows


As you know, most of the windows in Visual Studio .NET have an object model that you can use to program the contents and present data that your code generates. However, at times you might need to display data in a way that the existing tool windows cannot handle. To allow you to display data in a way that is most suitable for your add-in, the Visual Studio .NET object model allows creation of custom tool windows.

To create a tool window, all you need is an ActiveX control and an add-in that makes a call to the Windows.CreateToolWindow method. CreateToolWindow has the following method signature:


public EnvDTE.Window CreateToolWindow(EnvDTE.AddIn AddInInst,
string ProgID,
string Caption,
string GuidPosition,
ref object DocObj)

This method returns a Window object that behaves like any tool window that Visual Studio .NET creates. Here are the arguments for this method:

AddInInst

An add-in object that's the sponsor of the tool window. When the sponsor add-in is unloaded, all tool windows associated with that add-in are automatically closed and the ActiveX control is unloaded.

ProgID

The ProgID of the ActiveX control that's hosted on the newly created tool window.

Caption

The text to show in the title bar of the new tool window.

GuidPosition

A GUID in string format. As you'll recall, the Windows.Item method can be indexed by a GUID, and that GUID uniquely identifies a specific window. The GUID assigned to your tool window and the GUID passed to the Windows.Item method are set using this parameter. This GUID must be different from the GUID used by other tool windows; if you call CreateToolWindow multiple times, you must use a different GUID for each window.

DocObject

Most ActiveX controls have a programmable object in the form of a COM IDispatch interface, which is mapped to a System.Object when you're using the .NET Framework. The programmable object of the ActiveX control is passed back to the caller through this parameter, which allows you to program the control as you would any other tool window. You can also retrieve the programmable object of the ActiveX control by calling the Object property of the Window object for the tool window that's created using the CreateToolWindow method.


To demonstrate using the CreateToolWindow method, the samples that accompany this book include an add-in project called VSMediaPlayer. This sample creates a tool window using Windows Media Player as the ActiveX control and then, by using the programmable object of the control, plays an audio file. The code that does the work of creating the tool window looks like this:


void CreateMediaPlayerToolWindow()
{
EnvDTE.Windows windows;
EnvDTE.Window mediaPlayerWindow;
object controlObject = null;
string mediaPlayerProgID = "MediaPlayer.MediaPlayer";
string toolWindowCaption = "Windows Media Player";
string toolWindowGuid = "{AB5E549E-F823-44BB-8161-BE2BD5D698D8}";
//Create and show a tool window that hosts the
// Windows Media Player control:
windows = applicationObject.Windows;
mediaPlayerWindow = windows.CreateToolWindow(addInInstance,
mediaPlayerProgID,
toolWindowCaption,
toolWindowGuid,
ref controlObject);
mediaPlayerWindow.Visible = true;
//Play the Windows "Tada" sound:
//Can only get the system directory (Eg: C:\windows\system32),
// need to change this to the Windows install dir
string mediaFile = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.System);
mediaFile += "\\..\\media\\tada.wav";
MediaPlayer.IMediaPlayer2 mediaPlayer =
(MediaPlayer.IMediaPlayer2)controlObject;
mediaPlayer.AutoStart = true;
mediaPlayer.FileName = mediaFile;
}

The CreateMediaPlayerToolWindow method is called in two places in the sample add-inonce in the OnConnection method and once in the OnStartupComplete method. It must be called twice because of the way add-ins are loaded by Visual Studio .NET. If an add-in is set to load on startup, when Visual Studio .NET starts, the add-in starts loading. This loading process includes calling the OnConnection method. But the OnConnection method is called just before the Visual Studio .NET main window is created and shown. If you call the CreateToolWindow method within OnConnection before the main window is shown, creating the tool window will fail because creating an ActiveX control requires its parent window to be visible. You can check to make sure that the main window has been created by examining the connectMode argument passed to the OnConnection method. If this is set to ext_cm_AfterStartup, the add-in was loaded through the Add-in Manager or by means other than the load on startup flag being set and Visual Studio .NET being started. Therefore, the tool window can be shown when an add-in is loaded using an OnConnection implementation such as this:


public void OnConnection(object application,
Extensibility.ext_ConnectMode connectMode, object addInInst,
ref System.Array custom)
{
applicationObject = (_DTE)application;
addInInstance = (AddIn)addInInst;
//If the add-in is loaded from the Add-in Manager dialog, then
// create and show the tool window:
if(connectMode == Extensibility.ext_ConnectMode.ext_cm_AfterStartup)
{
CreateMediaPlayerToolWindow();
}
}

If the load on startup flag is set and you want to show the tool window when an add-in is loaded, you can create the window in the OnStartupComplete method. This method is called when initialization of Visual Studio .NET is complete, which includes creating and showing the main window. It's as simple as this code snippet:


public void OnStartupComplete(ref System.Array custom)
{
//If the add-in is loaded at startup, then
// create and show the tool window:
CreateMediaPlayerToolWindow();
}

The CreateToolWindow method can be a powerful aid in creating an add-in's user interface, but it does add one complication. As mentioned earlier, when a tool window is created, an ActiveX control is instantiated and hosted within the new window; but ActiveX controls cannot be created using the .NET Framework. To allow use of a .NET user control within a tool window, you need a shim control.


Shim Controls


To enable hosting of a .NET Framework user control in a tool window, you can use a specialized ActiveX control called a shim control. A shim control is simply an ActiveX control written in an unmanaged language (such as Visual C++) that creates an instance of the .NET common language runtime (CLR). Using a small amount of code, you can direct the instance of the CLR to create the user control to display in the tool window and then parent the control onto the shim ActiveX control. You can add new user controls to an existing project by choosing Project | Add User Control, or you can create a new Windows Control Library project, which will create a user control object.

The book's sample files include an implementation of a shim control called VSUserControlHost and a sample that uses the shim control, CSHostedControl. To create and host an instance of a user control on a tool window, two steps are needed. First, to host the shim ActiveX control in a tool window, you call the CreateToolWindow method, supplying the ProgID of the shim, as shown in this line of code taken from the CSHostedControl sample:


toolWindow = applicationObject.Windows.CreateToolWindow(addInInstance,
"VSUserControlHost.VSUserControlHostCtl", "C# Hosted Control",
"{C4E8F504-E3FB-4828-82F4-DDD1CAE13D39}", ref obj);

The next step is to tell the shim control where the Windows control can be found and the name of the class that implements the control. You do this through the VSUserControlHostLib.IVSUserControlHostCtl interface, which you can obtain by casting the programmatic object of the shim control:


shimControl =
(VSUserControlHostLib.IVSUserControlHostCtl)toolWindow.Object;

The IVSUserControlHostCtl interface has four methods that you can call to pass the control's location and class name as well as other bits of information. Here's the signature of the interface:


System.Object HostUserControl(System.String Assembly, System.String Class);
System.Object HostUserControl2(System.Int32 HWnd);

Each of these methods returns the programmable object of the .NET control that's hosted by the shim control. The arguments passed to these methods are as follows:

Assembly

The location of the assembly that contains the control that is to be hosted. This location can be in one of three formats. The first is the full path to the assembly of the user control, such as C:\Assembly.dll. The second format is the URL of an assembly located on a Web server, such as http://localhost/Assembly.dll. The third format is the full name of an assembly located within the GAC, such as System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, Custom=null for the assembly implementing the System.Windows.Forms namespace.

Class

The full name of the class that implements the control that is to be hosted. If the assembly location is the full name of the System.Windows.Form assembly, as given above, and the name of the class is System.Windows.Forms.Button, an instance of the Windows Forms Button object is created and hosted in the tool window.

HWnd

The handle of a .NET control that is to be hosted within the shim control. Using this form of hosting a control is useful if the control has already been created or if the control code is located in the same assembly as the add-in calling CreateToolWindow because you can create the control and pass its window handle rather than passing information such as the location of the assembly and the class name.


Add-in developers commonly add a user control class to an add-in and then place that control on a tool window. You can do this using the shim control in two ways. The first way is to find the location of the assembly that implements the add-in and pass this as the first parameter to the HostUserControl method, as shown here:


VSUserControlHostLib.IVSUserControlHostCtl shimControl;
string assemblyPath;
EnvDTE.Window toolWindow;
object obj = null;
toolWindow = applicationObject.Windows.CreateToolWindow(addInInstance,
"VSUserControlHost.VSUserControlHostCtl", "Hosted Control",
"{A71654EC-A72E-40cf-9CD6-63FA3C52C307}", ref obj);
toolWindow.Visible = true;
shimControl =
(VSUserControlHostLib.IVSUserControlHostCtl)toolWindow.Object;
assemblyPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
shimControl.HostUserControl(assemblyPath, "MyAddin1.UserControl1");

The second way is to instantiate the control directly and pass the control's window handle to the HostUserControl2 method:


VSUserControlHostLib.IVSUserControlHostCtl shimControl;
string assemblyPath;
EnvDTE.Window toolWindow;
object obj = null;
toolWindow = applicationObject.Windows.CreateToolWindow(addInInstance,
"VSUserControlHost.VSUserControlHostCtl", "Hosted Control",
"{A71654EC-A72E-40cf-9CD6-63FA3C52C307}", ref obj);
toolWindow.Visible = true;
shimControl =
(VSUserControlHostLib.IVSUserControlHostCtl)toolWindow.Object;
assemblyPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
UserControl1 uc = new UserControl1();
shimControl.HostUserControl3(uc.Handle.ToInt32());


Lab: Setting Up a Web Server to Host a User Control for a Tool Window


The HostUserControl method of the shim control takes as its first argument the full path to a .NET Framework user control on disk, the full name of an assembly in the computer's GAC, or a URL to a control that's on a Web server. If you put a user control for a tool window on a Web server, you can modify the control to provide new functionality and bug fixes to the user, but the user must connect to the Internet to download the control. If the user isn't connected to the Internet or if your Web server is down when a request for the control is made and the control has previously been downloaded, the control is loaded from the computer's download cache.

You can use the Microsoft Internet Information Services (IIS) Web server running on your computer as a test server. To set up your project to place your user control on the Web server, simply right-click on the project for the user control you want to place on a tool window and choose Properties to display the Property Pages dialog box for that project. Select the Configuration Properties | Build node, change the Configuration drop-down list selection to All Configurations, and then enter the path to your IIS Web server directory (usually C:\Inetpub\wwwroot) as the Output Path property. To cause the shim control to load your control from the Web server, change the path to the control from a location on disk or the name of an assembly on disk to http://localhost/assemblyname.dll.

You should keep a few things in mind when you load a control from a Web server. First, any assemblies that the control references, except ones within the GAC of the computer that load the control, must be placed in the same folder on the Web server so the .NET Framework loader can find those references. Second, you can't program the object exposed through the control unless you use the Type.InvokeMember method. This is because of the way the .NET Framework resolves types when methods and properties are invoked. Third, before giving your add-in to a user, you must copy the user control to a server that the user can access and change the URL passed to the HostUserControl method to point to that server.


Setting the Tab Picture of a Custom Tool Window


When two or more tool windows are tab-linked together, an image is displayed so the user can quickly recognize the tool windows that are linked together. Figure 10-6 shows the Macro Explorer, Solution Explorer, and Properties windows docked to one another.


Figure 10-6. The pictures displayed on the tabs of the Macro Explorer, Solution Explorer and Properties windows



To set the tab picture for a tool window that's created by an add-in, you use the Window.SetTabPicture method. SetTabPicture takes as its argument a COM IPictureDisp type, which is mapped to the .NET Framework as a System.Object type. To create an IPictureDisp object, you can use the same technique described earlier of calling the OleLoadPictureFile method and then passing the returned IPictureDisp object to the SetTabPicture method.

The bitmap to place onto a tool window tab must have a specific format, and any deviation from this format can cause the bitmap to appear with incorrect colors or not appear at all. This bitmap must be 16 by 16 pixels, with a color depth of 16. If any portion of the bitmap is to show as transparent, the transparent pixels must have the RGB value 0,254,0. The format for this bitmap is the same format used for displaying custom pictures on command bar buttons (as discussed in Chapter 7); a bitmap can be shared for these two uses.

You can call the Window.SetTabPicture method only on a tool window created using the Windows.CreateToolWindow method. Windows defined by Visual Studio .NET already have their bitmaps set; if you try to change them, an exception will be generated. If you want to set the bitmap for your own tool window, you should set it before setting the Visible property of your window to true; otherwise, the picture might not be displayed immediately. Lastly, if a custom picture is not set, Visual Studio uses a default picturethe Visual Studio .NET logo.


Setting the Selection Object


As you select different windows in Visual Studio .NET, you see the Properties window update itself with properties available for those windows. For example, if you select a file in Solution Explorer, a set of properties is made availablesuch as the file path, when the file was modified, or how the file should be built. When you create a tool window, you might also want to have properties for your tool window appear in the Properties window. You set items to appear in the Properties window using the Window.SetSelectionContainer method, which takes as a parameter an array of type System.Object. These items are displayed in the Properties window when the window that has this method called on it becomes the active window. The sample VSMediaPlayerAdv, an extension to the VSMediaPlayer sample, displays a property set in the Properties window by calling the SetSelectionContainer method with the programmable object of Windows Media Player, which was returned through the DocObj parameter of the CreateToolWindow method. This portion of code shows how this is done:


object []propertiesWindowObjects = {mediaPlayer};
mediaPlayerWindow.SetSelectionContainer(ref propertiesWindowObjects);

You can call the SetSelectionContainer method only on tool windows that you create. If you call this method on a Window object for, say, the Solution Explorer tool window, an exception will be generated.


/ 118