Sdílet prostřednictvím


Přidání hledání do okna nástroje

Při vytváření nebo aktualizaci okna nástroje v rozšíření můžete přidat stejné funkce vyhledávání, které se zobrazí jinde v sadě Visual Studio. Tato funkce zahrnuje následující funkce:

  • Vyhledávací pole, které je vždy umístěné ve vlastní oblasti panelu nástrojů.

  • Indikátor průběhu, který je překryvný v samotném vyhledávacím poli.

  • Možnost zobrazovat výsledky hned po zadání jednotlivých znaků (okamžité hledání) nebo až po výběru klávesy Enter (hledání na vyžádání).

  • Seznam, který zobrazuje termíny, pro které jste naposledy hledali.

  • Možnost filtrovat vyhledávání podle konkrétních polí nebo aspektů cílů hledání.

V tomto názorném postupu se dozvíte, jak provádět následující úlohy:

  1. Vytvořte projekt VSPackage.

  2. Vytvořte okno nástroje, které obsahuje UserControl s textovým polem jen pro čtení.

  3. Do okna nástroje přidejte vyhledávací pole.

  4. Přidejte implementaci vyhledávání.

  5. Povolí okamžité hledání a zobrazení indikátoru průběhu.

  6. Přidejte možnost Rozlišovat malá a velká písmena.

  7. Přidejte filtr pouze řádků hledání.

Vytvoření projektu VSIX

  1. Vytvořte projekt VSIX s názvem TestToolWindowSearch tool window s názvem TestSearch. Pokud s tím potřebujete pomoct, přečtěte si téma Vytvoření rozšíření pomocí okna nástroje.

Vytvoření okna nástroje

  1. TestToolWindowSearch V projektu otevřete soubor TestSearchControl.xaml.

  2. <StackPanel> Existující blok nahraďte následujícím blokem, který přidá do okna nástroje jen TextBox pro UserControl čtení.

    <StackPanel Orientation="Vertical">
        <TextBox Name="resultsTextBox" Height="800.0"
            Width="800.0"
            IsReadOnly="True">
        </TextBox>
    </StackPanel>
    
  3. Do souboru TestSearchControl.xaml.cs přidejte následující direktivu using:

    using System.Text;
    
  4. Odeberte metodu button1_Click() .

    Do Třídy TestSearchControl přidejte následující kód.

    Tento kód přidá veřejnou TextBox vlastnost s názvem SearchResultsTextBox a vlastnost veřejného řetězce s názvem SearchContent. V konstruktoru je SearchResultsTextBox nastaven na textové pole a SearchContent se inicializuje na novou sadu řetězců oddělených řádky. Obsah textového pole se také inicializuje do sady řetězců.

    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. Sestavte projekt a spusťte ladění. Zobrazí se experimentální instance sady Visual Studio.

  6. Na řádku nabídek zvolte Zobrazit>další windows>TestSearch.

    Zobrazí se okno nástroje, ale ovládací prvek hledání se ještě nezobrazuje.

Přidání vyhledávacího pole do okna nástroje

  1. Do souboru TestSearch.cs přidejte do TestSearch třídy následující kód. Kód přepíše SearchEnabled vlastnost tak, aby get accessor vrací true.

    Chcete-li povolit vyhledávání, je nutné přepsat SearchEnabled vlastnost. Třída ToolWindowPane implementuje IVsWindowSearch a poskytuje výchozí implementaci, která nepovoluje vyhledávání.

    public override bool SearchEnabled
    {
        get { return true; }
    }
    
  2. Sestavte projekt a spusťte ladění. Zobrazí se experimentální instance.

  3. V experimentální instanci sady Visual Studio otevřete TestSearch.

    V horní části okna nástroje se zobrazí ovládací prvek hledání s vodoznakem Hledání a ikonou lupy. Vyhledávání ale zatím nefunguje, protože proces vyhledávání nebyl implementován.

Přidání implementace vyhledávání

Když povolíte vyhledávání na objektu ToolWindowPane, jako v předchozím postupu, vytvoří okno nástroje hostitele vyhledávání. Tento hostitel nastavuje a spravuje procesy vyhledávání, ke kterým vždy dochází na vlákně na pozadí. Vzhledem k tomu, že ToolWindowPane třída spravuje vytváření hostitele vyhledávání a nastavení vyhledávání, potřebujete vytvořit pouze úlohu vyhledávání a zadat metodu vyhledávání. Proces hledání probíhá ve vlákně na pozadí a volání ovládacího prvku okna nástroje na vlákně uživatelského rozhraní. Proto je nutné použít ThreadHelper.Invoke* metoda ke správě všech volání, která provedete při práci s ovládacím prvku.

  1. Do souboru TestSearch.cs přidejte následující using direktivy:

    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. TestSearch Do třídy přidejte následující kód, který provádí následující akce:

    • Přepíše metodu CreateSearch pro vytvoření vyhledávací úlohy.

    • Přepíše metodu ClearSearch obnovení stavu textového pole. Tato metoda se volá, když uživatel zruší úlohu vyhledávání a když uživatel nastaví nebo zruší nastavení nebo filtry. Obě CreateSearch a ClearSearch jsou volána ve vlákně uživatelského rozhraní. Proto nemusíte přistupovat k textovému poli pomocí metody ThreadHelper.Invoke* .

    • Vytvoří třídu s názvem TestSearchTask , která dědí z VsSearchTask, která poskytuje výchozí implementaci IVsSearchTask.

      Konstruktor TestSearchTasknastaví soukromé pole, které odkazuje na okno nástroje. Chcete-li poskytnout vyhledávací metodu, přepíšete OnStartSearch metody a OnStopSearch metody. Metoda OnStartSearch je místo, kde implementujete proces vyhledávání. Tento proces zahrnuje provádění hledání, zobrazení výsledků hledání v textovém poli a volání implementace základní třídy této metody k hlášení, že hledání je dokončeno.

    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. Otestujte implementaci vyhledávání provedením následujících kroků:

    1. Znovu sestavte projekt a spusťte ladění.

    2. V experimentální instanci sady Visual Studio znovu otevřete okno nástroje, zadejte do vyhledávacího okna hledaný text a klikněte na ENTER.

      Měly by se zobrazit správné výsledky.

Přizpůsobení chování hledání

Změnou nastavení vyhledávání můžete provádět různé změny v zobrazení ovládacího prvku hledání a způsobu provádění hledání. Můžete například změnit vodoznak (výchozí text zobrazený ve vyhledávacím poli), minimální a maximální šířku ovládacího prvku hledání a zjistit, jestli se má zobrazit indikátor průběhu. Můžete také změnit bod, kdy se výsledky hledání začnou zobrazovat (na vyžádání nebo okamžité hledání) a jestli se má zobrazit seznam termínů, pro které jste nedávno hledali. Úplný seznam nastavení najdete ve SearchSettingsDataSource třídě.

  1. Do souboru* TestSearch.cs* přidejte do TestSearch třídy následující kód. Tento kód umožňuje okamžité vyhledávání místo hledání na vyžádání (což znamená, že uživatel nemusí kliknout na ENTER). Kód přepíše metodu ProvideSearchSettings TestSearch ve třídě, což je nezbytné ke změně výchozího nastavení.

    public override void ProvideSearchSettings(IVsUIDataSource pSearchSettings)
    {
        Utilities.SetValue(pSearchSettings,
            SearchSettingsDataSource.SearchStartTypeProperty.Name,
            (uint)VSSEARCHSTARTTYPE.SST_INSTANT);}
    
  2. Otestujte nové nastavení opětovným sestavením řešení a restartováním ladicího programu.

    Výsledky hledání se zobrazí při každém zadání znaku do vyhledávacího pole.

  3. ProvideSearchSettings Do metody přidejte následující řádek, který umožňuje zobrazení indikátoru průběhu.

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

    Aby se indikátor průběhu zobrazil, musí se oznamovat průběh. Pokud chcete hlásit průběh, odkomentujte následující kód v OnStartSearch metodě TestSearchTask třídy:

    SearchCallback.ReportProgress(this, progress++, (uint)contentArr.GetLength(0));
    
  4. Pokud chcete zpomalit zpracování, aby byl indikátor průběhu viditelný, odkomentujte následující řádek v OnStartSearch metodě TestSearchTask třídy:

    System.Threading.Thread.Sleep(100);
    
  5. Nové nastavení otestujte opětovným sestavením řešení a zahájením ladění.

    Indikátor průběhu se zobrazí v okně hledání (jako modrý řádek pod vyhledávacím textovým polem) při každém provedení hledání.

Povolení upřesňování hledání uživatelům

Uživatelům můžete povolit upřesnit hledání pomocí možností, jako je rozlišovat velká a malá písmena nebo Shoda celého slova. Možnosti můžou být logické, které se zobrazují jako zaškrtávací políčka nebo příkazy, které se zobrazují jako tlačítka. V tomto názorném postupu vytvoříte logickou možnost.

  1. Do souboru TestSearch.cs přidejte do TestSearch třídy následující kód. Kód přepíše metodu SearchOptionsEnum , která umožňuje implementaci vyhledávání zjistit, jestli je daná možnost zapnutá nebo vypnutá. Kód v SearchOptionsEnum nástroji přidá možnost, která porovnává malá a velká písmena enumerátoru IVsEnumWindowSearchOptions . Možnost porovnávání případu je také k dispozici jako MatchCaseOption vlastnost.

    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. TestSearchTask Ve třídě odkomentujte následující řádek v OnStartSearch metodě:

    matchCase = m_toolWindow.MatchCaseOption.Value;
    
  3. Otestujte možnost:

    1. Sestavte projekt a spusťte ladění. Zobrazí se experimentální instance.

    2. V okně nástroje zvolte šipku dolů na pravé straně textového pole.

      Zobrazí se zaškrtávací políčko Rozlišovat případ .

    3. Zaškrtněte políčko Rozlišovat malá a velká písmena a pak proveďte některá hledání.

Přidání vyhledávacího filtru

Můžete přidat filtry hledání, které uživatelům umožňují upřesnit sadu cílů hledání. Můžete například filtrovat soubory v Průzkumník souborů podle kalendářních dat, ke kterým byly naposledy upraveny, a jejich přípony názvů souborů. V tomto názorném postupu přidáte filtr jenom pro sudé řádky. Když uživatel zvolí tento filtr, hostitel vyhledávání přidá do vyhledávacího dotazu řetězce, které zadáte. Tyto řetězce pak můžete identifikovat v metodě hledání a odpovídajícím způsobem filtrovat cíle hledání.

  1. Do souboru TestSearch.cs přidejte do TestSearch třídy následující kód. Kód se implementuje SearchFiltersEnum přidáním určujícího WindowSearchSimpleFilter pro filtrování výsledků hledání tak, aby se zobrazily jenom řádky.

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

    Teď ovládací prvek hledání zobrazí vyhledávací filtr Search even lines only. Když uživatel vybere filtr, řetězec lines:"even" se zobrazí ve vyhledávacím poli. Další kritéria hledání se můžou zobrazit ve stejnou dobu jako filtr. Vyhledávací řetězce se můžou zobrazit před filtrem, za filtrem nebo oběma.

  2. Do souboru TestSearch.cs přidejte následující metody do TestSearchTask třídy, která je ve TestSearch třídě. Tyto metody podporují metodu OnStartSearch , kterou upravíte v dalším kroku.

    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. TestSearchTask Ve třídě aktualizujte metodu OnStartSearch následujícím kódem. Tato změna aktualizuje kód tak, aby podporoval filtr.

    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. Otestujte kód.

  5. Sestavte projekt a spusťte ladění. V experimentální instanci sady Visual Studio otevřete okno nástroje a pak zvolte šipku dolů u ovládacího prvku hledání.

    Zaškrtávací políčko Rozlišovat velká a sudá řádky se zobrazí jenom vyfiltrování.

  6. Zvolte filtr.

    Vyhledávací pole obsahuje řádky:"even" a zobrazí se následující výsledky:

    2 dobré

    4 Dobré

    6 Sbohem

  7. Odstraňte lines:"even" ho z vyhledávacího pole, zaškrtněte políčko Rozlišovat malá a velká písmena a zadejte g do vyhledávacího pole.

    Zobrazí se následující výsledky:

    1 go

    2 dobré

    5 sbohem

  8. Zvolte X na pravé straně vyhledávacího pole.

    Hledání se vymaže a zobrazí se původní obsah. Zaškrtávací políčko Rozlišovat malá a velká písmena je však stále zaškrtnuté.