![]() |
||||
|
When an add-in creates commandbar buttons (CommandBarButton class) on built-in toolbars or context menus of Visual Studio using a temporary user-interface approach, it should remove them when unloaded (using a permanent user-interface approach they should remain, though). To learn the difference between a temporary and a permanent user-interface approach see HOWTO: Adding buttons, commandbars and toolbars to Visual Studio .NET from an add-in. CommandBar buttons are typically removed using the CommandBarButton.Delete method. However, if Visual Studio or the add-in crashes before the add-in is unloaded, it doesn't have the chance of removing those buttons and they would remain there forever. More Information An approach to prevent this problem is to delete the command (rather that the commandbar button) and re-create it when the add-in is unloaded. Since deleting a command removes all buttons created from it, the next time that the add-in can be unloaded successfully even dead buttons will be removed. Notes:
The sample code below shows this approach. To test the code:
Public Class Connect
Implements Extensibility.IDTExtensibility2, EnvDTE.IDTCommandTarget
Private Const m_COMMAND1_NAME As String = "MyCommand1"
Private Const m_COMMAND2_NAME As String = "MyCommand2"
Private Const m_COMMAND1_CAPTION As String = "My Command 1"
Private Const m_COMMAND2_CAPTION As String = "My Command 2"
Private Const m_COMMAND1_TOOLTIP As String = "Executes Command 1"
Private Const m_COMMAND2_TOOLTIP As String = "Executes Command 2"
Private Const m_COMMAND1_IMAGE As Integer = 59
Private Const m_COMMAND2_IMAGE As Integer = 60
Private m_dte As EnvDTE.DTE
Private m_addIn As EnvDTE.AddIn
Public Sub OnConnection(ByVal application As Object, ByVal connectMode As Extensibility.ext_ConnectMode, _
ByVal addInInst As Object, ByRef custom As System.Array) _
Implements Extensibility.IDTExtensibility2.OnConnection
Try
m_dte = CType(application, EnvDTE.DTE)
m_addIn = CType(addInInst, EnvDTE.AddIn)
Select Case connectMode
Case ext_ConnectMode.ext_cm_UISetup
' Create commands in the UI Setup phase. This phase is called only once when the add-in is deployed.
CreateCommands()
Case ext_ConnectMode.ext_cm_Startup
' Do nothing yet, wait until the IDE is fully initialized (OnStartupComplete will be called)
Case ext_ConnectMode.ext_cm_AfterStartup
InitializeAddIn()
End Select
Catch objException As Exception
MessageBox.Show(objException.ToString, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
Public Sub OnStartupComplete(ByRef custom As System.Array) _
Implements Extensibility.IDTExtensibility2.OnStartupComplete
InitializeAddIn()
End Sub
Private Sub CreateCommands()
CreateCommand(m_COMMAND1_NAME, m_COMMAND1_CAPTION, m_COMMAND1_TOOLTIP, m_COMMAND1_IMAGE, Nothing)
CreateCommand(m_COMMAND2_NAME, m_COMMAND2_CAPTION, m_COMMAND2_TOOLTIP, m_COMMAND2_IMAGE, Nothing)
End Sub
Private Sub CreateCommand(ByVal commandShortName As String, ByVal commandCaption As String, _
ByVal commandTooltip As String, ByVal commandImage As Integer, ByVal bindings As Object)
Dim command As EnvDTE.Command = Nothing
Try
command = m_dte.Commands.AddNamedCommand(m_addIn, commandShortName, commandCaption, _
commandTooltip, True, commandImage)
If Not (bindings Is Nothing) Then
command.Bindings = bindings
End If
Catch ex As Exception
' This should not happen!
End Try
End Sub
Private Sub InitializeAddIn()
Dim standardWindowCommandBar As CommandBar
Dim commandBars As CommandBars
' Retrieve the "Standard" toolbar
commandBars = CType(m_dte.CommandBars, CommandBars)
standardWindowCommandBar = commandBars.Item("Standard")
' Create the buttons from the commands
AddCommandBarButton(standardWindowCommandBar, m_COMMAND1_NAME)
AddCommandBarButton(standardWindowCommandBar, m_COMMAND2_NAME)
End Sub
Private Sub AddCommandBarButton(ByVal commandBar As CommandBar, ByVal commandShortName As String)
Dim commandBarControl As CommandBarControl
Dim commandBarButton As CommandBarButton
Dim command As Command
' Retrieve the command created in the ext_cm_UISetup phase of the OnConnection method
command = m_dte.Commands.Item(m_addIn.ProgID & "." & commandShortName)
' Add a control to the command bar
commandBarControl = CType(command.AddControl(commandBar, commandBar.Controls.Count + 1), CommandBarControl)
' Cast it to CommandBarButton to set some properties
commandBarButton = DirectCast(commandBarControl, CommandBarButton)
commandBarButton.BeginGroup = True
commandBarButton.Style = MsoButtonStyle.msoButtonIconAndCaption
commandBarButton.Visible = True
End Sub
Public Sub OnDisconnection(ByVal RemoveMode As Extensibility.ext_DisconnectMode, ByRef custom As System.Array) _
Implements Extensibility.IDTExtensibility2.OnDisconnection
Try
Select Case RemoveMode
Case ext_DisconnectMode.ext_dm_UserClosed, ext_DisconnectMode.ext_dm_HostShutdown
If MessageBox.Show("Do you want to simulate the add-in not removing its buttons when unloading?", _
"Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes Then
' Do nothing. The button will remain on the toolbar even when the add-in is unloaded
Else
' Recreate the commands to delete the commandbar buttons
RecreateCommands()
End If
End Select
Catch objException As Exception
MessageBox.Show(objException.ToString, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
Private Sub RecreateCommands()
RecreateCommand(m_COMMAND1_NAME, m_COMMAND1_CAPTION, m_COMMAND1_TOOLTIP, m_COMMAND1_IMAGE)
RecreateCommand(m_COMMAND2_NAME, m_COMMAND2_CAPTION, m_COMMAND2_TOOLTIP, m_COMMAND2_IMAGE)
End Sub
Private Sub RecreateCommand(ByVal commandShortName As String, ByVal commandCaption As String, _
ByVal commandTooltip As String, ByVal commandImage As Integer)
Dim existingCommand As Command = Nothing
Dim bindings As Object
Dim commandFullName As String
commandFullName = m_addIn.ProgID & "." & commandShortName
' Try to get the command if it exists to get the current binding
Try
existingCommand = m_dte.Commands.Item(commandFullName)
Catch
End Try
If existingCommand Is Nothing Then
' This should not happen!
Else
' We must preserve the command bindings
bindings = existingCommand.Bindings
' Remove the existing command
existingCommand.Delete()
' Create it again
CreateCommand(commandShortName, commandCaption, commandTooltip, commandImage, bindings)
End If
End Sub
Public Sub OnBeginShutdown(ByRef custom As System.Array) _
Implements Extensibility.IDTExtensibility2.OnBeginShutdown
End Sub
Public Sub OnAddInsUpdate(ByRef custom As System.Array) _
Implements Extensibility.IDTExtensibility2.OnAddInsUpdate
End Sub
Public Sub QueryStatus(ByVal CmdName As String, _
ByVal NeededText As EnvDTE.vsCommandStatusTextWanted, _
ByRef StatusOption As EnvDTE.vsCommandStatus, ByRef CommandText As Object) _
Implements EnvDTE.IDTCommandTarget.QueryStatus
Select Case CmdName
Case m_addIn.ProgID & "." & m_COMMAND1_NAME
StatusOption = vsCommandStatus.vsCommandStatusSupported Or _
vsCommandStatus.vsCommandStatusEnabled
Case m_addIn.ProgID & "." & m_COMMAND2_NAME
StatusOption = vsCommandStatus.vsCommandStatusSupported Or _
vsCommandStatus.vsCommandStatusEnabled
End Select
End Sub
Public Sub Exec(ByVal CmdName As String, ByVal ExecuteOption As EnvDTE.vsCommandExecOption, _
ByRef VariantIn As Object, ByRef VariantOut As Object, ByRef handled As Boolean) _
Implements EnvDTE.IDTCommandTarget.Exec
Select Case CmdName
Case m_addIn.ProgID & "." & m_COMMAND1_NAME
MessageBox.Show("MyCommand1 executed")
Case m_addIn.ProgID & "." & m_COMMAND2_NAME
MessageBox.Show("MyCommand2 executed")
End Select
End Sub
End Class
public class Connect : Extensibility.IDTExtensibility2, EnvDTE.IDTCommandTarget
{
private const string m_COMMAND1_NAME = "MyCommand1";
private const string m_COMMAND2_NAME = "MyCommand2";
private const string m_COMMAND1_CAPTION = "My Command 1";
private const string m_COMMAND2_CAPTION = "My Command 2";
private const string m_COMMAND1_TOOLTIP = "Executes Command 1";
private const string m_COMMAND2_TOOLTIP = "Executes Command 2";
private const int m_COMMAND1_IMAGE = 59;
private const int m_COMMAND2_IMAGE = 60;
private EnvDTE.DTE m_dte;
private EnvDTE.AddIn m_addIn;
public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode,
object addInInst, ref System.Array custom)
{
try
{
m_dte = (EnvDTE.DTE)application;
m_addIn = (EnvDTE.AddIn)addInInst;
switch (connectMode)
{
case ext_ConnectMode.ext_cm_UISetup:
// Create commands in the UI Setup phase. This phase is called only once when the add-in is deployed.
CreateCommands();
break;
case ext_ConnectMode.ext_cm_Startup:
// Do nothing yet, wait until the IDE is fully initialized (OnStartupComplete will be called)
break;
case ext_ConnectMode.ext_cm_AfterStartup:
InitializeAddIn();
break;
}
}
catch (Exception objException)
{
MessageBox.Show(objException.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
public void OnStartupComplete(ref System.Array custom)
{
InitializeAddIn();
}
private void CreateCommands()
{
CreateCommand(m_COMMAND1_NAME, m_COMMAND1_CAPTION, m_COMMAND1_TOOLTIP, m_COMMAND1_IMAGE, null);
CreateCommand(m_COMMAND2_NAME, m_COMMAND2_CAPTION, m_COMMAND2_TOOLTIP, m_COMMAND2_IMAGE, null);
}
private void CreateCommand(string commandShortName, string commandCaption, string commandTooltip, int commandImage, object bindings)
{
EnvDTE.Command command = null;
object[] contextUIGuids = new object[] { };
try
{
command = m_dte.Commands.AddNamedCommand(m_addIn, commandShortName, commandCaption, commandTooltip, true,
commandImage, ref contextUIGuids, (int)vsCommandStatus.vsCommandStatusSupported);
if (bindings != null)
{
command.Bindings = bindings;
}
}
catch (Exception ex)
{
// This should not happen!
}
}
private void InitializeAddIn()
{
CommandBar standardWindowCommandBar = null;
CommandBars commandBars = null;
// Retrieve the "Standard" toolbar
commandBars = (CommandBars)m_dte.CommandBars;
standardWindowCommandBar = commandBars["Standard"];
// Create the buttons from the commands
AddCommandBarButton(standardWindowCommandBar, m_COMMAND1_NAME);
AddCommandBarButton(standardWindowCommandBar, m_COMMAND2_NAME);
}
private void AddCommandBarButton(CommandBar commandBar, string commandShortName)
{
Command command = null;
CommandBarControl commandBarControl = null;
CommandBarButton commandBarButton = null;
// Retrieve the command created in the ext_cm_UISetup phase of the OnConnection method
command = m_dte.Commands.Item(m_addIn.ProgID + "." + commandShortName, -1);
// Add a control to the command bar
commandBarControl = (CommandBarControl)command.AddControl(commandBar, commandBar.Controls.Count + 1);
// Cast it to CommandBarButton to set some properties
commandBarButton = (CommandBarButton)commandBarControl;
commandBarButton.BeginGroup = true;
commandBarButton.Style = MsoButtonStyle.msoButtonIconAndCaption;
commandBarButton.Visible = true;
}
public void OnDisconnection(Extensibility.ext_DisconnectMode RemoveMode, ref System.Array custom)
{
try
{
switch (RemoveMode)
{
case ext_DisconnectMode.ext_dm_UserClosed:
case ext_DisconnectMode.ext_dm_HostShutdown:
if (MessageBox.Show("Do you want to simulate the add-in not removing its buttons when unloading?",
"Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
// Do nothing. The button will remain on the toolbar even when the add-in is unloaded
}
else
{
// Recreate the commands to delete the commandbar buttons
RecreateCommands();
}
break;
}
}
catch (Exception objException)
{
MessageBox.Show(objException.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void RecreateCommands()
{
RecreateCommand(m_COMMAND1_NAME, m_COMMAND1_CAPTION, m_COMMAND1_TOOLTIP, m_COMMAND1_IMAGE);
RecreateCommand(m_COMMAND2_NAME, m_COMMAND2_CAPTION, m_COMMAND2_TOOLTIP, m_COMMAND2_IMAGE);
}
private void RecreateCommand(string commandShortName, string commandCaption, string commandTooltip, int commandImage)
{
Command existingCommand = null;
object bindings = null;
string commandFullName = null;
commandFullName = m_addIn.ProgID + "." + commandShortName;
// Try to get the command if it exists to get the current binding
try
{
existingCommand = m_dte.Commands.Item(commandFullName, -1);
}
catch
{
}
if (existingCommand == null)
{
// This should not happen!
}
else
{
// We must preserve the command bindings
bindings = existingCommand.Bindings;
// Remove the existing command
existingCommand.Delete();
// Create it again
CreateCommand(commandShortName, commandCaption, commandTooltip, commandImage, bindings);
}
}
public void OnBeginShutdown(ref System.Array custom)
{
}
public void OnAddInsUpdate(ref System.Array custom)
{
}
public void QueryStatus(string CmdName, EnvDTE.vsCommandStatusTextWanted NeededText,
ref EnvDTE.vsCommandStatus StatusOption, ref object CommandText)
{
if (CmdName == m_addIn.ProgID + "." + m_COMMAND1_NAME)
{
StatusOption = vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
}
else if (CmdName == m_addIn.ProgID + "." + m_COMMAND2_NAME)
{
StatusOption = vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
}
}
public void Exec(string CmdName, EnvDTE.vsCommandExecOption ExecuteOption, ref object VariantIn,
ref object VariantOut, ref bool handled)
{
if (CmdName == m_addIn.ProgID + "." + m_COMMAND1_NAME)
{
MessageBox.Show("MyCommand1 executed");
}
else if (CmdName == m_addIn.ProgID + "." + m_COMMAND2_NAME)
{
MessageBox.Show("MyCommand2 executed");
}
}
}
Related articles
Go back to the 'Resources for Visual Studio .NET extensibility' section for more articles like this
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||