Aggiungere la ricerca a una finestra degli strumenti
Quando si crea o si aggiorna una finestra degli strumenti nell'estensione, è possibile aggiungere la stessa funzionalità di ricerca visualizzata altrove in Visual Studio. Questa funzionalità include le funzionalità seguenti:
Casella di ricerca che si trova sempre in un'area personalizzata della barra degli strumenti.
Indicatore di stato sovrapposto nella casella di ricerca stessa.
La possibilità di visualizzare i risultati non appena si immette ogni carattere (ricerca immediata) o solo dopo aver scelto il tasto INVIO (ricerca su richiesta).
Elenco che mostra i termini per i quali è stata eseguita la ricerca più di recente.
Possibilità di filtrare le ricerche in base a campi o aspetti specifici delle destinazioni di ricerca.
Seguendo questa procedura dettagliata si apprenderà come eseguire le attività seguenti:
Creare un progetto VSPackage.
Creare una finestra degli strumenti che contiene un controllo UserControl con un controllo TextBox di sola lettura.
Aggiungere una casella di ricerca alla finestra degli strumenti.
Aggiungere l'implementazione della ricerca.
Abilitare la ricerca immediata e la visualizzazione di un indicatore di stato.
Aggiungere un'opzione Maiuscole/minuscole .
Aggiungere un filtro Solo righe di ricerca pari.
Per creare un progetto VSIX
- Creare un progetto VSIX denominato
TestToolWindowSearch
con una finestra degli strumenti denominata TestSearch. Per altre informazioni, vedere Creazione di un'estensione con una finestra degli strumenti.
Per creare una finestra degli strumenti
TestToolWindowSearch
Nel progetto aprire il file TestSearchControl.xaml.Sostituire il blocco esistente
<StackPanel>
con il blocco seguente, che aggiunge un valore di sola TextBox lettura a UserControl nella finestra degli strumenti.<StackPanel Orientation="Vertical"> <TextBox Name="resultsTextBox" Height="800.0" Width="800.0" IsReadOnly="True"> </TextBox> </StackPanel>
Nel file TestSearchControl.xaml.cs aggiungere la direttiva using seguente:
using System.Text;
Rimuovere il
button1_Click()
metodo .Nella classe TestSearchControl aggiungere il codice seguente.
Questo codice aggiunge una proprietà pubblica TextBox denominata SearchResultsTextBox e una proprietà stringa pubblica denominata SearchContent. Nel costruttore SearchResultsTextBox è impostato sulla casella di testo e SearchContent viene inizializzato su un set di stringhe delimitato da una nuova riga. Anche il contenuto della casella di testo viene inizializzato nel set di stringhe.
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(); } }
Compilare il progetto e avviare il debug. Viene visualizzata l'istanza sperimentale di Visual Studio.
Sulla barra dei menu scegliere Visualizza>altri test di WindowsSearch.>
Viene visualizzata la finestra degli strumenti, ma il controllo di ricerca non viene ancora visualizzato.
Per aggiungere una casella di ricerca alla finestra degli strumenti
Nel file TestSearch.cs aggiungere il codice seguente alla
TestSearch
classe . Il codice esegue l'override della SearchEnabled proprietà in modo che la funzione di accesso get restituiscatrue
.Per abilitare la ricerca, è necessario eseguire l'override della SearchEnabled proprietà . La ToolWindowPane classe implementa IVsWindowSearch e fornisce un'implementazione predefinita che non abilita la ricerca.
public override bool SearchEnabled { get { return true; } }
Compilare il progetto e avviare il debug. Viene visualizzata l'istanza sperimentale.
Nell'istanza sperimentale di Visual Studio aprire TestSearch.
Nella parte superiore della finestra degli strumenti viene visualizzato un controllo di ricerca con una filigrana di ricerca e un'icona a forma di lente di ingrandimento. Tuttavia, la ricerca non funziona ancora perché il processo di ricerca non è stato implementato.
Per aggiungere l'implementazione della ricerca
Quando si abilita la ricerca in un ToolWindowPaneoggetto , come nella procedura precedente, la finestra degli strumenti crea un host di ricerca. Questo host configura e gestisce i processi di ricerca, che si verificano sempre in un thread in background. Poiché la ToolWindowPane classe gestisce la creazione dell'host di ricerca e la configurazione della ricerca, è sufficiente creare un'attività di ricerca e fornire il metodo di ricerca. Il processo di ricerca viene eseguito su un thread in background e le chiamate al controllo della finestra degli strumenti si verificano nel thread dell'interfaccia utente. Pertanto, è necessario utilizzare il metodo ThreadHelper.Invoke* per gestire tutte le chiamate effettuate durante la gestione del controllo.
Nel file TestSearch.cs aggiungere le direttive seguenti
using
: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;
TestSearch
Nella classe aggiungere il codice seguente, che esegue le azioni seguenti:Esegue l'override del CreateSearch metodo per creare un'attività di ricerca.
Esegue l'override del ClearSearch metodo per ripristinare lo stato della casella di testo. Questo metodo viene chiamato quando un utente annulla un'attività di ricerca e quando un utente imposta o annulla opzioni o filtri. Sia CreateSearch che ClearSearch vengono chiamati nel thread dell'interfaccia utente. Pertanto, non è necessario accedere alla casella di testo tramite il metodo ThreadHelper.Invoke* .
Crea una classe denominata
TestSearchTask
che eredita da VsSearchTask, che fornisce un'implementazione predefinita di IVsSearchTask.In
TestSearchTask
il costruttore imposta un campo privato che fa riferimento alla finestra degli strumenti. Per fornire il metodo di ricerca, eseguire l'override dei OnStartSearch metodi e OnStopSearch . Il OnStartSearch metodo è il percorso in cui si implementa il processo di ricerca. Questo processo include l'esecuzione della ricerca, la visualizzazione dei risultati della ricerca nella casella di testo e la chiamata all'implementazione della classe di base di questo metodo per segnalare che la ricerca è stata completata.
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; } }
Testare l'implementazione della ricerca eseguendo la procedura seguente:
Ricompilare il progetto e avviare il debug.
Nell'istanza sperimentale di Visual Studio aprire di nuovo la finestra degli strumenti, immettere un testo di ricerca nella finestra di ricerca e fare clic su INVIO.
Verranno visualizzati i risultati corretti.
Per personalizzare il comportamento di ricerca
Modificando le impostazioni di ricerca, è possibile apportare diverse modifiche nel modo in cui viene visualizzato il controllo di ricerca e come viene eseguita la ricerca. Ad esempio, è possibile modificare la filigrana (il testo predefinito visualizzato nella casella di ricerca), la larghezza minima e massima del controllo di ricerca e se visualizzare una barra di stato. È anche possibile modificare il punto in cui i risultati della ricerca iniziano a essere visualizzati (su richiesta o ricerca immediata) e se visualizzare un elenco di termini per cui è stata eseguita la ricerca di recente. È possibile trovare l'elenco completo delle impostazioni nella SearchSettingsDataSource classe .
Nel file* TestSearch.cs* aggiungere il codice seguente alla
TestSearch
classe . Questo codice abilita la ricerca immediata invece della ricerca su richiesta ( ovvero l'utente non deve fare clic su INVIO). Il codice esegue l'override delProvideSearchSettings
TestSearch
metodo nella classe , necessario per modificare le impostazioni predefinite.public override void ProvideSearchSettings(IVsUIDataSource pSearchSettings) { Utilities.SetValue(pSearchSettings, SearchSettingsDataSource.SearchStartTypeProperty.Name, (uint)VSSEARCHSTARTTYPE.SST_INSTANT);}
Testare la nuova impostazione ricompilando la soluzione e riavviando il debugger.
I risultati della ricerca vengono visualizzati ogni volta che si immette un carattere nella casella di ricerca.
ProvideSearchSettings
Nel metodo aggiungere la riga seguente, che abilita la visualizzazione di un indicatore di stato.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); }
Per visualizzare l'indicatore di stato, è necessario segnalare lo stato di avanzamento. Per segnalare lo stato di avanzamento, rimuovere il commento dal codice seguente nel
OnStartSearch
metodo dellaTestSearchTask
classe :SearchCallback.ReportProgress(this, progress++, (uint)contentArr.GetLength(0));
Per rallentare l'elaborazione sufficiente che la barra di stato sia visibile, rimuovere il commento dalla riga seguente nel
OnStartSearch
metodo dellaTestSearchTask
classe :System.Threading.Thread.Sleep(100);
Testare le nuove impostazioni ricompilando la soluzione e avviando il debug.
La barra di stato viene visualizzata nella finestra di ricerca (come riga blu sotto la casella di testo di ricerca) ogni volta che si esegue una ricerca.
Per consentire agli utenti di perfezionare le ricerche
È possibile consentire agli utenti di perfezionare le ricerche tramite opzioni quali Maiuscole/minuscole o Parole intere. Le opzioni possono essere booleane, visualizzate come caselle di controllo o comandi, che vengono visualizzate come pulsanti. Per questa procedura dettagliata si creerà un'opzione booleana.
Nel file TestSearch.cs aggiungere il codice seguente alla
TestSearch
classe . Il codice esegue l'override delSearchOptionsEnum
metodo , che consente all'implementazione della ricerca di rilevare se una determinata opzione è attivata o disattivata. Il codice inSearchOptionsEnum
aggiunge un'opzione per trovare la corrispondenza tra maiuscole e minuscole a un IVsEnumWindowSearchOptions enumeratore. L'opzione per trovare laMatchCaseOption
corrispondenza tra maiuscole e minuscole viene resa disponibile anche come proprietà .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; } }
TestSearchTask
Nella classe rimuovere il commento dalla riga seguente nelOnStartSearch
metodo :matchCase = m_toolWindow.MatchCaseOption.Value;
Testare l'opzione:
Compilare il progetto e avviare il debug. Viene visualizzata l'istanza sperimentale.
Nella finestra degli strumenti scegliere la freccia Giù sul lato destro della casella di testo.
Viene visualizzata la casella di controllo Maiuscole /minuscole.
Selezionare la casella di controllo Caso di corrispondenza e quindi eseguire alcune ricerche.
Per aggiungere un filtro di ricerca
È possibile aggiungere filtri di ricerca che consentono agli utenti di perfezionare il set di destinazioni di ricerca. Ad esempio, è possibile filtrare i file in Esplora file in base alle date in cui sono state modificate più di recente e alle relative estensioni di file. In questa procedura dettagliata si aggiungerà un filtro solo per le righe pari. Quando l'utente sceglie tale filtro, l'host di ricerca aggiunge le stringhe specificate alla query di ricerca. È quindi possibile identificare queste stringhe all'interno del metodo di ricerca e filtrare le destinazioni di ricerca di conseguenza.
Nel file TestSearch.cs aggiungere il codice seguente alla
TestSearch
classe . Il codice implementaSearchFiltersEnum
aggiungendo un oggetto WindowSearchSimpleFilter che specifica di filtrare i risultati della ricerca in modo che vengano visualizzate solo le righe.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; } }
Il controllo di ricerca visualizza ora il filtro
Search even lines only
di ricerca . Quando l'utente sceglie il filtro, la stringalines:"even"
viene visualizzata nella casella di ricerca. Altri criteri di ricerca possono essere visualizzati contemporaneamente al filtro. Le stringhe di ricerca possono essere visualizzate prima del filtro, dopo il filtro o entrambe.Nel file TestSearch.cs aggiungere i metodi seguenti alla
TestSearchTask
classe , che si trova nellaTestSearch
classe . Questi metodi supportano ilOnStartSearch
metodo, che verrà modificato nel passaggio successivo.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; }
TestSearchTask
Nella classe aggiornare ilOnStartSearch
metodo con il codice seguente. Questa modifica aggiorna il codice per supportare il filtro.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(); }
Testare il codice.
Compilare il progetto e avviare il debug. Nell'istanza sperimentale di Visual Studio aprire la finestra degli strumenti e quindi scegliere la freccia GIÙ nel controllo di ricerca.
Viene visualizzata la casella di controllo Maiuscole /minuscole e il filtro Cerca solo righe pari.
Scegliere il filtro.
La casella di ricerca contiene righe:"even"e vengono visualizzati i risultati seguenti:
2 buono
4 Buono
6 Addio
Eliminare
lines:"even"
dalla casella di ricerca, selezionare la casella di controllo Caso di corrispondenza e quindi immettereg
nella casella di ricerca.Vengono visualizzati i risultati seguenti:
1 andare
2 buono
5 addio
Scegliere la X sul lato destro della casella di ricerca.
La ricerca viene cancellata e viene visualizzato il contenuto originale. Tuttavia, la casella di controllo Caso di corrispondenza è ancora selezionata.