From 03684a449d083a235ca3c600ed6e91fa7eeb3a04 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Wed, 13 May 2026 18:49:05 +0200 Subject: [PATCH] Search pane view with input, mode picker, result list Replace the placeholder TextBlock with the real layout: a TextBox at the top bound two-way to SearchPaneModel.SearchTerm (UpdateSourceTrigger PropertyChanged so the orchestrator reacts on every keystroke once it lands), a ComboBox bound to SearchModes / SelectedSearchMode, and a ListBox that renders each SearchResult as three trimmed columns (Name / Location / Assembly). Assisted-by: Claude:claude-opus-4-7:Claude Code --- ILSpy.Tests/Search/SearchPaneViewTests.cs | 76 +++++++++++++++++++++++ ILSpy/Search/SearchPane.axaml | 33 +++++++++- 2 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 ILSpy.Tests/Search/SearchPaneViewTests.cs diff --git a/ILSpy.Tests/Search/SearchPaneViewTests.cs b/ILSpy.Tests/Search/SearchPaneViewTests.cs new file mode 100644 index 000000000..2dce5905a --- /dev/null +++ b/ILSpy.Tests/Search/SearchPaneViewTests.cs @@ -0,0 +1,76 @@ +// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System.Linq; +using System.Threading.Tasks; + +using Avalonia.Controls; +using Avalonia.Headless.NUnit; + +using AwesomeAssertions; + +using ILSpy.AppEnv; +using ILSpy.Search; +using ILSpy.Views; + +using NUnit.Framework; + +namespace ICSharpCode.ILSpy.Tests.Search; + +[TestFixture] +public class SearchPaneViewTests +{ + [AvaloniaTest] + public async Task SearchPane_Hosts_The_Required_Three_Controls_For_Search_Input_Mode_And_Results() + { + // The pane's contract — used by every downstream commit in this series — is + // that the view exposes three named controls bound to the view-model: a TextBox + // for the query (SearchInput), a ComboBox for the mode picker (SearchModePicker), + // and a ListBox that renders incoming results (SearchResults). + + var window = AppComposition.Current.GetExport(); + window.Show(); + var pane = await window.WaitForComponent(); + + var input = pane.FindControl("SearchInput"); + ((object?)input).Should().NotBeNull("the query TextBox is what the user types into"); + + var modePicker = pane.FindControl("SearchModePicker"); + ((object?)modePicker).Should().NotBeNull("the mode picker drives which ILSpyX strategy runs"); + modePicker!.ItemCount.Should().Be(12, + "the picker must populate from SearchPaneModel.SearchModes — twelve entries"); + + var results = pane.FindControl("SearchResults"); + ((object?)results).Should().NotBeNull("the results list is the binding sink for the streaming orchestrator"); + } + + [AvaloniaTest] + public async Task Typing_Into_The_Search_Input_Writes_Through_To_SearchTerm() + { + var window = AppComposition.Current.GetExport(); + window.Show(); + var pane = await window.WaitForComponent(); + var vm = (SearchPaneModel)pane.DataContext!; + + var input = pane.FindControl("SearchInput"); + input!.Text = "Enumerable"; + + vm.SearchTerm.Should().Be("Enumerable", + "the TextBox is bound two-way to SearchPaneModel.SearchTerm"); + } +} diff --git a/ILSpy/Search/SearchPane.axaml b/ILSpy/Search/SearchPane.axaml index 1a9912b6c..8a5e3117a 100644 --- a/ILSpy/Search/SearchPane.axaml +++ b/ILSpy/Search/SearchPane.axaml @@ -6,7 +6,34 @@ mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="200" x:Class="ILSpy.Search.SearchPane" x:DataType="search:SearchPaneModel"> - + + + + + + + + + + + + + + + + + + + + + + +