Freigeben über


Hinzufügen der Suche zu einem Toolfenster

Wenn Sie ein Toolfenster in Ihrer Erweiterung erstellen oder aktualisieren, können Sie dieselbe Suchfunktion hinzufügen, die an anderer Stelle in Visual Studio angezeigt wird. Diese Funktionalität umfasst die folgenden Features:

  • Ein Suchfeld, das sich immer in einem benutzerdefinierten Bereich der Symbolleiste befindet.

  • Eine Statusanzeige, die im Suchfeld selbst überlagert ist.

  • Die Möglichkeit, Ergebnisse anzuzeigen, sobald Sie jedes Zeichen (Sofortsuche) eingeben, oder nur nachdem Sie die EINGABETASTE (Suche bei Bedarf) ausgewählt haben.

  • Eine Liste mit Begriffen, nach denen Sie zuletzt gesucht haben.

  • Die Möglichkeit, Suchvorgänge nach bestimmten Feldern oder Aspekten der Suchziele zu filtern.

Anhand dieser exemplarischen Vorgehensweise erfahren Sie, wie Sie die folgenden Aufgaben ausführen:

  1. Erstellen Sie ein VSPackage-Projekt.

  2. Erstellen Sie ein Toolfenster, das ein UserControl-Objekt mit einem schreibgeschützten TextBox-Steuerelement enthält.

  3. Fügen Sie dem Toolfenster ein Suchfeld hinzu.

  4. Fügen Sie die Suchimplementierung hinzu.

  5. Aktivieren sie die Sofortsuche und die Anzeige einer Statusleiste.

  6. Fügen Sie eine Option "Groß-/Kleinschreibung beachten" hinzu.

  7. Fügen Sie nur filterte Suchzeilen hinzu.

So erstellen Sie ein VSIX-Projekt

  1. Erstellen Sie ein VSIX-Projekt mit dem Namen TestToolWindowSearch "TestSearch". Wenn Sie Hilfe dazu benötigen, lesen Sie das Erstellen einer Erweiterung mit einem Toolfenster.

So erstellen Sie ein Toolfenster

  1. Öffnen Sie im TestToolWindowSearch Projekt die Datei "TestSearchControl.xaml ".

  2. Ersetzen Sie den vorhandenen <StackPanel> Block durch den folgenden Block, der dem UserControl Toolfenster ein schreibgeschütztes TextBox Element hinzufügt.

    <StackPanel Orientation="Vertical">
        <TextBox Name="resultsTextBox" Height="800.0"
            Width="800.0"
            IsReadOnly="True">
        </TextBox>
    </StackPanel>
    
  3. Fügen Sie in der Datei "TestSearchControl.xaml.cs " die folgende Direktive hinzu:

    using System.Text;
    
  4. Entfernen Sie die button1_Click() Methode.

    Fügen Sie in der TestSearchControl-Klasse den folgenden Code hinzu.

    Dieser Code fügt eine öffentliche TextBox Eigenschaft namens SearchResultsTextBox und eine öffentliche Zeichenfolgeneigenschaft namens SearchContent hinzu. Im Konstruktor wird SearchResultsTextBox auf das Textfeld festgelegt, und SearchContent wird in einen durch Neueline getrennten Satz von Zeichenfolgen initialisiert. Der Inhalt des Textfelds wird auch für den Satz von Zeichenfolgen initialisiert.

    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();
        }
    }
    
  5. Erstellen Sie das Projekt, und starten Sie das Debugging. Die experimentelle Instanz von Visual Studio wird angezeigt.

  6. Wählen Sie auf der Menüleiste "Andere Windows>TestSearch anzeigen>" aus.

    Das Toolfenster wird angezeigt, aber das Suchsteuerelement wird noch nicht angezeigt.

So fügen Sie dem Toolfenster ein Suchfeld hinzu

  1. Fügen Sie in der Datei "TestSearch.cs " der Klasse den folgenden Code hinzu TestSearch . Der Code setzt die SearchEnabled Eigenschaft außer Kraft, sodass der Get-Accessor zurückgegeben wird true.

    Um die Suche zu aktivieren, müssen Sie die SearchEnabled Eigenschaft überschreiben. Die ToolWindowPane Klasse implementiert und stellt eine Standardimplementierung IVsWindowSearch bereit, die die Suche nicht aktiviert.

    public override bool SearchEnabled
    {
        get { return true; }
    }
    
  2. Erstellen Sie das Projekt, und starten Sie das Debugging. Die experimentelle Instanz wird geöffnet.

  3. Öffnen Sie in der experimentellen Instanz von Visual Studio TestSearch.

    Oben im Toolfenster wird ein Suchsteuerelement mit einem Suchwasserzeichen und einem Lupensymbol angezeigt. Die Suche funktioniert jedoch noch nicht, da der Suchvorgang noch nicht implementiert wurde.

So fügen Sie die Suchimplementierung hinzu

Wenn Sie die Suche auf einem ToolWindowPane, wie im vorherigen Verfahren beschrieben, aktivieren, erstellt das Toolfenster einen Suchhost. Dieser Host richtet Suchprozesse ein und verwaltet diese, die immer in einem Hintergrundthread auftreten. Da die ToolWindowPane Klasse die Erstellung des Suchhosts und die Einrichtung der Suche verwaltet, müssen Sie nur eine Suchaufgabe erstellen und die Suchmethode bereitstellen. Der Suchvorgang erfolgt in einem Hintergrundthread, und Aufrufe des Toolfenster-Steuerelements erfolgen im UI-Thread. Daher müssen Sie die ThreadHelper.Invoke* -Methode verwenden, um alle Aufrufe zu verwalten, die Sie im Umgang mit dem Steuerelement vornehmen.

  1. Fügen Sie in der Datei "TestSearch.cs " die folgenden using Direktiven hinzu:

    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. Fügen Sie in der TestSearch Klasse den folgenden Code hinzu, der die folgenden Aktionen ausführt:

    • Überschreibt die CreateSearch Methode zum Erstellen einer Suchaufgabe.

    • Setzt die ClearSearch Methode außer Kraft, um den Zustand des Textfelds wiederherzustellen. Diese Methode wird aufgerufen, wenn ein Benutzer eine Suchaufgabe abbricht und wenn ein Benutzer Optionen oder Filter festlegt oder entsetzt. Beide CreateSearch und ClearSearch werden im UI-Thread aufgerufen. Daher müssen Sie nicht über die ThreadHelper.Invoke* -Methode auf das Textfeld zugreifen.

    • Erstellt eine Klasse, die benannt TestSearchTask wird, von VsSearchTaskder geerbt wird, die eine Standardimplementierung von IVsSearchTask.

      In TestSearchTask, legt der Konstruktor ein privates Feld fest, das auf das Toolfenster verweist. Um die Suchmethode bereitzustellen, überschreiben Sie die und OnStopSearch die OnStartSearch Methoden. Die OnStartSearch Methode ist der Ort, an dem Sie den Suchvorgang implementieren. Dieser Vorgang umfasst das Ausführen der Suche, das Anzeigen der Suchergebnisse im Textfeld und das Aufrufen der Basisklassenimplementierung dieser Methode, um zu melden, dass die Suche abgeschlossen ist.

    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()
    {
        TestSearchControl control = (TestSearchControl)this.Content;
        control.SearchResultsTextBox.Text = control.SearchContent;
    }
    
    internal class TestSearchTask : VsSearchTask
    {
        private TestSearch m_toolWindow;
    
        public TestSearchTask(uint dwCookie, IVsSearchQuery pSearchQuery, IVsSearchCallback pSearchCallback, TestSearch 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 };
            TestSearchControl control = (TestSearchControl)m_toolWindow.Content;
            string[] contentArr = control.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)((TestSearchControl)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. Testen Sie ihre Suchimplementierung, indem Sie die folgenden Schritte ausführen:

    1. Erstellen Sie das Projekt neu, und starten Sie das Debuggen.

    2. Öffnen Sie in der experimentellen Instanz von Visual Studio das Toolfenster erneut, geben Sie einen Suchtext in das Suchfenster ein, und klicken Sie auf DIE EINGABETASTE.

      Die richtigen Ergebnisse sollten angezeigt werden.

So passen Sie das Suchverhalten an

Durch Ändern der Sucheinstellungen können Sie eine Vielzahl von Änderungen daran vornehmen, wie das Suchsteuerelement angezeigt wird und wie die Suche ausgeführt wird. Sie können z. B. das Wasserzeichen (der Standardtext, der im Suchfeld angezeigt wird), die Minimale und maximale Breite des Suchsteuerelements und die Anzeige einer Statusleiste ändern. Sie können auch den Punkt ändern, an dem Suchergebnisse (bei Bedarf oder Sofortsuche) angezeigt werden und ob eine Liste der Ausdrücke angezeigt werden soll, nach denen Sie kürzlich gesucht haben. Die vollständige Liste der Einstellungen finden Sie in der SearchSettingsDataSource Klasse.

  1. Fügen Sie in der Datei * TestSearch.cs* der Klasse den folgenden Code hinzu TestSearch . Dieser Code ermöglicht die Sofortsuche anstelle der On-Demand-Suche (d. h., der Benutzer muss nicht auf die EINGABETASTE klicken). Der Code setzt die ProvideSearchSettings Methode in der TestSearch Klasse außer Kraft, die zum Ändern der Standardeinstellungen erforderlich ist.

    public override void ProvideSearchSettings(IVsUIDataSource pSearchSettings)
    {
        Utilities.SetValue(pSearchSettings,
            SearchSettingsDataSource.SearchStartTypeProperty.Name,
            (uint)VSSEARCHSTARTTYPE.SST_INSTANT);}
    
  2. Testen Sie die neue Einstellung, indem Sie die Lösung neu erstellen und den Debugger neu starten.

    Suchergebnisse werden jedes Mal angezeigt, wenn Sie ein Zeichen in das Suchfeld eingeben.

  3. Fügen Sie in der ProvideSearchSettings Methode die folgende Zeile hinzu, die die Anzeige einer Statusanzeige ermöglicht.

    public override void ProvideSearchSettings(IVsUIDataSource pSearchSettings)
    {
        Utilities.SetValue(pSearchSettings,
            SearchSettingsDataSource.SearchStartTypeProperty.Name,
             (uint)VSSEARCHSTARTTYPE.SST_INSTANT);
        Utilities.SetValue(pSearchSettings,
            SearchSettingsDataSource.SearchProgressTypeProperty.Name,
             (uint)VSSEARCHPROGRESSTYPE.SPT_DETERMINATE);
    }
    

    Damit die Statusanzeige angezeigt wird, muss der Fortschritt gemeldet werden. Um den Fortschritt zu melden, heben Sie die Kommentare im folgenden Code in der OnStartSearch Methode der TestSearchTask Klasse auf:

    SearchCallback.ReportProgress(this, progress++, (uint)contentArr.GetLength(0));
    
  4. Um die Verarbeitung so zu verlangsamen, dass die Statusanzeige sichtbar ist, heben Sie die Kommentare in der OnStartSearch Methode der TestSearchTask Klasse auf:

    System.Threading.Thread.Sleep(100);
    
  5. Testen Sie die neuen Einstellungen, indem Sie die Lösung neu erstellen und mit dem Debuggen beginnen.

    Die Statusleiste wird jedes Mal, wenn Sie eine Suche ausführen, im Suchfenster (als blaue Linie unterhalb des Suchtextfelds) angezeigt.

So können Benutzer ihre Suchvorgänge verfeinern

Sie können Es Benutzern ermöglichen, ihre Suchvorgänge mithilfe von Optionen wie " Groß-/Kleinschreibung beachten" oder "Ganzes Wort abgleichen" zu verfeinern. Optionen können boolesch sein, die als Kontrollkästchen oder Befehle angezeigt werden, die als Schaltflächen angezeigt werden. Für diese exemplarische Vorgehensweise erstellen Sie eine boolesche Option.

  1. Fügen Sie in der Datei "TestSearch.cs " der Klasse den folgenden Code hinzu TestSearch . Der Code überschreibt die SearchOptionsEnum Methode, mit der die Suchimplementierung erkennen kann, ob eine bestimmte Option aktiviert oder deaktiviert ist. Der Code in SearchOptionsEnum fügt eine Option zum Abgleichen der Groß-/Kleinschreibung zu einem IVsEnumWindowSearchOptions Enumerator hinzu. Die Option zum Abgleichen des MatchCaseOption Falls wird auch als Eigenschaft verfügbar gemacht.

    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. Heben Sie in der TestSearchTask Klasse die Kommentare aus der folgenden Zeile in der OnStartSearch Methode auf:

    matchCase = m_toolWindow.MatchCaseOption.Value;
    
  3. Testen Sie die Option:

    1. Erstellen Sie das Projekt, und starten Sie das Debugging. Die experimentelle Instanz wird geöffnet.

    2. Wählen Sie im Toolfenster den Pfeil nach unten auf der rechten Seite des Textfelds aus.

      Das Kontrollkästchen " Groß-/Kleinschreibung beachten" wird angezeigt.

    3. Aktivieren Sie das Kontrollkästchen "Groß-/Kleinschreibung beachten", und führen Sie dann einige Suchvorgänge durch.

So fügen Sie einen Suchfilter hinzu

Sie können Suchfilter hinzufügen, mit denen Benutzer den Satz von Suchzielen verfeinern können. Sie können z. B. Dateien in Explorer nach den Datumsangaben filtern, nach denen sie zuletzt geändert wurden, und deren Dateinamenerweiterungen. In dieser exemplarischen Vorgehensweise fügen Sie nur einen Filter für gerade Zeilen hinzu. Wenn der Benutzer diesen Filter auswähnt, fügt der Suchhost die Zeichenfolgen hinzu, die Sie der Suchabfrage angeben. Anschließend können Sie diese Zeichenfolgen in Ihrer Suchmethode identifizieren und die Suchziele entsprechend filtern.

  1. Fügen Sie in der Datei "TestSearch.cs " der Klasse den folgenden Code hinzu TestSearch . Der Code implementiert, indem ein WindowSearchSimpleFilter Objekt hinzugefügt wirdSearchFiltersEnum, das angibt, dass die Suchergebnisse so gefiltert werden, dass nur gerade Zeilen angezeigt werden.

    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;
        }
    }
    
    

    Nun zeigt das Suchsteuerelement den Suchfilter Search even lines onlyan. Wenn der Benutzer den Filter auswäht, wird die Zeichenfolge lines:"even" im Suchfeld angezeigt. Andere Suchkriterien können gleichzeitig mit dem Filter angezeigt werden. Suchzeichenfolgen können vor dem Filter, nach dem Filter oder beides angezeigt werden.

  2. Fügen Sie in der Datei TestSearch.cs der Klasse die folgenden Methoden hinzu TestSearchTask , die sich in der TestSearch Klasse befinden. Diese Methoden unterstützen die OnStartSearch Methode, die Sie im nächsten Schritt ändern werden.

    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)).Trim();
    }
    
    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. Aktualisieren Sie in der TestSearchTask Klasse die OnStartSearch Methode mit dem folgenden Code. Durch diese Änderung wird der Code aktualisiert, um den Filter zu unterstützen.

    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 = ((TestSearchControl)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)((TestSearchControl)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. Testen Sie Ihren Code.

  5. Erstellen Sie das Projekt, und starten Sie das Debugging. Öffnen Sie in der experimentellen Instanz von Visual Studio das Toolfenster, und wählen Sie dann den Pfeil nach unten im Suchsteuerelement aus.

    Das Kontrollkästchen " Groß-/Kleinschreibung beachten" und die Geraden Suchzeilen werden nur angezeigt.

  6. Wählen Sie den Filter aus.

    Das Suchfeld enthält Zeilen:"even", und die folgenden Ergebnisse werden angezeigt:

    2 gut

    4 Gut

    6 Verabschieden

  7. Löschen lines:"even" Sie aus dem Suchfeld, aktivieren Sie das Kontrollkästchen "Groß-/Kleinschreibung beachten", und geben Sie g dann in das Suchfeld ein.

    Die folgenden Ergebnisse werden angezeigt:

    1 go

    2 gut

    5 Verabschieden

  8. Wählen Sie das X auf der rechten Seite des Suchfelds aus.

    Die Suche wird gelöscht, und der ursprüngliche Inhalt wird angezeigt. Das Kontrollkästchen "Groß-/Kleinschreibung beachten" ist jedoch weiterhin aktiviert.