|< Free Open Study >|| |
Now that you have seen how to set up and trap the major events within the IDE, you may be asking what you can do with the information. In this section, you are going to add code to some of the event handlers that will allow you to provide useful features to an add-in. This will not be an exhaustive study of the events, but it should spark your thinking and cause you to look for ways to use the information provided by the events.
The WindowActivated event is raised each time a window receives focus. This gives you an opportunity to enforce a small, but significant standard. When a new class, module, or form is added to the project, the first thing that you should do is change the default name of the file from Module1, Class1, or Form1 to some more meaningful name that will describe its contents or purpose. Yet, many times in the heat of the battle, developers forget to do simple things like this. Later on, they find themselves wondering where some code is located. Giving meaningful names to files and methods, which provides developers a good head start on organizing their code, could have solved that problem.
In the WindowActivated event, I have called the CkForRemindOfDefaultName of the CReminder class. This method looks for forms, modules, and classes whose names have never been changed from the default name provided when they were initially added to the project.
Visual Studio .NET makes it easy for the user to change a default name. At the time that a new item is added to the project, the Add New Item dialog box is displayed to allow the user to choose or confirm the type of item to be added. At the same time, the default name is highlighted in the Name text box. All developers have to do is to start typing the name of the new item. Therefore, you should not worry about reminding them if they did not take advantage of that option when adding the new item.
If you implement such a feature in your add-in, you might consider having a way to turn this feature off, as it may become annoying to developers who choose not to change the name. However, this feature can be used to enforce a standard of changing to a meaningful name.With this feature activated, developers will probably change the name just so they will not have to keep clicking the OK button on the message box.
Listing 11-14 shows the new code for the WindowActivated event handler. It calls a method of the Creminder class that is shown in Listing 11-17.
Listing 11-14: Using the WindowActivated Event
Private Sub eventWindows_WindowActivated(ByVal GotFocus As EnvDTE.Window, _ ByVal LostFocus As EnvDTE.Window) Handles eventWindows.WindowActivated ' Let's do something useful ' if the window name is a default name, e.g, Form(n), ' Module(n) or Class(n) ' suggest to the user that they need to rename it oRemind.CkForRemindOfDefaultName(GotFocus.Caption) ' task item removed does not always fire because of ' multiple events firing, so place the calls in this ' event to force the closing of the task list If GotFocus.Caption.StartsWith("Task List") Then oRemind.CkForClosingTaskList() End If If LostFocus.Caption.StartsWith("Task List") Then oRemind.CkForClosingTaskList() End If End Sub
Figure 11-1 shows a display of the message box reminding the user to change the default name of Form1.
Figure 11-1: Reminding the user to change the name of Form1
When you enter a line of code into the Text Editor that will generate a compile error, a to-do item is automatically placed into the Task List.
A to-do item is placed automatically in the Task List in Visual Basic only. This is not done in Visual C# until you compile the project.
Although I do not want to have to answer a message box, it would be nice for the Task List to automatically open and remain open to remind me to correct the problem immediately. Sometimes I may have to enter some other code before the error is cleared up. This would be the case if I enter a call to a procedure that does not yet exist. Even in this case, I may need to be reminded to code that procedure. Having the Task List automatically open to show the to-do item seems to me to be a nice touch.
I have added special code to the TaskAdded event handler. This code automatically opens the Task List when an item is added to the Task List. In addition to opening the window, I have set the AutoHides property to False. This will keep me from ignoring the error and attempting to compile the program only to find, to my surprise, that I have one or more errors. Along with the code that I have added to the TaskRemoved event handler, the window will stay open until I have corrected all of the lines with errors in them.
If you implement this feature in your add-in, you might consider having a way to disable it. This feature may annoy the developer that uses your add-in and it does not enforce any standards—it is simply a quick reminder of errors being created as the developer is coding.
Listing 11-15 shows the code for the new ItemAdded event of the TaskListEvents object.
Listing 11-15: TaskListEvents ItemAdded Event
Private Sub taskListEvents_TaskAdded(ByVal TaskItem As EnvDTE.TaskItem) _ Handles taskListEvents.TaskAdded ow.WriteOutputWindow("TaskListEvents::TaskAdded", _ vbTab & "Task description: " & TaskItem.Description) oRemind.ActivateTaskList() End Sub
Listing 11-16 shows the new code for the ItemRemoved event of the TaskListEvents object. This code calls the CkForClosingTaskList method of the CReminder class. That method checks the count of items in the Task List, and if it is zero, it automatically hides the Task List window.
Listing 11-16: New TaskRemoved Event
Private Sub taskListEvents_TaskRemoved( ByVal TaskItem As EnvDTE.TaskItem) Handles taskListEvents.TaskRemoved ow.WriteOutputWindow("TaskListEvents::TaskRemoved", vbTab & "Task description: " & TaskItem.Description) ORemind.CkForClosingTaskList() End Sub
You cannot always depend on the sequence of the firing of events, and in fact, you cannot always depend on certain events firing if other events are firing at the same time, which is often the case. For that reason, the ItemRemoved event of the TaskListEvents object does not always fire. Therefore, the CkForClosingTaskList method may not always be called. In testing, I have found this sequence to be erratic at best. For that reason, I have placed calls to the CReminder class in the WindowActivated event handler. Placing these extra calls helps get the Task List closed.
Figure 11-2 shows a display of the Task List that has been activated because an item has been added to the Task List. You will note that Task List already has some error items in it. Even if the developer closes the Task List with errors in it, it will pop up again if another error is entered into the Task List.
Figure 11-2: Task List activated by code with errors
I have created a new class called the CReminder class. Initially it contains only three public methods that perform the functions described in the two previous sections. However, this class provides the container for other methods and functionality that you can add as you think through some of the features that you would like to trigger upon the occurrence of a DTE event. Listing 11-17 shows the code for this class.
In the CkForRemindOfDefaultName method I keep a record of the files that have been passed to the method. I did this so that I will not display the reminder message every time the window is activated. That would be a little too annoying to developers. It will remind them once per instance of the IDE.
You will notice that I am using the StringBuilder object at the beginning of the CkForRemindOfDefaultName method. The StringBuilder object is new to Visual Basic .NET. It creates a mutable (changeable) string that can be appended to without having to recreate a new string as it does when you simply use a String variable. The StringBuilder object, sb, is created in the constructor of the CReminder class.
Listing 11-17: CReminder Class
Imports Microsoft.Office.Core Imports Extensibility Imports System.Runtime.InteropServices Imports EnvDTE Public Class CReminders Private DefaultName As String Private sb As System.Text.StringBuilder Private oVB As EnvDTE.DTE Public Sub CkForRemindOfDefaultName(ByVal winCaption As String) ' Display message to remind the developer to change ' the name of the file from the default name if they ' have not already done so. However, don't do it but ' once per instance of the IDE. ' DefaultName is a string variable which simply contains ' the winCaption parameter concatenated with all previous ' names, separated by "_". ' if the name is extant in the string, don't put it ' there again or notify the user. If sb.ToString.IndexOf(winCaption) > -1 Then Exit Sub If (Left(winCaption, 4) = "Form" And _ winCaption.EndsWith("[Design]")) Or _ Left(winCaption, 6) = "Module" Or _ Left(winCaption, 5) = "Class" _ Then MsgBox(winCaption & " still has a default name;" & vbLf & "it should be changed to a more meaningful name.", MsgBoxStyle.Exclamation, "Change Default Name") sb.Append(winCaption & "_") End If End Sub Public Sub ActivateTaskList() Dim win As Window = oVB.Windows.Item(Constants.vsWindowKindTaskList) win.Activate() win.AutoHides = False End Sub Public Sub CkForClosingTaskList() Dim win As Window = oVB.Windows.Item(Constants.vsWindowKindTaskList) Dim tskList As TaskList = win.Object If tskList.TaskItems.Count = 0 Then win.AutoHides = True End If win.Activate() End Sub Public Sub New(ByVal roVB As EnvDTE.DTE) oVB = roVB sb = New System.Text.StringBuilder() End Sub End Class
|< Free Open Study >|| |