빠른 시작
콘텐츠의 테이블 축소
콘텐츠의 테이블 확장
언어: HTML | XAML

빠른 시작: 앱에 검색 추가(XAML)

[ 이 문서는 Windows 런타임 앱을 작성하는 Windows에서 8.x 및 Windows Phone 8.x 개발자를 대상으로 합니다. Windows 10용으로 개발하는 경우에는 최신 설명서를 참조하세요.]

대부분의 사용자는 검색에 의존하여 원하는 내용을 찾습니다. 예를 들어 앱이 미디어 파일을 재생하는 경우 사용자는 특정 음악이나 동영상을 검색할 수 있기를 원합니다. 앱이 요리 앱인 경우 사용자는 특정 조리법이나 재료를 검색할 수 있기를 원합니다.

약간의 계획을 통해 앱에 검색 기능을 쉽게 추가할 수 있습니다. 필요한 사항은 다음과 같습니다.

  • 검색할 데이터 소스. 사용자가 검색할 항목의 카탈로그 또는 인벤토리가 필요합니다. 이 인벤토리의 정보가 자세할수록 검색 결과가 더 정확해집니다.
  • 검색 쿼리를 입력하기 위한 컨트롤. Windows는 앱에서 사용할 수 있는 SearchBox 컨트롤을 제공합니다. SearchBox는 쿼리를 입력하기 위한 입력 영역, 검색을 실행하기 위한 검색 단추 및 검색 쿼리를 처리하기 위한 이벤트를 제공합니다. 몇 가지 검색 제안도 자동으로 제공합니다.
  • 검색 결과를 표시하기 위한 페이지. Microsoft Visual Studio는 검색 쿼리를 처리하고 결과를 표시하는 데 필요한 많은 코드를 만드는 검색 결과 페이지 템플릿을 제공합니다.

이 빠른 시작에서는 이러한 항목을 사용하여 앱에 검색 기능을 추가하는 방법을 설명합니다.

사전 요구 사항

데이터 설정

사용자가 검색 쿼리를 입력하면 앱에서 사용자가 찾고 있는 항목을 검색합니다. 앱에서 검색하는 데이터는 XML 파일, JSON(JavaScript Object Notation) 데이터, 데이터베이스, 웹 서비스, 파일 시스템의 파일 등 여러 형태일 수 있습니다.

이 빠른 시작의 예제는 Microsoft Visual Studio에서 새 프로젝트를 만들 때 제공된 샘플 데이터를 사용합니다.

Visual Studio를 사용하여 새 그리드 앱, 허브 앱 또는 분할 앱을 만드는 경우 Visual Studio에서 JSON 데이터 액세스를 위한 개체를 제공하는 코드 파일과 샘플 데이터가 포함된 JSON 파일이 들어 있는 DataModel 폴더를 만듭니다.

새 허브 앱 프로젝트의 샘플 데이터

코드 파일은 다음 세 가지 클래스를 정의합니다.

  • SampleDataItem: 개별 데이터 항목입니다.
  • SampleDataGroup: SampleDataItem 개체 그룹입니다.
  • SampleDataSource: SampleDataGroup 개체 컬렉션입니다.

데이터 자체는 JSON 파일에서 정의되며 그룹과 항목으로 구성됩니다. 다음은 데이터가 표시되는 모양의 예입니다.


{"Groups":[
  {
    "UniqueId": "Group-1",
    "Title": "Group Title: 1",
    "Subtitle": "Group subtitle: 1",
    "ImagePath": "Assets/DarkGray.png",
    "Description" : "Group Description: Lorem ipsum dolor sit amet...",
    "Items":
    [
      {
        "UniqueId": "Group-1-Item-1",
        "Title": "Item Title: 1",
        "Subtitle": "Item Subtitle: 1",
        "ImagePath": "Assets/LightGray.png",
        "Description" : "Item Description: Pellentesque porta, mauris... neque tortor ac erat.",
        "Content" : "Curabitur class..."
      },
      {
        "UniqueId": "Group-1-Item-2",
        "Title": "Item Title: 2",
        "Subtitle": "Item Subtitle: 2",
        "ImagePath": "Assets/DarkGray.png",
        "Description" : "Item Description: Pellentesque porta, mauris... neque tortor ac erat.",
        "Content" : "Curabitur class..."
      },

데이터 작업에 대한 자세한 내용은 프로젝트 템플릿에 데이터 추가를 참조하세요.

앱에서 검색을 구현할 때는 고유한 데이터를 사용하는 것이 좋지만, 이 샘플 데이터를 사용하는 초기 버전을 만들면 검색을 익히는 데 도움이 되며 고유한 데이터를 검색 가능하도록 구성하는 방법에 대한 몇 가지 아이디어를 얻을 수 있습니다.

검색 결과 페이지 추가

검색 결과 페이지는 검색 쿼리를 처리하고 결과를 표시합니다. 프로젝트에 검색 결과 페이지를 추가하겠습니다.

Hh868180.wedge(ko-kr,WIN.10).gif검색 결과 페이지 항목 추가

  1. 솔루션 탐색기에서 프로젝트 노드를 마우스 오른쪽 단추로 클릭하여 프로젝트 바로 가기 메뉴를 열고 추가 > 새 항목을 클릭합니다. 새 항목 추가 대화 상자가 나타납니다.
  2. 새 항목 추가 대화 상자의 가운데 창에서 검색 결과 페이지를 클릭합니다. 이 예제에서는 이름을 SearchResultsPageExample.xaml로 변경합니다.
  3. 추가 단추를 클릭합니다. Visual Studio에서 일부 파일을 추가해야 한다는 알림이 표시될 수도 있습니다. 를 클릭하면 자동으로 추가됩니다.

Visual Studio에서 SearchResultsPageExample.xaml 및 함께 제공되는 코드 숨김 파일인 SearchResultsPageExample.xaml.cs를 만듭니다.

SearchResultsPageExample.xaml 파일을 살펴보겠습니다. 다음은 파일에 포함된 중요한 항목 중 일부입니다.

  • resultsViewSource - SourceDefaultViewModel의 "Results" 속성에 바인딩된 CollectionViewSource 리소스입니다. DefaultViewModel은 각 페이지에서 정의됩니다. 자세한 내용은 프로젝트 템플릿에 데이터 추가를 참조하세요. 결과를 표시하기 위해 DefaultViewModel["Results"]을 결과가 포함된 목록으로 설정합니다.
  • filtersViewSource - SourceDefaultViewModel의 "Filters" 속성에 바인딩된 CollectionViewSource 리소스입니다.
  • filtersItemsControl - filtersViewSource에 바인딩된 ItemsControl입니다. 이 ItemsControl은 검색 필터를 표시합니다.
  • resultsGridView - resultsViewSource에 바인딩된 GridView입니다. 이 GridView는 검색 결과를 표시합니다.
  • 두 개의 VisualState 정의가 포함된 VisualStateManager: "ResultsFound"에 대한 정의와 "NoResultsFound"에 대한 정의가 있습니다. 시각적 상태가 "NoResultsFound"로 설정된 경우 VisualStateManagerresultsGridView 컨트롤을 숨기고 "No results match your search"라는 텍스트를 대신 표시합니다.

SearchResultsPageExample.xaml.cs에는 수정할 두 개의 메서드 navigationHelper_LoadStateFilter_Checked가 포함되어 있습니다.

검색 상자 추가

검색 결과 페이지에서 수행할 작업이 남아 있지만 먼저 앱에 SearchBox를 추가하겠습니다. SearchBox를 포함하면 구현 시 검색 결과 페이지를 더 쉽게 테스트할 수 있습니다.

SearchBox에서는 사용자가 쿼리를 입력할 수 있습니다. 제안을 표시할 수도 있습니다.

앱에 SearchBox를 추가하려면 XAML 페이지에 다음 태그를 추가하면 됩니다.


<SearchBox
    Height="35" Width="270"
    Margin="0, 25, 25, 0" />

Height, WidthMargin을 이러한 값으로 설정하지 않아도 되지만, 이 설정은 대부분의 앱에 적합합니다.

검색 상자는 어디에 배치해야 할까요? 사용자가 원할 때마다 쉽게 검색할 수 있도록 앱의 각 페이지에 검색 상자를 배치하는 것이 좋습니다. 공간이 문제가 되는 경우 위쪽 앱 바에 검색 상자를 배치할 수 있습니다.

일반적으로 페이지의 오른쪽 위에 SearchBox를 배치하는 것이 가장 좋습니다. Visual Studio 템플릿을 통해 만든 대부분의 페이지(예: 기본 페이지 템플릿)에는 페이지 제목과 뒤로 단추가 포함된 Grid가 있습니다.


<!-- Back button and page title -->
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="120"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Button x:Name="backButton" Margin="39,59,39,0" 
                Command="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"
                Style="{StaticResource NavigationBackButtonNormalStyle}"
                VerticalAlignment="Top"
                AutomationProperties.Name="Back"
                AutomationProperties.AutomationId="BackButton"
                AutomationProperties.ItemType="Navigation Button"/>
    <TextBlock x:Name="pageTitle" Text="{StaticResource AppName}" 
                Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1" 
                IsHitTestVisible="false" TextWrapping="NoWrap" 
                VerticalAlignment="Bottom" Margin="0,0,30,40"/>
</Grid>

Grid에 세 번째 열을 추가하고 WidthAuto로 설정한 다음 SearchBox를 추가하고 Grid.Column을 "2"로 설정합니다.


<!-- Back button and page title -->
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="120"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <Button x:Name="backButton" Margin="39,59,39,0" 
                Command="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"
                Style="{StaticResource NavigationBackButtonNormalStyle}"
                VerticalAlignment="Top"
                AutomationProperties.Name="Back"
                AutomationProperties.AutomationId="BackButton"
                AutomationProperties.ItemType="Navigation Button"/>
    <TextBlock x:Name="pageTitle" Text="{StaticResource AppName}" 
                Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1" 
                IsHitTestVisible="false" TextWrapping="NoWrap" 
                VerticalAlignment="Bottom" Margin="0,0,30,40"/>
    <SearchBox
        Grid.Column="2"
        Height="35" Width="270"  Margin="0,25,25,0" />
</Grid>

SearchBox가 포함된 기본 페이지

이 빠른 시작의 예제에서는 허브 앱 템플릿을 사용합니다. 허브 페이지에 SearchBox를 추가하는 방법을 자세히 살펴보겠습니다.

Hh868180.wedge(ko-kr,WIN.10).gif허브 페이지에 SearchBox 추가

  1. 허브 페이지에 대한 XAML 파일을 열고 Hub 컨트롤을 정의하는 태그로 이동합니다. 일반적으로 이 페이지의 이름은 HubPage.xaml입니다.
  2. Hub 컨트롤의 HorizontalContentAlignmentStretch로 설정합니다.
    
    <Hub SectionHeaderClick="Hub_SectionHeaderClick" HorizontalContentAlignment="Stretch">
    
    
  3. Hub 컨트롤의 Header에서:

    1. Grid에 세 번째 열을 추가하고 해당 WidthAuto로 설정합니다.
    2. SearchBox를 추가합니다.

      • SearchBoxGrid.Column 속성을 "2"로 설정합니다.
      • 이름을 지정합니다. 이 예제에서는 "mySearchBox"를 사용합니다.
      • Height를 35픽셀, Width를 200픽셀로 설정합니다.
      • PlaceholderText를 "Search"로 설정합니다.
      • QuerySubmitted 이벤트를 "SearchBox_QuerySubmitted"로 설정합니다.
    
    
                <Hub.Header>
                    <!-- Back button and page title -->
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="80"/>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                        <Button  x:Name="backButton" Style="{StaticResource NavigationBackButtonNormalStyle}"
                            Margin="-1,-1,39,0" 
                            VerticalAlignment="Top"
                            Command="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"
                            AutomationProperties.Name="Back"
                            AutomationProperties.AutomationId="BackButton"
                            AutomationProperties.ItemType="Navigation Button"/>
                        <TextBlock x:Name="pageTitle" Text="{StaticResource AppName}" Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1" 
                            VerticalAlignment="Top" IsHitTestVisible="false" TextWrapping="NoWrap" />
                        <SearchBox
                            x:Name="mySearchBox"
                            Grid.Column="2"
                            Height="35" Width="270"
                            PlaceholderText="Search" 
                            QuerySubmitted="SearchBox_QuerySubmitted"/>
                    </Grid>
                </Hub.Header>
    
    

Hh868180.wedge(ko-kr,WIN.10).gifQuerySubmitted 이벤트 처리

  1. 허브 페이지의 코드 숨김 파일(HubPage.xaml.cs)을 엽니다. SearchBox에 대한 QuerySubmitted 이벤트 처리기를 만들고 이름을 SearchBox_QuerySubmitted로 지정합니다.
    
            private void SearchBox_QuerySubmitted(SearchBox sender, SearchBoxQuerySubmittedEventArgs args)
            {
    
            }
    
    
  2. 이벤트 처리기를 사용하여 새 검색 결과 페이지를 탐색합니다.
    
            private void SearchBox_QuerySubmitted(SearchBox sender, SearchBoxQuerySubmittedEventArgs args)
            {
                 this.Frame.Navigate(typeof(SearchResultsPageExample), args.QueryText);
            }
    
    

허브 페이지의 모양은 다음과 같습니다.

SearchBox가 포함된 허브 페이지

시도해 보세요. SearchBox에 테스트 쿼리를 입력하고 Enter 키를 누릅니다.

테스트 쿼리

작성한 QuerySubmitted 이벤트 처리기는 검색 결과 페이지를 탐색하고 입력된 쿼리를 전달합니다.

테스트 쿼리의 결과

검색 결과는 표시되지 않지만 검색 결과 페이지가 작동하고 있습니다. 다음 단계에서는 실제로 데이터에서 일치 항목을 검색하도록 페이지를 업데이트하겠습니다. 하지만 그 전에 검색 상자로 돌아가서 쿼리를 다시 입력합니다. 두 번째 쿼리 입력을 완료하기 전에 제안으로 표시되어야 합니다.

테스트 쿼리

SearchBox의 유용한 기능 중 하나는 검색 기록을 사용하여 자동으로 제안을 제공한다는 것입니다. 이후 단계에서 제안을 사용자 지정하는 방법에 대해 자세히 알아보겠습니다.

데이터 검색

이제 검색 결과 페이지로 돌아가겠습니다. 검색 결과 페이지는 검색 쿼리를 처리하고 결과를 표시합니다. 이 단계에서는 들어오는 쿼리를 처리하고 결과 목록을 준비하는 코드를 작성합니다.

Hh868180.wedge(ko-kr,WIN.10).gif데이터 가져오기 및 검색 결과 정의

  1. 검색 결과 페이지의 코드 숨김 파일인 SearchResultsPageExample.xaml.cs를 엽니다.
  2. 페이지 맨 위에 데이터 클래스에 대한 참조를 추가합니다. 앞에서 설명했듯이, 예제에서는 새 응용 프로그램을 만들 때 Visual Studio에서 만든 샘플 데이터를 사용합니다. 이러한 클래스는 <ApplicationNamespace>.Data 네임스페이스에 속합니다.
    
    
    // Change this to <YourApplicationNamespace>.Data
    using SearchBoxAndPageExample.Data;
    
    
    
  3. SearchResultsPageExample 클래스에서 결과를 저장 및 표시하기 위한 속성을 만듭니다. 이 예제에서는 Dictionary를 사용하여 결과를 저장합니다.
    
    public Dictionary<String, IEnumerable<SampleDataItem>> AllResultsCollection { get; set; }
    
    
    

검색 결과 페이지를 탐색할 때 앱이 Visual Studio에서 자동으로 생성한 메서드인 페이지의 navigationHelper_LoadState 메서드를 호출합니다. 지금은 해당 코드에서 많은 기능을 수행하지 않습니다. 다음 단계에서 이 코드를 데이터 검색에 사용되는 고유한 코드로 바꿉니다.

Hh868180.wedge(ko-kr,WIN.10).gif검색 논리 구현

  1. SearchResultsPageExample.xaml.cs 파일에서 navigationHelper_LoadState 메서드로 이동한 다음 메서드에 포함된 코드를 삭제합니다.
  2. async 키워드를 추가하여 navigationHelper_LoadState 메서드를 비동기로 설정합니다.
    
            private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
            {
    
    
  3. 검색 결과 페이지를 탐색할 때 앱이 검색 쿼리를 탐색 매개 변수로 전달합니다. LoadStateEventArgs 매개 변수, eNavigationParameter 속성에서 쿼리 텍스트를 검색합니다. LoadStateEventArgs 클래스는 그리드, 허브 또는 분할 앱을 만들 때 프로젝트에 포함된 도우미 파일 중 하나인 NavigationHelper.cs에서 정의됩니다.
    
    
                var queryText = e.NavigationParameter as String;
    
    
  4. 결과 목록을 초기화하고 총 일치 항목 수를 추적하기 위한 변수를 만듭니다.
    
    
                // Initialize the results list.
                AllResultsCollection = new Dictionary<string, IEnumerable<SampleDataItem>>();
    
                // Keep track of the number of matching items. 
                var totalMatchingItems = 0;
    
    
    
  5. 일치 항목을 찾을 때마다 일치 항목의 그룹을 필터 목록에 추가합니다. 검색 결과 페이지 템플릿에서 자동으로 Filter 클래스를 만듭니다. Filter 개체의 List를 만들겠습니다. 일치 항목을 찾으면 항목의 그룹을 필터 목록에 추가합니다.
    
    
                var filterList = new List<Filter>();
    
    
    
  6. 그런 다음 데이터를 검색하고 결과를 저장합니다. 먼저 데이터가 포함된 모든 그룹을 가져옵니다.
    
                          
                var groups = await SampleDataSource.GetGroupsAsync();
    
    
    

  7. 이제 일치 항목을 확인할 수 있도록 각 그룹을 반복하는 foreach 루프를 만듭니다.

    
    
                foreach (var group in groups)
                {
    
    
    
  8. foreach 루프 내:

    1. 데이터 클래스의 각 그룹 SampleDataGroup에는 SampleDataItem 개체의 ObservableCollection을 반환하는 Items 속성이 포함되어 있습니다. Where 메서드를 사용하여 이 컬렉션에서 일치 항목을 검색할 수 있습니다.

      이 예제에서는 대/소문자를 구분하지 않고 제목에 쿼리가 포함되어 있는 항목을 검색하고 반환된 일치 항목 컬렉션을 matchingItems 변수에 저장합니다. 이 예제에서는 각 항목의 제목만 확인합니다. 부제목, 설명 등의 추가 데이터를 확인할 수도 있습니다.

      
      
      
                      var matchingItems = group.Items.Where(
                          item => 
                              item.Title.IndexOf(
                                  queryText, StringComparison.CurrentCultureIgnoreCase) > -1); 
      
      
      
      

      이 예제에서는 IndexOf(String, StringComparison) 메서드를 사용하여 문자열 비교를 수행합니다. 문화권을 구분하고 대/소문자를 구분하지 않는 검색을 지정할 수 있도록 이 오버로드를 사용합니다. 검색 시 문화권을 구분하도록 설정하면 더 많은 언어에서 코드가 제대로 작동하는 데 도움이 됩니다.

        

      이 예제에서는 데이터의 한 필드(제목 필드)에서만 쿼리 일치 항목을 확인합니다. 실제 앱은 부제목, 설명 등의 여러 필드에서 일치 항목을 검색할 수 있습니다.

       
        

      사용자 환경을 향상하는 한 가지 방법으로 검색 요청의 관련성을 추적하고 정확도 순으로 결과를 정렬합니다. 예를 들어 일치 항목의 품질에 따라 각 일치 항목에 특정 개수의 포인트를 할당할 수 있습니다. 제목 필드의 일치 항목에는 5포인트가 할당되고, 부제목 필드의 일치 항목에는 2포인트가 할당되고, 설명 필드의 일치 항목에는 1포인트가 할당됩니다. 결과를 표시하기 전에 포인트가 가장 많은 항목이 첫 번째로 표시되도록 정렬합니다.

       
    2. 일치 항목 수를 확인합니다. 일치 항목이 있으면 결과 목록에 추가하고 그룹을 필터 목록에 추가합니다.

      
      
      
                      int numberOfMatchingItems = matchingItems.Count();
                      totalMatchingItems += numberOfMatchingItems;
                      if (numberOfMatchingItems > 0)
                      {
                          AllResultsCollection.Add(group.Title, matchingItems);
                          filterList.Add(new Filter(group.Title, numberOfMatchingItems));
                      }
                  }
      
      
  9. 그룹을 기준으로 필터링하는 기능은 유용하지만 사용자가 모든 검색 결과를 한 번에 보려는 경우도 있습니다. 필터 목록의 시작 부분에 "All" 항목을 추가합니다.
    
    
                // Create an entry for "All" for viewing all search results. 
                filterList.Insert(0, new Filter("All", totalMatchingItems, true));
    
    
    
  10. 샘플 결과 페이지에는 페이지의 기본 DataContext에 바인딩된 DefaultViewModel 속성이 있습니다. DefaultViewModel은 페이지 UI에 영향을 주는 개체를 저장하는 데 사용할 수 있는 사전 유형입니다. 이 속성을 사용하여 필터 및 원래 쿼리를 표시합니다. DefaultViewModel 개체의 "QueryText"를 원래 쿼리 텍스트로 설정하고, "Filters"를 "filterList"로 설정하고, "ShowFilters"를 true로 설정합니다.
    
    
                // Communicate results through the view model
                this.DefaultViewModel["QueryText"] = '\u201c' + queryText + '\u201d';
                this.DefaultViewModel["Filters"] = filterList;
                this.DefaultViewModel["ShowFilters"] = true;
            }
    
    

    다음은 업데이트된 메서드의 전체 코드입니다.

    
    
            private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
            {
                var queryText = e.NavigationParameter as String;
    
                // Initialize the results list.
                AllResultsCollection = new Dictionary<string, IEnumerable<SampleDataItem>>();
    
                // Keep track of the number of matching items. 
                var totalMatchingItems = 0;
    
                var filterList = new List<Filter>();
    
                var groups = await SampleDataSource.GetGroupsAsync();
                foreach (var group in groups)
                {
                    var matchingItems = group.Items.Where(
                        item => 
                            item.Title.IndexOf(
                                queryText, StringComparison.CurrentCultureIgnoreCase) > -1); 
                    int numberOfMatchingItems = matchingItems.Count();
                    totalMatchingItems += numberOfMatchingItems; 
                    if (numberOfMatchingItems > 0)
                    {
                        AllResultsCollection.Add(group.Title, matchingItems);
                        filterList.Add(new Filter(group.Title, numberOfMatchingItems));
                    }
                }
    
                // Create an entry for "All" for viewing all search results. 
                filterList.Insert(0, new Filter("All", totalMatchingItems, true));
    
                // Communicate results through the view model
                this.DefaultViewModel["QueryText"] = '\"' + queryText + '\"';
                this.DefaultViewModel["Filters"] = filterList;
                this.DefaultViewModel["ShowFilters"] = true;
    
            }
    
    

앱을 실행하고 "Item"을 검색합니다. 앱이 각 그룹에 대해 찾은 적중 횟수를 표시하지만 실제로 검색 결과를 표시하지는 않습니다.

검색 결과

검색 결과 표시

navigationHelper_LoadState 메서드가 항목을 검색하고 일치 결과와 필터를 저장하지만 실제로 결과를 표시하는 것은 Filter_Checked 이벤트 처리기입니다. 사용자가 필터를 선택하면 이 메서드에서 해당 필터와 일치하는 결과를 표시합니다.

Hh868180.wedge(ko-kr,WIN.10).gifFilter_Checked 메서드 업데이트

  1. 검색 결과 페이지의 코드 숨김 파일에서 Filter_Checked 메서드로 이동한 다음 메서드에 포함된 템플릿 생성 코드를 삭제합니다.
    
            void Filter_Checked(object sender, RoutedEventArgs e)
            {
    
            }
    
    
  2. 필터 목록은 라디오 단추 집합입니다. 이벤트를 발생시킨 라디오 단추의 DataContext를 검색하여 선택된 필터를 확인합니다.

    
    
            void Filter_Checked(object sender, RoutedEventArgs e)
            {
                var filter = (sender as FrameworkElement).DataContext as Filter;
    
    
    
  3. SearchResultsPageExample.xaml 파일에는 filtersViewSource라는 CollectionViewSource가 들어 있습니다. 이 데이터 원본은 필터 목록에 바인딩되어 있습니다. 사용자가 라디오 단추를 선택하면 MoveCurrentTo 메서드를 사용하여 현재 필터를 선택합니다.

    
    
                // Mirror the change into the CollectionViewSource.
                if (filtersViewSource.View != null)
                {
                    filtersViewSource.View.MoveCurrentTo(filter);
                }
    
    
    
  4. 필터가 null이 아닌지 확인한 다음 Active 속성을 true로 설정합니다. XAML 파일은 라디오 단추의 IsChecked 상태를 필터의 Active 속성에 바인딩하므로 이 속성을 업데이트하면 라디오 단추가 선택된 상태로 표시됩니다.

    
    
                // Determine which filter was selected
                if (filter != null)
                {
                    // Mirror the results into the corresponding Filter object to allow the
                    // RadioButton representation used when not snapped to reflect the change
                    filter.Active = true;
    
    
    
  5. 필터를 사용하여 결과 컬렉션에서 표시할 항목을 확인합니다. "all" 필터가 선택된 경우에는 모든 항목을 표시합니다.

    
    
                    if (filter.Name.Equals("All"))
                    {
                        var tempResults = new List<SampleDataItem>();
    
                        // Add the items from each group to the temporary results
                        // list. 
                        foreach (var group in AllResultsCollection)
                        {
                            tempResults.AddRange(group.Value);
                       
                        }
                        // Display the items.
                        this.DefaultViewModel["Results"] = tempResults;
                    }
    
    
    
  6. 그렇지 않으면 선택한 필터에 속하는 항목을 표시합니다.
    
    
                    else if (AllResultsCollection.ContainsKey(filter.Name))
                    {
                        this.DefaultViewModel["Results"] =
                          new List<SampleDataItem>(AllResultsCollection[filter.Name]);
                    }
    
    
    
  7. 실제로 표시할 결과가 있는지 확인합니다. 결과가 있는 경우 페이지 상태를 "ResultsFound" 상태로 변경합니다. 그렇지 않으면 페이지 상태를 "NoResultsFound"로 변경합니다.
    
                    // Ensure results are found
                    object results;
                    ICollection resultsCollection;
                    if (this.DefaultViewModel.TryGetValue("Results", out results) &&
                        (resultsCollection = results as ICollection) != null &&
                        resultsCollection.Count != 0)
                    {
                        VisualStateManager.GoToState(this, "ResultsFound", true);
                        return;
                    }
                }
    
                // Display informational text when there are no search results.
                VisualStateManager.GoToState(this, "NoResultsFound", true);
            }
    
    

다음은 Filter_Checked 메서드의 전체 코드입니다.


        void Filter_Checked(object sender, RoutedEventArgs e)
        {
            // Retrieve the data context of the sender (the selected radio button).
            // This gives us the selected Filter object. 
            var filter = (sender as FrameworkElement).DataContext as Filter;

            // Mirror the change into the CollectionViewSource.
            // This is most likely not needed.
            if (filtersViewSource.View != null)
            {
                filtersViewSource.View.MoveCurrentTo(filter);
            }

            // Determine which filter was selected
            if (filter != null)
            {
                // Mirror the results into the corresponding Filter object to allow the
                // RadioButton representation used when not snapped to reflect the change
                filter.Active = true;

                // TODO: Respond to the change in active filter by setting this.DefaultViewModel["Results"]
                //       to a collection of items with bindable Image, Title, Subtitle, and Description properties

                if (filter.Name.Equals("All"))
                {
                    var tempResults = new List<SampleDataItem>();

                    // Add the items from each group to the temporary results
                    // list. 
                    foreach (var group in AllResultsCollection)
                    {
                        tempResults.AddRange(group.Value);

                    }

                    // Display the items.
                    this.DefaultViewModel["Results"] = tempResults;
                }
                else if (AllResultsCollection.ContainsKey(filter.Name))
                {
                    this.DefaultViewModel["Results"] =
                      new List<SampleDataItem>(AllResultsCollection[filter.Name]);
                }

                // Ensure results are found
                object results;
                ICollection resultsCollection;
                if (this.DefaultViewModel.TryGetValue("Results", out results) &&
                    (resultsCollection = results as ICollection) != null &&
                    resultsCollection.Count != 0)
                {
                    VisualStateManager.GoToState(this, "ResultsFound", true);
                    return;
                }
            }

            // Display informational text when there are no search results.
            VisualStateManager.GoToState(this, "NoResultsFound", true);
        }

앱을 실행하고 "Item-1"을 검색합니다. 고유한 데이터를 사용 중인 경우 알고 있는 내용을 검색하여 적중 항목을 얻을 수 있습니다.

검색 결과

(옵션) GridView 컨트롤의 ItemTemplate 업데이트

SearchResultsPageExample.xaml은 GridView를 사용하여 검색 결과를 표시합니다. GridView 컨트롤의 ItemTemplate에 대한 템플릿 생성 코드는 Visual Studio에서 자동으로 만든 샘플 데이터 원본으로 작동하도록 작성되었습니다. 각 데이터 항목에 "Image", "Title", "Subtitle" 및 "Description" 필드가 있다고 가정합니다.

데이터 항목에 다른 필드가 있는 경우 ItemTemplate을 수정해야 합니다. ItemTemplate을 수정하는 방법에 대한 자세한 내용은 빠른 시작: ListView 및 GridView 컨트롤 추가를 참조하세요.

(옵션) 검색 제안 추가

검색 제안은 검색 창의 검색 상자 아래에 표시됩니다. 제안은 사용자의 시간을 절약하고 앱에서 사용자가 검색할 수 있는 항목의 종류에 대한 유용한 힌트를 제공하므로 중요합니다.

여러 소스에서 제안을 가져올 수 있습니다.

  • 직접 제안을 정의할 수 있습니다. 예를 들어 자동차 제조업체 목록을 만들 수 있습니다.
  • 앱이 로컬 파일을 검색하는 경우 Windows에서 제안을 가져올 수 있습니다.
  • 웹 서비스나 서버에서 제안을 가져올 수 있습니다.

제안을 표시하는 방법에 대한 사용자 환경 지침은 검색에 대한 지침 및 검사 목록을 참조하세요.

LocalContentSuggestionSettings를 사용하면 Windows의 로컬 파일을 기반으로 단 몇 줄의 코드만 사용하여 제안을 추가할 수 있습니다. 또는 검색 상자 컨트롤의 SuggestionsRequested 이벤트를 등록하고 다른 소스(예: 로컬에 정의된 목록 또는 웹 서비스)에서 검색한 제안으로 구성되는 제안 목록을 직접 작성할 수 있습니다. 이 빠른 시작에서는 SuggestionsRequested 이벤트를 처리하는 방법을 보여 줍니다.

검색 제안을 추가하는 방법을 보여 주는 코드 예제는 SearchBox 컨트롤 샘플(영문)을 다운로드하세요. 샘플에서는 세 가지 가능한 소스를 모두 사용하여 검색 제안을 추가하는 방법 및 IME(입력기)에서 생성된 쿼리 텍스트의 대체 형식을 사용하여 동아시아 언어에 대한 제안을 추가하는 방법을 보여 줍니다. 일본어 또는 중국어 사용자가 앱을 사용하는 경우 쿼리 텍스트 대안을 사용하는 것이 좋습니다.

Hh868180.wedge(ko-kr,WIN.10).gifSuggestionsRequested 이벤트 처리

  1. 앱에 SearchBox 컨트롤이 여러 개 있을 수도 있습니다. SearchResultsPageExample.xaml.cs 파일에서 모든 컨트롤이 사용할 수 있는 단일 정적 이벤트 처리기를 정의하겠습니다. Filter_Checked 메서드 뒤에 이 코드를 추가합니다.
    
            public async static void SearchBox_SuggestionsRequested(
                SearchBox sender, 
                SearchBoxSuggestionsRequestedEventArgs args)
            {
    
    
  2. SuggestionsRequested 이벤트에 비동기적으로 응답하려면 제안 목록을 편집하기 전에 SearchSuggestionsRequestDeferral 개체를 가져와야 합니다.
    
                // This object lets us edit the SearchSuggestionCollection asynchronously. 
                var deferral = args.Request.GetDeferral();
    
    
  3. 사용자가 수행한 이전 검색 등의 일부 검색 제안이 자동으로 제공됩니다. 시스템에서 제공하는 항목에 검색 제안을 추가하겠습니다.

    
                try { 
    
                    // Retrieve the system-supplied suggestions.
                    var suggestions = args.Request.SearchSuggestionCollection;
    
    
  4. 데이터의 각 항목을 반복하고 일치 항목을 확인합니다. 일치 항목을 찾으면 검색 제안 컬렉션에 일치 항목의 제목을 추가합니다.

    
                    var groups = await SampleDataSource.GetGroupsAsync();
                    foreach (var group in groups)
                    {
                        var matchingItems = group.Items.Where(
                            item => item.Title.StartsWith(
                                args.QueryText, StringComparison.CurrentCultureIgnoreCase));
    
                        foreach (var item in matchingItems)
                        {
                            suggestions.AppendQuerySuggestion(item.Title);
                        }
                    }
            
    
    
  5. SearchBoxSuggestionsRequestEventArgs.LinguisticDetails.QueryTextAlternatives 속성은 IME에서 사용자가 입력한 텍스트에 대한 추가 제안을 제공합니다. 이러한 제안을 사용하면 동아시아 언어 사용자의 검색 환경이 향상됩니다. 원래 쿼리가 포함된 문자열에 대한 쿼리 텍스트 대안을 확인하고 검색 제안 목록에 추가하겠습니다.

    
                    foreach (string alternative in args.LinguisticDetails.QueryTextAlternatives)
                    {
                        if (alternative.StartsWith(
                            args.QueryText, StringComparison.CurrentCultureIgnoreCase))
                        {
                            suggestions.AppendQuerySuggestion(alternative); 
                        }
                    }
                }
    
    
  6. 마지막으로 SearchSuggestionsRequestDeferral을 사용하여 시스템에 제안 목록 편집을 완료했다는 것을 알립니다.

    
                finally {
                    deferral.Complete();
                }
    
            }
    
    

    이것이 검색 제안 이벤트 처리기에 필요한 모든 코드입니다. 다음은 전체 SearchBox_SuggestionsRequested 메서드입니다.

    
            public async static void SearchBox_SuggestionsRequested(
                SearchBox sender, 
                SearchBoxSuggestionsRequestedEventArgs args)
            {
    
                // This object lets us edit the SearchSuggestionCollection asynchronously. 
                var deferral = args.Request.GetDeferral();
    
                try { 
    
                    // Retrieve the system-supplied suggestions.
                    var suggestions = args.Request.SearchSuggestionCollection;
               
                    var groups = await SampleDataSource.GetGroupsAsync();
                    foreach (var group in groups)
                    {
                        var matchingItems = group.Items.Where(
                            item => item.Title.StartsWith(
                                args.QueryText, StringComparison.CurrentCultureIgnoreCase));
    
                        foreach (var item in matchingItems)
                        {
                            suggestions.AppendQuerySuggestion(item.Title);
                        }
                    }
                
                    foreach (string alternative in args.LinguisticDetails.QueryTextAlternatives)
                    {
                        if (alternative.StartsWith(
                            args.QueryText, StringComparison.CurrentCultureIgnoreCase))
                        {
                            suggestions.AppendQuerySuggestion(alternative); 
                        }
                    }
                }
                finally {
                    deferral.Complete();
                }
    
            }
    
    
  7. 이제 SearchBox에 이벤트를 등록하겠습니다.

    이 이벤트 처리기는 정적이므로 XAML에서 이벤트 처리기를 설정할 수 없습니다. 대신, SearchBox가 포함된 페이지의 코드 숨김 파일을 열고 페이지의 생성자를 사용하여 이벤트를 등록합니다.

    
            public HubPage()
            {
                this.InitializeComponent();
                this.navigationHelper = new NavigationHelper(this);
                this.navigationHelper.LoadState += navigationHelper_LoadState;
    
                // Register for the SuggestsRequested event.
                mySearchBox.SuggestionsRequested += SearchResultsPageExample.SearchBox_SuggestionsRequested;
        
            }
    
    

검색 계약 구현(이전 Windows 버전)

Windows 8.1 이전에는 앱이 검색 참 메뉴를 사용하여 앱에서 바로 검색을 제공했습니다. 개발자는 검색 계약을 구현하고 SearchPane API를 사용하여 쿼리를 처리하고 제안 및 결과를 가져왔습니다.

Windows 8 검색 계약 및 SearchPane API도 계속 지원되지만 Windows 8.1부터는 SearchPane 대신 SearchBox 컨트롤을 사용하는 것이 좋습니다. SearchBox를 사용하는 앱은 검색 계약을 구현할 필요가 없습니다.

앱이 SearchPane 및 검색 계약을 사용해야 하나요? 사용자가 앱을 자주 검색할 것 같지 않은 경우 SearchPane 및 검색 계약을 사용할 수 있습니다. 사용자가 검색 창을 활성화하기 위해 클릭할 수 있는 검색 문자 모양(Segoe UI Symbol 0xE0094, 15pt)이 포함된 단추를 앱에 사용하는 것이 좋습니다. SearchPane 및 검색 계약을 구현하는 코드를 보려면 검색 계약 샘플을 참조하세요.

요약 및 다음 단계

SearchBox 컨트롤과 검색 결과 페이지를 사용하여 앱에 검색 기능을 추가했습니다.

사용자에게 적합한 검색 환경 설계 및 만들기에 대한 지침은 검색에 대한 지침 및 검사 목록을 참조하세요.

관련 항목

SearchBox 컨트롤 샘플
검색에 대한 지침 및 검사 목록

 

 

표시:
© 2017 Microsoft