代码之家  ›  专栏  ›  技术社区  ›  Damn Vegetables

WPF,组合框,按类型显示候选者,但不自动完成?

  •  0
  • Damn Vegetables  · 技术社区  · 3 年前

    有没有可能让WPF组合框显示下面的候选人,比如谷歌的建议是如何工作的,但不能自动完成输入字段上的其余文本?

    例如,如果我在底部的WPF代码中键入“b”,我就会得到这个。

    enter image description here

    但这导致了使用文本合成的亚洲语言输入法的一些问题。此外,这并没有显示所有其他以“b”开头的候选者。相反,我可以像大多数IDE文本编辑器一样,让WPF ComboBox显示为这样,并让用户使用箭头键和选项卡选择候选者吗?

    enter image description here

        <ComboBox HorizontalAlignment="Left" Margin="111,61,0,0" VerticalAlignment="Top" Width="120" IsEditable="True">
            <ComboBoxItem Content="Alice"/>
            <ComboBoxItem Content="Bob"/>
            <ComboBoxItem Content="Bart"/>
            <ComboBoxItem Content="Bort"/>
            <ComboBoxItem Content="Charlie"/>
        </ComboBox>
    
    0 回复  |  直到 3 年前
        1
  •  0
  •   EldHasp    3 年前

    可以根据输入的文本对ItemsSource集合的项进行筛选。
    但是,在我看来,不可能改变第一个合适的自动选择——这种行为嵌套在ComboBox逻辑中。
    并且不可能将用户输入与第一元素的文本区分开。 因此,过滤也不可能正确配置。
    在我看来,如果不更改组合框模板或用您自己的自定义元素替换它,就不可能实现这一点。

    基于扩展器的实现示例:

    首先,永远不要用UI项填充ComboBox、ListBox(和其他ItemsControl)。
    创建一个可观察的集合并将其传递给ItemsSource。

    其次,获取此集合的表示形式,并在其Filter属性中设置用于筛选元素的处理程序方法。
    它应该将传递给ItemsSource的集合的元素与指定筛选器模板的Text值进行比较。
    如果Text为空(string.IsNullOrWhiteSpace(Text)=true),则筛选器应跳过所有元素。

    第三,当Text更改时,在集合视图上调用Reftech。

    <Window x:Class="FilterComboBox.FilterComboBoxWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:FilterComboBox"
            mc:Ignorable="d"
            Title="FilterComboBoxWindow" Height="450" Width="800">
        <Grid x:Name="grid">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Expander>
                <Expander.Header>
                    <TextBox x:Name="tBox" MinWidth="100"
                             TextChanged="OnTextChanged"/>
                </Expander.Header>
                <ListBox x:Name="listBox" SelectionChanged="OnSelectionChanged"/>
                <Expander.Style>
                    <Style TargetType="Expander">
                        <Style.Triggers>
                            <Trigger Property="IsKeyboardFocusWithin" Value="True">
                                <Setter Property="IsExpanded" Value="True"/>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Expander.Style>
    
            </Expander>
            <TextBlock Grid.Row="1" Text="{Binding SelectedItem, ElementName=listBox}"/>
        </Grid>
    </Window>
    
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    
    namespace FilterComboBox
    {
        /// <summary>
        /// Логика взаимодействия для FilterComboBoxWindow.xaml
        /// </summary>
        public partial class FilterComboBoxWindow : Window
        {
            private readonly ObservableCollection<string> contetnItems
                = new ObservableCollection<string>()
                {
                    "Alice",
                    "Bob",
                    "Bart",
                    "Bort",
                    "Charlie"
                };
    
            public FilterComboBoxWindow()
            {
                InitializeComponent();
    
                ICollectionView view = CollectionViewSource.GetDefaultView(contetnItems);
                view.Filter = OnFilter;
                listBox.ItemsSource = contetnItems;
            }
    
    
    
            private bool OnFilter(object obj)
            {
                return
                    string.IsNullOrWhiteSpace(tBox.Text) ||
                    ((obj is string text) && text.ToUpper().StartsWith(tBox.Text.ToUpper()));
            }
    
            private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                tBox.Text = listBox.SelectedItem?.ToString();
            }
    
            private void OnTextChanged(object sender, TextChangedEventArgs e)
            {
                CollectionViewSource.GetDefaultView(contetnItems).Refresh();
            }
        }
    }
    

    附笔。 使用MVVM模式可以更方便、更正确地执行这些操作。