読者です 読者をやめる 読者になる 読者になる

C# + WPF で、WPFToolKitのAutoCompleteBoxを使ってオートコンプリートを行う

C# WPF

引き続き、Microsoft.TeamFoundation.MVVM名前空間を使って作る、WPFアプリの話です。

GoogleExcelでオートコンプリート、VisualStudioでインテリセンスを使ったりしているのですが、WPFでも同じことができるのかなと思い、試してみました。

 
2015/12/10 追記 ここから

公式Blogに以下の記事が掲載されましたので、Microsoft.TeamFoundation.MVVMの使用前に記事を確認してみてください。
Microsoft.TeamFoundation.MVVM 名前空間の利用について - Visual Studio サポート チーム blog - Site Home - MSDN Blogs

2015/12/10 追記 ここまで

 

環境

 

調査

オートコンプリートコントロールはWPFの標準コントロールとしては用意されていないようでした*1

 
Webで探してみるとオートコンプリートのコントロールを自作した記事がいくつかありましたが、便利そうなライブラリがないかを探してみたところ、stackoverflowに情報がありました。
c# - WPFToolkit : Type reference cannot find a public type - Stack Overflow

 
stackoverflowでは、

の2つのライブラリが紹介されていましたが、オートコンプリートの場合はWPF Toolkitのみに含まれるAutoCompleteBoxを使えば良いということが分かりました*2

 
そこで、以下の記事を参考に、WPF ToolkitのAutoCompleteBoxを使って作ってみることにしました。
WPF: AutoCompleteBox, an autocomplete text box - broculos

 

作るもの

  • オートコンプリートのソースとして、以下を用意

  • AutoCompleteBoxに以下を入力すると、オートコンプリートで「りんご名 + ID」を表示

    • 「シナノ」の場合、シナノゴールド・シナノドルチェが表示
    • 「ゴールド」の場合、シナノゴールド・ジョナゴールドが表示
    • 「ナ」の場合、全部表示

 

プロジェクトの準備

NuGetよりWPF Toolkitをインストール

WPF Toolkitで検索するといくつか引っかかりますが、識別:WPFToolkit作成者:JenniLe, Shimmyのものをインストールします。
NuGet Gallery | WPF Toolkit 3.5.50211.1

 

View (AutoCompleteView.xaml)

名前空間の追加

DataContext用にlocalを、AutoCompleteBox用にtoolkitを、それぞれ追加します。

<Window x:Class="AutoCompleteBoxMVVM.AutoCompleteView"
        ...
        xmlns:local="clr-namespace:AutoCompleteBoxMVVM"
        xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"
        ...>

 

DataContext の追加

いつもどおり、ViewModelを指定します。

<Window.DataContext>
    <local:AutoCompleteViewModel/>
</Window.DataContext>

 

Resourcesの追加

AutoCompleteBoxで使うDataTemplateを定義します。

AutoCompleteBoxのItemsSourceにデータバインディングしたオブジェクトに含まれるプロパティ(Name, ID)をLabelのContentとして表示します。

<Window.Resources>
    <DataTemplate x:Key="AutoCompleteBoxItemTemplate">
        <StackPanel Orientation="Horizontal">
            <Label Content="{Binding Name}"
                   Width="100" />
            <Label Content="{Binding ID}"
                   FontStyle="Italic"
                   Foreground="DarkGray" />
        </StackPanel>
    </DataTemplate>
</Window.Resources>

 

AutoCompleteBoxを追加

以下のプロパティにデータバインディングしておきます。

項目 用途など
ItemsSource オートコンプリートで表示されるソース
ValueMemberPath ItemsSourceのうち、実際に使用する値が含まれる項目(ComboBoxのものと同じようなもの)
SelectedItem オートコンプリートで選択した値(ただし、ItemsSourceに無い値が入力されると、nullになる)
Text AutoCompleteBoxに入力されている値 (ItemsSourceに無い値でも、その値がセット)
ItemTemplate 使用するDataTemplate
ItemFilter オートコンプリートで表示するときのフィルター

 

<toolkit:AutoCompleteBox Grid.Row="0" Margin="10,0,0,0" Width="150"
                         ItemsSource="{Binding Path=RingoSource}"
                         ValueMemberPath="Name"
                     
                         SelectedItem="{Binding Path=SelectedRingo, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
                         Text="{Binding Path=SelectedRingoName, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
                         
                         ItemTemplate="{StaticResource ResourceKey=AutoCompleteBoxItemTemplate}"
                         ItemFilter="{Binding RingoFilter}"/>

 

ViewModel (AutoCompleteViewModel.cs)

Viewでデータバインディングを定義したプロパティを実装します。

 

オートコンプリートのソース

手間を省くため、今回はViewModelでソースを生成しておきます。

private ObservableCollection<Ringo> _ringoSource;
public ObservableCollection<Ringo> RingoSource
{
    get
    {
        if (_ringoSource == null)
        {
            _ringoSource = new ObservableCollection<Ringo>()
            {
                new Ringo(){ ID = 1, Name = "シナノゴールド" },
                new Ringo(){ ID = 2, Name = "シナノドルチェ" },
                new Ringo(){ ID = 3, Name = "ジョナゴールド" }
            };
        }
        return _ringoSource;
    }
}

 

オートコンプリートのフィルター

AutoCompleteFilterPredicateデリゲートに合わせてフィルターを用意します。
Windows Presentation Foundation (WPF) - Source Code

今回は、入力された文字列が含まれているソースを表示します。

public AutoCompleteFilterPredicate<object> RingoFilter
{
    get { return (searchText, obj) => (obj as Ringo).Name.Contains(searchText); }
}

 
他のプロパティはいつもと同じなので、省略します。

 

Model (Ringo.cs)

IDとNameというプロパティを持つ簡単なModelなので省略します。

 

実行イメージ

起動後

f:id:thinkAmi:20140917152422p:plain

 

「シナノ」と入力

f:id:thinkAmi:20140917152428p:plain

 

「ゴールド」と入力

f:id:thinkAmi:20140917152432p:plain

 

「ナ」と入力

f:id:thinkAmi:20140917152437p:plain

 

ソースコード

GitHubに上げました。
CSharp-Sample/MVVMApp/AutoCompleteBoxMVVM at master · thinkAmi/CSharp-Sample · GitHub

 

その他資料

自作されてるかた

*1:Silverlightでは用意されていました - AutoCompleteBox クラス (System.Windows.Controls) - MSDN)

*2:なお、Extended WPF Toolkitの公式のフォーラムでもAutoCompleteBox はWPF Toolkitにあるとの記載がありました。
Extended WPF Toolkit™ Community Edition - AutoCompleteBox Selection