Share via


Walkthrough: Adding Search to a Tool Window

When you create or update a tool window in your extension, you can add the same search functionality that appears elsewhere in Visual Studio. This functionality includes the following features:

  • A search box that’s always located in a custom area of the toolbar.

  • A progress indicator that’s overlaid on the search box itself.

  • The ability to show results as soon as you enter each character (instant search) or only after you choose the Enter key (search on demand).

  • A list that shows terms for which you’ve searched most recently.

  • The ability to filter searches by specific fields or aspects of the search targets.

By following this walkthrough, you’ll learn how to perform the following tasks:

  1. Create a VSPackage project.

  2. Create a tool window that contains a UserControl with a read-only TextBox.

  3. Add a search box to the tool window.

  4. Add the search implementation.

  5. Enable instant search and display of a progress bar.

  6. Add a Match case option.

  7. Add a Search even lines only filter.

To create a VSPackage project

  1. On the menu bar, choose File, New, Project.

  2. In the New Project dialog box, expand Other Project Types, and then choose Extensibility.

  3. In the Templates pane, choose the Visual Studio Package template.

  4. In the Name box, enter TestToolWindowSearch for the solution, and then choose the OK button.

    The Visual Studio Package Wizard starts.

  5. On the Select a Programming Language page, choose the Visual C# or Visual Basic option button, and then choose the Next button.

  6. On the Basic VSPackage Information page, accept the default values, and then choose the Next button.

  7. On the Select VSPackage Options page, select the Tool Window check box, ensure that all other check boxes are cleared, and then choose the Next button.

  8. On the Tool Window Options page, enter TestSearchWindow in the Window name box and cmdidTestSearchWindow in the Command ID box, and then choose the Next button.

    The value in the Window name box also appears on the menu command for your tool window. That command will appear on the Other Windows submenu of the View menu.

  9. On the Select Test Project Options page, accept the default values, and then choose the Finish button to create your VSPackage.

To create a tool window

  1. In the TestToolWindowSearch project, open the MyControl.xaml file.

  2. Replace the existing <StackPanel> block with the following block, which adds a read-only TextBox to the UserControl in the tool window.

    <StackPanel Orientation="Vertical">
        <TextBox Name="resultsTextBox" Height="800.0"
            Width="800.0"
            IsReadOnly="True">
        </TextBox>
    </StackPanel>
    
  3. In the MyControl.xaml.cs or .vb file, remove the button1_Click() method.

    In the MyControl class, add the following code.

    This code adds a public TextBox property that’s named SearchResultsTextBox and a public string property that’s named SearchContent. In the constructor, SearchResultsTextBox is set to the text box, and SearchContent is initialized to a newline-delimited set of strings. The contents of the text box is also initialized to the set of strings.

    Partial Public Class MyControl
        Inherits System.Windows.Controls.UserControl
    
        Public Property SearchResultsTextBox As System.Windows.Controls.TextBox
        Public Property SearchContent As String 
    
        Public Sub New()
    
            ' This call is required by the designer.
            InitializeComponent()
    
            ' Add any initialization after the InitializeComponent() call. 
            Me.SearchResultsTextBox = resultsTextBox
            Me.SearchContent = buildContent
    
            Me.SearchResultsTextBox.Text = Me.SearchContent
        End Sub 
    
        Private Function BuildContent() As String 
            Dim sb As New System.Text.StringBuilder()
    
            sb.AppendLine("1 go")
            sb.AppendLine("2 good")
            sb.AppendLine("3 Go")
            sb.AppendLine("4 Good")
            sb.AppendLine("5 goodbye")
            sb.AppendLine("6 Goodbye")
    
            Return sb.ToString()
        End Function 
    End Class
    
    public partial class MyControl : UserControl
    {
        public TextBox SearchResultsTextBox { get; set; }
        public string SearchContent { get; set; }
    
        public MyControl()
        {
            InitializeComponent();
    
            this.SearchResultsTextBox = resultsTextBox;
            this.SearchContent = BuildContent();
    
            this.SearchResultsTextBox.Text = this.SearchContent;
        }
    
        private string BuildContent()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("1 go");
            sb.AppendLine("2 good");
            sb.AppendLine("3 Go");
            sb.AppendLine("4 Good");
            sb.AppendLine("5 goodbye");
            sb.AppendLine("6 Goodbye");
    
            return sb.ToString();
        }
    }
    
  4. Build and debug the solution.

    The experimental instance of Visual Studio appears.

  5. On the menu bar, choose View, Other Windows, TestSearchWindow.

    The tool window appears, but the search control doesn’t yet appear.

To add a search box to the tool window

  1. In the MyToolWindow.cs or .vb file, add the following code to the MyToolWindow class. The code overrides the SearchEnabled property so that the get accessor returns true.

    To enable search, you must override the SearchEnabled property. The ToolWindowPane class implements IVsWindowSearch and provides a default implementation that doesn’t enable search.

    Public Overrides ReadOnly Property SearchEnabled As Boolean 
        Get 
            Return True 
        End Get 
    End Property
    
    public override bool SearchEnabled
    {
        get { return true; }
    }
    
  2. Rebuild and debug the solution.

  3. In the experimental instance of Visual Studio, expand Other Windows, and then open TestSearchWindow.

    At the top of the tool window, a search control appears with a Search watermark and a magnifying-glass icon. However, search doesn’t work yet because the search process hasn’t been implemented.

To add the search implementation

When you enable search on a ToolWindowPane, as in the previous procedure, the tool window creates a search host. This host sets up and manages search processes, which always occur on a background thread. Because the ToolWindowPane class manages the creation of the search host and the setting up of the search, you need only create a search task and provide the search method. The search process occurs on a background thread, and calls to the tool window control occur on the UI thread. Therefore, you must use the [M:Microsoft.VisualStudio.Shell.ThreadHelper.Invoke``1(System.Func`1)] method to manage any calls that you make in dealing with the control.

  1. In the MyToolWindow.cs or .vb file, add the following using statements (C#) or Imports statements (Visual Basic):

    Imports System
    Imports System.Collections.Generic
    Imports System.Runtime.InteropServices
    Imports System.Text
    Imports System.Windows.Controls
    Imports Microsoft.Internal.VisualStudio.PlatformUI
    Imports Microsoft.VisualStudio
    Imports Microsoft.VisualStudio.PlatformUI
    Imports Microsoft.VisualStudio.Shell
    Imports Microsoft.VisualStudio.Shell.Interop
    
    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Windows.Controls;
    using Microsoft.Internal.VisualStudio.PlatformUI;
    using Microsoft.VisualStudio;
    using Microsoft.VisualStudio.PlatformUI;
    using Microsoft.VisualStudio.Shell;
    using Microsoft.VisualStudio.Shell.Interop;
    
  2. In the MyToolWindow class, add the following code, which performs the following actions:

    • Overrides the CreateSearch method to create a search task.

    • Overrides the ClearSearch method to restore the state of the text box. This method is called when a user cancels a search task and when a user sets or unsets options or filters. Both CreateSearch and ClearSearch are called on the UI thread. Therefore, you don’t need to access the text box by means of the [M:Microsoft.VisualStudio.Shell.ThreadHelper.Invoke``1(System.Func`1)] method.

    • Creates a class that’s named TestSearchTask that inherits from VsSearchTask, which provides a default implementation of IVsSearchTask.

      In TestSearchTask, the constructor sets a private field that references the tool window. To provide the search method, you override the OnStartSearch and OnStopSearch methods. The OnStartSearch method is where you implement the search process. This process includes performing the search, displaying the search results in the text box, and calling the base class implementation of this method to report that the search is complete.

    Public Overrides Function CreateSearch(ByVal dwCookie As UInteger, ByVal pSearchQuery As IVsSearchQuery, ByVal pSearchCallback As IVsSearchCallback) As IVsSearchTask
        If pSearchQuery Is Nothing Or pSearchCallback Is Nothing Then 
            Return Nothing 
        Else 
            Return New TestSearchTask(dwCookie, pSearchQuery, pSearchCallback, Me)
        End If 
    End Function 
    
    Public Overrides Sub ClearSearch()
        Dim control = DirectCast(Me.Content, MyControl)
        control.SearchResultsTextBox.Text = control.SearchContent
    End Sub 
    
    Friend Class TestSearchTask
        Inherits VsSearchTask
    
        Private m_toolWindow As MyToolWindow
    
        Public Sub New(ByVal dwCookie As UInteger, ByVal pSearchQuery As IVsSearchQuery, ByVal pSearchCallback As IVsSearchCallback, ByVal toolwindow As MyToolWindow)
            MyBase.New(dwCookie, pSearchQuery, pSearchCallback)
    
            m_toolWindow = toolwindow
        End Sub 
    
        Protected Overrides Sub OnStartSearch()
            ' Use the original content of the text box as the target of the search. 
            Dim separator = New String() {Environment.NewLine}
            Dim contentArr As String() = DirectCast(m_toolWindow.Content, MyControl).SearchContent.Split(separator, StringSplitOptions.None)
    
            ' Get the search option. 
            Dim matchCase As Boolean = False 
            ' matchCase = m_toolWindow.MatchCaseOption.Value 
    
            ' Set variables that are used in the finally block. 
            Dim sb As New StringBuilder("")
            Dim resultCount As UInteger = 0
            Me.ErrorCode = VSConstants.S_OK
    
            Try 
                Dim searchString As String = Me.SearchQuery.SearchString
    
                ' Determine the results. 
                Dim progress As UInteger = 0
                For Each line As String In contentArr
    
                    If matchCase = True Then 
                        If line.Contains(searchString) Then
                            sb.AppendLine(line)
                            resultCount += 1
                        End If 
                    Else 
                        If line.ToLower().Contains(searchString.ToLower()) Then
                            sb.AppendLine(line)
                            resultCount += 1
                        End If 
                    End If 
                    ' SearchCallback.ReportProgress(Me, progress, CUInt(contentArr.GetLength(0))) 
                    ' progress += 1 
    
                    ' Uncomment the following line to demonstrate the progress bar. 
                    ' System.Threading.Thread.Sleep(100) 
                Next 
            Catch e As Exception
                Me.ErrorCode = VSConstants.E_FAIL
            Finally
                ThreadHelper.Generic.Invoke(
                    Sub()
                        DirectCast(DirectCast(m_toolWindow.Content, MyControl).SearchResultsTextBox, TextBox).Text = sb.ToString()
                    End Sub)
    
                Me.SearchResults = resultCount
            End Try 
    
            ' Call the implementation of this method in the base class. 
            ' This sets the task status to complete and reports task completion. 
            MyBase.OnStartSearch()
        End Sub 
    
        Protected Overrides Sub OnStopSearch()
            Me.SearchResults = 0
        End Sub 
    End Class
    
    public override IVsSearchTask CreateSearch(uint dwCookie, IVsSearchQuery pSearchQuery, IVsSearchCallback pSearchCallback)
    {
        if (pSearchQuery == null || pSearchCallback == null)
            return null;
        return new TestSearchTask(dwCookie, pSearchQuery, pSearchCallback, this);
    }
    
    public override void ClearSearch()
    {
        MyControl control = (MyControl)this.Content;
        control.SearchResultsTextBox.Text = control.SearchContent;
    }
    
    internal class TestSearchTask : VsSearchTask
    {
        private MyToolWindow m_toolWindow;
    
        public TestSearchTask(uint dwCookie, IVsSearchQuery pSearchQuery, IVsSearchCallback pSearchCallback, MyToolWindow toolwindow)
            : base(dwCookie, pSearchQuery, pSearchCallback)
        {
            m_toolWindow = toolwindow;
        }
    
        protected override void OnStartSearch()
        {
            // Use the original content of the text box as the target of the search. 
            var separator = new string[] { Environment.NewLine };
            string[] contentArr = ((MyControl)m_toolWindow.Content).SearchContent.Split(separator, StringSplitOptions.None);
    
            // Get the search option. 
            bool matchCase = false;
            // matchCase = m_toolWindow.MatchCaseOption.Value; 
    
            // Set variables that are used in the finally block.
            StringBuilder sb = new StringBuilder("");
            uint resultCount = 0;
            this.ErrorCode = VSConstants.S_OK;
    
            try
            {
                string searchString = this.SearchQuery.SearchString;
    
                // Determine the results. 
                uint progress = 0;
                foreach (string line in contentArr)
                {
                    if (matchCase == true)
                    {
                        if (line.Contains(searchString))
                        {
                            sb.AppendLine(line);
                            resultCount++;
                        }
                    }
                    else
                    {
                        if (line.ToLower().Contains(searchString.ToLower()))
                        {
                            sb.AppendLine(line);
                            resultCount++;
                        }
                    }
    
                    // SearchCallback.ReportProgress(this, progress++, (uint)contentArr.GetLength(0)); 
    
                    // Uncomment the following line to demonstrate the progress bar. 
                    // System.Threading.Thread.Sleep(100);
                }
            }
            catch (Exception e)
            {
                this.ErrorCode = VSConstants.E_FAIL;
            }
            finally
            {
                ThreadHelper.Generic.Invoke(() =>
                { ((TextBox)((MyControl)m_toolWindow.Content).SearchResultsTextBox).Text = sb.ToString(); });
    
                this.SearchResults = resultCount;
            }
    
            // Call the implementation of this method in the base class. 
            // This sets the task status to complete and reports task completion. 
            base.OnStartSearch();
        }
    
        protected override void OnStopSearch()
        {
            this.SearchResults = 0;
        }
    }
    
  3. Test your search implementation by performing the following steps:

    1. Rebuild and debug the solution.

    2. In the experimental instance of Visual Studio, open the tool window again, add text in the text box, enter search text in the search window, and then choose the Enter key.

      The correct results should appear.

To customize the search behavior

By changing the search settings, you can make a variety of changes in how the search control appears and how the search is carried out. For example, you can change the watermark (the default text that appears in the search box), the minimum and maximum width of the search control, and whether to show a progress bar. You can also change the point at which search results start to appear (on demand or instant search) and whether to show a list of terms for which you recently searched. You can find the complete list of settings in the SearchSettingsDataSource class.

  1. In the MyToolWindow.cs or .vb file, add the following code to the MyToolWindow class. This code enables instant search instead of on-demand search. The code overrides the ProvideSearchSettings method in the MyToolWindow class, which is necessary to change the default settings.

    Public Overrides Sub ProvideSearchSettings(ByVal pSearchSettings As IVsUIDataSource)
        Utilities.SetValue(pSearchSettings, SearchSettingsDataSource.SearchStartTypeProperty.Name, CUInt(VSSEARCHSTARTTYPE.SST_INSTANT))
    End Sub
    
    public override void ProvideSearchSettings(IVsUIDataSource pSearchSettings)
    {
        Utilities.SetValue(pSearchSettings, SearchSettingsDataSource.SearchStartTypeProperty.Name, (uint)VSSEARCHSTARTTYPE.SST_INSTANT);
    }
    
  2. Test the new setting by rebuilding the solution and restarting the debugger.

    Search results appear every time that you enter a character in the search box.

  3. In the ProvideSearchSettings method, add the following line, which enables the display of a progress bar.

    Utilities.SetValue(pSearchSettings, SearchSettingsDataSource.SearchProgressTypeProperty.Name, CUInt(VSSEARCHPROGRESSTYPE.SPT_DETERMINATE))
    
    Utilities.SetValue(pSearchSettings, SearchSettingsDataSource.SearchProgressTypeProperty.Name, (uint)VSSEARCHPROGRESSTYPE.SPT_DETERMINATE);
    

    For the progress bar to appear, the progress must be reported. To report the progress, uncomment the following code in the OnStartSearch method of the TestSearchTask class:

    SearchCallback.ReportProgress(Me, progress, CUInt(contentArr.GetLength(0)))
    progress += 1
    
    SearchCallback.ReportProgress(this, progress++, (uint)contentArr.GetLength(0));
    
  4. To slow processing enough that the progress bar is visible, uncomment the following line in the OnStartSearch method of the TestSearchTask class:

    System.Threading.Thread.Sleep(100)
    
    System.Threading.Thread.Sleep(100);
    
  5. Test the new settings by rebuilding the solution and restarting the debugger.

    The progress bar appears in the search window every time that you perform a search.

  6. Comment out this line in the OnStartSearch method:

    ' System.Threading.Thread.Sleep(100)
    
    // System.Threading.Thread.Sleep(100);
    

To enable users to refine their searches

You can allow users to refine their searches by means of options such as Match case or Match whole word. Options can be boolean, which appear as check boxes, or commands, which appear as buttons. For this walkthrough, you’ll create a boolean option.

  1. In the MyToolWindow.cs or .vb file, add the following code to the MyToolWindow class. The code overrides the SearchOptionsEnum method, which allows the search implementation to detect whether a given option is on or off. The code in SearchOptionsEnum adds an option to match case to an IVsEnumWindowSearchOptions enumerator. The option to match case is also made available as the MatchCaseOption property.

    Private m_optionsEnum As IVsEnumWindowSearchOptions
    Public Overrides ReadOnly Property SearchOptionsEnum() As IVsEnumWindowSearchOptions
        Get 
            If m_optionsEnum Is Nothing Then 
                Dim list As New List(Of IVsWindowSearchOption)()
    
                list.Add(Me.MatchCaseOption)
    
                m_optionsEnum = TryCast(New WindowSearchOptionEnumerator(list), IVsEnumWindowSearchOptions)
            End If 
    
            Return m_optionsEnum
        End Get 
    End Property 
    
    Private m_matchCaseOption As WindowSearchBooleanOption
    Public ReadOnly Property MatchCaseOption
        Get 
            If m_matchCaseOption Is Nothing Then
                m_matchCaseOption = New WindowSearchBooleanOption("Match case", "Match case", False)
            End If 
    
            Return m_matchCaseOption
        End Get 
    End Property
    
    private IVsEnumWindowSearchOptions m_optionsEnum;
    public override IVsEnumWindowSearchOptions SearchOptionsEnum
    {
        get
        {
            if (m_optionsEnum == null)
            {
                List<IVsWindowSearchOption> list = new List<IVsWindowSearchOption>();
    
                list.Add(this.MatchCaseOption);
    
                m_optionsEnum = new WindowSearchOptionEnumerator(list) as IVsEnumWindowSearchOptions;
            }
            return m_optionsEnum;
        }
    }
    
    private WindowSearchBooleanOption m_matchCaseOption;
    public WindowSearchBooleanOption MatchCaseOption
    {
        get
        {
            if (m_matchCaseOption == null)
            {
                m_matchCaseOption = new WindowSearchBooleanOption("Match case", "Match case", false);
            }
            return m_matchCaseOption;
        }
    }
    
  2. In the TestSearchTask class, uncomment the following line in the OnStartSearch method:

    matchCase = m_toolWindow.MatchCaseOption.Value
    
    matchCase = m_toolWindow.MatchCaseOption.Value;
    
  3. Test the option by performing the following steps:.

    1. Rebuild the solution, and restart the debugger.

    2. In the tool window, choose the Down arrow on the search control.

      The Match case check box appears.

    3. Select the Match case check box, and then perform some searches.

To add a search filter

You can add search filters that allow users to refine the set of search targets. For example, you can filter files in File Explorer by the dates on which they were modified most recently and their file name extensions. In this walkthrough, you’ll add a filter for even lines only. When the user chooses that filter, the search host adds the strings that you specify to the search query. You can then identify these strings inside your search method and filter the search targets accordingly.

  1. In the MyToolWindow.cs or .vb file, add the following code to the MyToolWindow class. The code implements SearchFiltersEnum in the MyToolWindow class by adding a WindowSearchSimpleFilter that specifies to filter the search results so that only even lines appear.

    Public Overrides ReadOnly Property SearchFiltersEnum() As IVsEnumWindowSearchFilters
        Get 
            Dim list As New List(Of IVsWindowSearchFilter)()
            list.Add(New WindowSearchSimpleFilter("Search even lines only", "Search even lines only", "lines", "even"))
            Return TryCast(New WindowSearchFilterEnumerator(list), IVsEnumWindowSearchFilters)
        End Get 
    End Property
    
    public override IVsEnumWindowSearchFilters SearchFiltersEnum
    {
        get
        {
            List<IVsWindowSearchFilter> list = new List<IVsWindowSearchFilter>();
            list.Add(new WindowSearchSimpleFilter("Search even lines only", "Search even lines only", "lines", "even"));
            return new WindowSearchFilterEnumerator(list) as IVsEnumWindowSearchFilters;
        }
    }
    

    Now the search control displays the search filter Search even lines only. When the user chooses the filter, the string lines:"even" appears in the search box. Other search criteria can appear at the same time as the filter. Search strings may appear before the filter, after the filter, or both.

  2. In the MyToolWindow.cs or .vb file, add the following methods to the TestSearchTask class, which is in the MyToolWindow class. These methods support the OnStartSearch method, which you’ll modify in the next step.

    Private Function RemoveFromString(ByVal origString As String, ByVal stringToRemove As String) As String 
        Dim index As Integer = origString.IndexOf(stringToRemove)
        If index = -1 Then 
            Return origString
        Else 
            Return origString.Substring(0, index) & origString.Substring(index + stringToRemove.Length)
        End If 
    End Function 
    
    Private Function GetEvenItems(ByVal contentArr As String()) As String()
        Dim length As Integer = contentArr.Length \ 2
        Dim evenContentArr = New String(length) {}
    
        Dim indexB = 0
        For index = 1 To contentArr.Length - 1 Step 2
            evenContentArr(indexB) = contentArr(index)
            indexB += 1
        Next 
    
        Return evenContentArr
    End Function
    
    private string RemoveFromString(string origString, string stringToRemove)
    {
        int index = origString.IndexOf(stringToRemove);
        if (index == -1)
            return origString;
        else 
            return origString.Substring(0, index) + origString.Substring(index + stringToRemove.Length);
    }
    
    private string[] GetEvenItems(string[] contentArr)
    {
        int length = contentArr.Length / 2;
        string[] evenContentArr = new string[length];
    
        int indexB = 0;
        for (int index = 1; index < contentArr.Length; index += 2)
        {
            evenContentArr[indexB] = contentArr[index];
            indexB++;
        }
    
        return evenContentArr;
    }
    
  3. In the TestSearchTask class, update the OnStartSearch method with the following code. This change updates the code to support the filter.

    Protected Overrides Sub OnStartSearch()
        ' Use the original content of the text box as the target of the search. 
        Dim separator = New String() {Environment.NewLine}
        Dim contentArr As String() = DirectCast(m_toolWindow.Content, MyControl).SearchContent.Split(separator, StringSplitOptions.None)
    
        ' Get the search option. 
        Dim matchCase As Boolean = False
        matchCase = m_toolWindow.MatchCaseOption.Value
    
        ' Set variables that are used in the finally block. 
        Dim sb As New StringBuilder("")
        Dim resultCount As UInteger = 0
        Me.ErrorCode = VSConstants.S_OK
    
        Try 
            Dim searchString As String = Me.SearchQuery.SearchString
    
            ' If the search string contains the filter string, filter the content array. 
            Dim filterString = "lines:""even""" 
    
            If searchString.Contains(filterString) Then 
                ' Retain only the even items in the array.
                contentArr = GetEvenItems(contentArr)
    
                ' Remove 'lines:"even"' from the search string.
                searchString = RemoveFromString(searchString, filterString)
            End If 
    
            ' Determine the results. 
            Dim progress As UInteger = 0
            For Each line As String In contentArr
                If matchCase = True Then 
                    If line.Contains(searchString) Then
                        sb.AppendLine(line)
                        resultCount += 1
                    End If 
                Else 
                    If line.ToLower().Contains(searchString.ToLower()) Then
                        sb.AppendLine(line)
                        resultCount += 1
                    End If 
                End If
    
                SearchCallback.ReportProgress(Me, progress, CUInt(contentArr.GetLength(0)))
                progress += 1
    
                ' Uncomment the following line to demonstrate the progress bar. 
                ' System.Threading.Thread.Sleep(100) 
            Next 
        Catch e As Exception
            Me.ErrorCode = VSConstants.E_FAIL
        Finally
            ThreadHelper.Generic.Invoke(
                Sub()
                    DirectCast(DirectCast(m_toolWindow.Content, MyControl).SearchResultsTextBox, TextBox).Text = sb.ToString()
                End Sub)
    
            Me.SearchResults = resultCount
        End Try 
    
        ' Call the implementation of this method in the base class. 
        ' This sets the task status to complete and reports task completion. 
        MyBase.OnStartSearch()
    End Sub
    
    protected override void OnStartSearch()
    {
        // Use the original content of the text box as the target of the search. 
        var separator = new string[] { Environment.NewLine };
        string[] contentArr = ((MyControl)m_toolWindow.Content).SearchContent.Split(separator, StringSplitOptions.None);
    
        // Get the search option. 
        bool matchCase = false;
        matchCase = m_toolWindow.MatchCaseOption.Value;
    
        // Set variables that are used in the finally block.
        StringBuilder sb = new StringBuilder("");
        uint resultCount = 0;
        this.ErrorCode = VSConstants.S_OK;
    
        try
        {
            string searchString = this.SearchQuery.SearchString;
    
            // If the search string contains the filter string, filter the content array. 
            string filterString = "lines:\"even\"";
    
    
            if (this.SearchQuery.SearchString.Contains(filterString))
            {
                // Retain only the even items in the array.
                contentArr = GetEvenItems(contentArr);
    
                // Remove 'lines:"even"' from the search string.
                searchString = RemoveFromString(searchString, filterString);
            }
    
            // Determine the results. 
            uint progress = 0;
            foreach (string line in contentArr)
            {
                if (matchCase == true)
                {
                    if (line.Contains(searchString))
                    {
                        sb.AppendLine(line);
                        resultCount++;
                    }
                }
                else
                {
                    if (line.ToLower().Contains(searchString.ToLower()))
                    {
                        sb.AppendLine(line);
                        resultCount++;
                    }
                }
    
                SearchCallback.ReportProgress(this, progress++, (uint)contentArr.GetLength(0));
    
                // Uncomment the following line to demonstrate the progress bar. 
                // System.Threading.Thread.Sleep(100);
            }
        }
        catch (Exception e)
        {
            this.ErrorCode = VSConstants.E_FAIL;
        }
        finally
        {
            ThreadHelper.Generic.Invoke(() =>
            { ((TextBox)((MyControl)m_toolWindow.Content).SearchResultsTextBox).Text = sb.ToString(); });
    
            this.SearchResults = resultCount;
        }
    
        // Call the implementation of this method in the base class. 
        // This sets the task status to complete and reports task completion. 
        base.OnStartSearch();
    }
    
  4. If you want to test your code, rebuild the solution, restart the debugger, and then perform the remaining steps in this procedure.

  5. In the experimental instance of Visual Studio, open the tool window, and then choose the Down arrow on the search control.

    The Match case check box and the Search even lines only filter appear.

  6. Choose the filter.

    The search box contains lines:”even”, and the following results appear:

    2 good

    4 Good

    6 Goodbye

  7. Delete lines:"even" from the search box, select the Match case check box, and then enter g in the search box.

    The following results appear:

    1 go

    2 good

    5 goodbye

  8. Choose the X on the right side of the search box.

    The search is cleared, and the original contents appear. However, the Match case check box is still selected.

See Also

Tasks

Walkthrough: Creating a Menu Command By Using the Visual Studio Package Template

Other Resources

Tool Windows