在WPF中搜索可搜索的组合框

时间:2017-07-21 12:29:57

标签: wpf xaml combobox

我有自定义的ComboBox:

public class CustomComboBox : ComboBox
{
    protected override void OnSelectionChanged(SelectionChangedEventArgs e)
    {
        // allow to go into items using up and down arrows without causing the text change
        e.Handled = true;
    }
}

和xaml as:

<Window>
    <Grid>
        <wpfApplication1:CustomComboBox IsEditable="True" 
                  Width="200" 
                  Height="25" 
                  IsTextSearchEnabled="False" 
                  StaysOpenOnEdit="True"
                  x:Name="cb" 
                  PreviewTextInput="Cb_OnPreviewTextInput" 
                  ItemsSource="{Binding Projects}" 
                  Text="{Binding Text}"
                  SelectionChanged="Cb_OnSelectionChanged">
            <ComboBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel />
                </ItemsPanelTemplate>
            </ComboBox.ItemsPanel>
        </wpfApplication1:CustomComboBox>
    </Grid>
</Window>

窗口代码:

public partial class MainWindow : INotifyPropertyChanged
{
    public ICollectionView Projects { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;

        ObservableCollection = new ObservableCollection<string>(Enumerable.Range(1, 1000).Select(i => $"Item {i}"));

        Projects = CollectionViewSource.GetDefaultView(ObservableCollection);
    }

    private string _text;
    public ObservableCollection<string> ObservableCollection { get; set; }

    public string Text
    {
        get { return _text; }
        set
        {
            if (_text != value)
            {
                _text = value;
                OnPropertyChanged();

                Projects.Filter = f =>
                {
                    var search = Text.ToLower();
                    var item = f.ToString().ToLower();

                    return item.Contains(search);
                };
            }
        }
    }

    private void Cb_OnPreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        cb.IsDropDownOpen = true;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

调用Cb_OnPreviewTextInput时,我设置了IsDropdownOpen = true。在第一次尝试时(键入第一个字母后),列表中的第一个项目被选中,我可以使用相关箭头上下移动,插入符号仍然在TextBox

当我继续打字时,我',我无法上下导航(当时只有1项),此时整个ScrollViewer得到了关注,我只能去底部或顶部,但不是1乘1.我必须关闭弹出窗口,例如按Escape,然后输入1个字符重新打开,以便能够再次上/下。

我也注意到在按下PageUp之后第一个项目也被选中了,所以我试图在代码中模仿它,但没有运气。

任何人都知道该怎么做才能上下滑动并输入没有问题?

我尝试过这样的事情:

protected override void OnPreviewKeyDown(KeyEventArgs e)
{
    if (_popup != null && e.Key == Key.Up || e.Key == Key.Down)
    {
        Dispatcher.BeginInvoke(DispatcherPriority.Input, 
        new Action(() =>
        {
            var c = _popup.Child;
            var vs = c.GetChildOfType<VirtualizingStackPanel>();
            vs.PageUp();
            vs.Focus();
            Keyboard.Focus(vs);
        }));
    }

    base.OnPreviewKeyDown(e);
}

但那没用。

1 个答案:

答案 0 :(得分:0)

最后编写一个包含ListView的新模板。

OnPreviewKeyDown内添加自定义逻辑:

if (e.Key == Key.Up || e.Key == Key.Down)
{
    listView.Focus();
    listView.Items.MoveCurrentTo(listView.SelectedItem);

    if (e.Key == Key.Up)
        listView.Items.MoveCurrentToPrevious();
    else
        listView.Items.MoveCurrentToNext();

    listView.SelectedItem = listView.Items.CurrentItem;
    listView.ScrollIntoView(listView.Items.CurrentItem);

    e.Handled = true;

    return;
}

运作良好;)