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

アニメイトラボ開発者ブログ

株式会社アニメイトラボの開発者ブログです


アニメイトラボ開発者ブログ

developer.animatelab.com


初心者でも分かる、オートコンプリート機能の導入方法〜成功・失敗例を図解!

この記事はanimateLAB Advent Calendar 2015 11日目の記事です。

こんにちは、sugicyanです。
前回に引き続き、Windows Presentation Foundation (WPF)を活用した業務アプリ開発の話をしようと思います。
先日、社内で「テキストで同じ文字を入力することが多いのでオートコンプリートを出して入力の手間を省けないか」という相談を受けました。
ちなみに、オートコンプリートというのはgoogleで検索するときなどに出てくるものです。
↓見慣れたこれですね。

f:id:sugicyan:20151209224649p:plain

まずは、技術選択

試しに、テキストボックスに「ご」と入力する例をやってみます。 候補リストとして

の2つを出すというものです。

今回は、2つの方法を試しました。

  1. Popupを使う方法
  2. WPF Toolkit*1を使う方法

結果を言ってしまうと、popupを使う方法ではうまくいきませんでした。
ですが、せっかく試したので失敗してしまった理由も合わせて書こうと思います。

1. Popupを出す方法が何故、失敗したのか

まず、浮かんだ方法はテキストに文字が入力された際、候補となる文字が含まれていればPopupを出すという方法です。
実装したソースは以下です。

ビュー

<Grid>
    <TextBox TextChanged="TextBoxBase_OnTextChanged" />
    <Popup x:Name="Popup"
          IsOpen="False"
          StaysOpen="False">
        <ListBox x:Name="ListBox"
             ItemsSource="{Binding Collection}"
             IsTextSearchEnabled="True">
        </ListBox>
    </Popup>
</Grid>

ListBoxとBindingされている要素

var Collection = new ObservableCollection<string>();
Collection.Add("ご注文はうさぎですか?");
Collection.Add("ご注文はうさぎですか??");

テキスト入力時の処理

private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e)
{
    var textBox = sender as TextBox;
    if (string.IsNullOrEmpty(textBox.Text))
    {
        return;
    }

    var l = ((MainWindowViewModel) DataContext).Collection.Where(_ => _.StartsWith(textBox.Text)).ToList();
    if (l.Count < 1)
    {
        return;
    }

    Popup.PlacementTarget = textBox;
    Popup.PlacementRectangle = textBox.GetRectFromCharacterIndex(textBox.CaretIndex);
    Popup.IsOpen = true;
    ListBox.Focus();

    e.Handled = true;
}

候補を出すことができました。 f:id:sugicyan:20151209215938p:plain

この方法は、「ご」と入力したときにPopupが出るところまでは問題ないです。
ですが、フォーカスがPopupに移ってしまい続けて文字を入力することができないという結果になりました。

2. WPF Toolkitを使った成功事例

僕が試した方法では、Popupでは失敗してしまいました。
ググってみると、WPF Toolkitを使うと良いという情報があったので、早速試してみます。

  1. NuGetでWPF Toolkitをインストール
<Window x:Class="WpfApplication4.MainWindow"
        ...
        xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"
        ...
        >
  1. XAML名前空間に追加
  2. TextBoxをtoolkit:AutoCompleteBoxに書き換える
<toolkit:AutoCompleteBox Margin="10,10,0,0"
                         VerticalAlignment="Top"
                         HorizontalAlignment="Left"
                         Width="150"
                         Height="23"
                         ItemsSource="{Binding Collection}"
                         Text="{Binding Path=SelectedRingoName, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
                         ItemFilter="{Binding Filter}" />

f:id:sugicyan:20151209224240p:plain f:id:sugicyan:20151209224245p:plain

この方法であれば、候補を出しつつそのまま文字入力を続けることができます。
今までオートコンプリートという機能は導入したことがなかったのですが、簡単に導入できたので、まだ試されていない方は、一度試してみてください。

*1:WPFを拡張するものです。NuGet Gallery | WPF Toolkit 3.5.50211.1