wpf 自定义控件 AutoCompleteComboBox

<ComboBox x:Class="View.AutoCompleteComboBox"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:View"
    mc:Ignorable="d" 
    d:DesignWidth="300"
    d:DesignHeight="300"
    IsEditable="True"
    IsTextSearchEnabled="False"
    PreviewKeyDown="ComboBox_PreviewKeyDown"
    />
AutoCompleteComboBox.xaml.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;

namespace View
{
    /// <summary>
    /// AutoCompleteComboBox.xaml
    /// </summary>
    public partial class AutoCompleteComboBox : ComboBox
    {
        readonly SerialDisposable disposable = new SerialDisposable();

        TextBox editableTextBoxCache;

        Predicate<object> defaultItemsFilter;

        public TextBox EditableTextBox
        {
            get
            {
                if (editableTextBoxCache == null)
                {
                    const string name = "PART_EditableTextBox";
                    editableTextBoxCache = (TextBox)VisualTreeModule.FindChild(this, name);
                }
                return editableTextBoxCache;
            }
        }

        /// <summary>
        /// Gets text to match with the query from an item.
        /// Never null.
        /// </summary>
        /// <param name="item"/>
        string TextFromItem(object item)
        {
            if (item == null) return string.Empty;

            var d = new DependencyVariable<string>();
            d.SetBinding(item, TextSearch.GetTextPath(this));
            return d.Value ?? string.Empty;
        }

        protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
        {
            base.OnItemsSourceChanged(oldValue, newValue);

            defaultItemsFilter = newValue is ICollectionView cv ? cv.Filter : null;
        }

        #region Setting
        static readonly DependencyProperty settingProperty =
            DependencyProperty.Register(
                "Setting",
                typeof(AutoCompleteComboBoxSetting),
                typeof(AutoCompleteComboBox)
            );

        public static DependencyProperty SettingProperty
        {
            get { return settingProperty; }
        }

        public AutoCompleteComboBoxSetting Setting
        {
            get { return (AutoCompleteComboBoxSetting)GetValue(SettingProperty); }
            set { SetValue(SettingProperty, value); }
        }

        AutoCompleteComboBoxSetting SettingOrDefault
        {
            get { return Setting ?? AutoCompleteComboBoxSetting.Default; }
        }
        #endregion

        #region OnTextChanged
        long revisionId;
        string previousText;

        struct TextBoxStatePreserver
            : IDisposable
        {
            readonly TextBox textBox;
            readonly int selectionStart;
            readonly int selectionLength;
            readonly string text;

            public void Dispose()
            {
                textBox.Text = text;
                textBox.Select(selectionStart, selectionLength);
            }

            public TextBoxStatePreserver(TextBox textBox)
            {
                this.textBox = textBox;
                selectionStart = textBox.SelectionStart;
                selectionLength = textBox.SelectionLength;
                text = textBox.Text;
            }
        }

        static int CountWithMax<T>(IEnumerable<T> xs, Predicate<T> predicate, int maxCount)
        {
            var count = 0;
            foreach (var x in xs)
            {
                if (predicate(x))
                {
                    count++;
                    if (count > maxCount) return count;
                }
            }
            return count;
        }

        void Unselect()
        {
            var textBox = EditableTextBox;
            textBox.Select(textBox.SelectionStart + textBox.SelectionLength, 0);
        }

        void UpdateFilter(Predicate<object> filter)
        {
            using (new TextBoxStatePreserver(EditableTextBox))
            using (Items.DeferRefresh())
            {
                // Can empty the text box. I don't why.
                Items.Filter = filter;
            }
        }

        void OpenDropDown(Predicate<object> filter)
        {
            UpdateFilter(filter);
            IsDropDownOpen = true;
            Unselect();
        }

        void OpenDropDown()
        {
            var filter = GetFilter();
            OpenDropDown(filter);
        }

        void UpdateSuggestionList()
        {
            var text = Text;

            if (text == previousText) return;
            previousText = text;

            if (string.IsNullOrEmpty(text))
            {
                IsDropDownOpen = false;
                SelectedItem = null;

                using (Items.DeferRefresh())
                {
                    Items.Filter = defaultItemsFilter;
                }
            }
            else if (SelectedItem != null && TextFromItem(SelectedItem) == text)
            {
                // It seems the user selected an item.
                // Do nothing.
            }
            else
            {
                using (new TextBoxStatePreserver(EditableTextBox))
                {
                    SelectedItem = null;
                }

                var filter = GetFilter();
                var maxCount = SettingOrDefault.MaxSuggestionCount;
                var count = CountWithMax(ItemsSource?.Cast<object>() ?? Enumerable.Empty<object>(), filter, maxCount);

                if (count > maxCount) return;

                OpenDropDown(filter);
            }
        }

        void OnTextChanged(object sender, TextChangedEventArgs e)
        {
            var id = unchecked(++revisionId);
            var setting = SettingOrDefault;

            if (setting.Delay <= TimeSpan.Zero)
            {
                UpdateSuggestionList();
                return;
            }

            disposable.Content =
                new Timer(
                    state =>
                    {
                        Dispatcher.InvokeAsync(() =>
                        {
                            if (revisionId != id) return;
                            UpdateSuggestionList();
                        });
                    },
                    null,
                    setting.Delay,
                    Timeout.InfiniteTimeSpan
                );
        }
        #endregion

        void ComboBox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (Keyboard.Modifiers.HasFlag(ModifierKeys.Control) && e.Key == Key.Space)
            {
                OpenDropDown();
                e.Handled = true;
            }
        }

        Predicate<object> GetFilter()
        {
            var filter = SettingOrDefault.GetFilter(Text, TextFromItem);

            return defaultItemsFilter != null
                ? i => defaultItemsFilter(i) && filter(i)
                : filter;
        }

        public AutoCompleteComboBox()
        {
            InitializeComponent();

            AddHandler(TextBoxBase.TextChangedEvent, new TextChangedEventHandler(OnTextChanged));
        }
    }
}

 

AutoCompleteComboBoxSetting.cs

using System;

namespace View
{
    /// <summary>
    /// Represents an object to configure <see cref="AutoCompleteComboBox"/>.
    /// </summary>
    public class AutoCompleteComboBoxSetting
    {
        /// <summary>
        /// Gets a filter function which determines whether items should be suggested or not
        /// for the specified query.
        /// Default: Gets the filter which maps an item to <c>true</c>
        /// if its text contains the query (case insensitive).
        /// </summary>
        /// <param name="query">
        /// The string input by user.
        /// </param>
        /// <param name="stringFromItem">
        /// The function to get a string which identifies the specified item.
        /// </param>
        /// <returns></returns>
        public virtual Predicate<object> GetFilter(string query, Func<object, string> stringFromItem)
        {
            return item => stringFromItem(item).IndexOf(query, StringComparison.InvariantCultureIgnoreCase) >= 0;
        }

        /// <summary>
        /// Gets an integer.
        /// The combobox opens the drop down
        /// if the number of suggested items is less than the value.
        /// Note that the value is larger, it's heavier to open the drop down.
        /// Default: 100.
        /// </summary>
        public virtual int MaxSuggestionCount
        {
            get { return 100; }
        }

        /// <summary>
        /// Gets the duration to delay updating the suggestion list.
        /// Returns <c>Zero</c> if no delay.
        /// Default: 300ms.
        /// </summary>
        public virtual TimeSpan Delay
        {
            get { return TimeSpan.FromMilliseconds(300.0); }
        }

        static AutoCompleteComboBoxSetting @default = new AutoCompleteComboBoxSetting();

        /// <summary>
        /// Gets the default setting.
        /// </summary>
        public static AutoCompleteComboBoxSetting Default
        {
            get { return @default; }
            set
            {
                if (value == null) throw new ArgumentNullException(nameof(value));
                @default = value;
            }
        }
    }
}

 

DependencyVariable.cs

using System;
using System.Windows;
using System.Windows.Data;

namespace View
{
    sealed class DependencyVariable<T>
        : DependencyObject
    {
        static readonly DependencyProperty valueProperty =
            DependencyProperty.Register(
                "Value",
                typeof(T),
                typeof(DependencyVariable<T>)
            );

        public static DependencyProperty ValueProperty
        {
            get { return valueProperty; }
        }

        public T Value
        {
            get { return (T)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        public void SetBinding(Binding binding)
        {
            BindingOperations.SetBinding(this, ValueProperty, binding);
        }

        public void SetBinding(object dataContext, string propertyPath)
        {
            SetBinding(new Binding(propertyPath) { Source = dataContext });
        }
    }
}
 

SerialDisposable.cs

using System;

namespace View
{
    sealed class SerialDisposable
         : IDisposable
    {
        IDisposable content;

        public IDisposable Content
        {
            get { return content; }
            set
            {
                if (content != null)
                {
                    content.Dispose();
                }

                content = value;
            }
        }

        public void Dispose()
        {
            Content = null;
        }
    }
}
 

VisualTreeModule.cs

using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;

namespace View
{
    static class VisualTreeModule
    {
        public static FrameworkElement FindChild(DependencyObject obj, string childName)
        {
            if (obj == null) return null;

            var queue = new Queue<DependencyObject>();
            queue.Enqueue(obj);

            while (queue.Count > 0)
            {
                obj = queue.Dequeue();

                var childCount = VisualTreeHelper.GetChildrenCount(obj);
                for (var i = 0; i < childCount; i++)
                {
                    var child = VisualTreeHelper.GetChild(obj, i);

                    var fe = child as FrameworkElement;
                    if (fe != null && fe.Name == childName)
                    {
                        return fe;
                    }

                    queue.Enqueue(child);
                }
            }

            return null;
        }
    }
}
 

style

<Style x:Key="ComboBoxToggleButtonDelete" TargetType="{x:Type ToggleButton}">
        <Setter Property="OverridesDefaultStyle" Value="true" />
        <Setter Property="IsTabStop" Value="false" />
        <Setter Property="Focusable" Value="false" />
        <Setter Property="ClickMode" Value="Press" />
        <Setter Property="BorderBrush" Value="#BFBFBF" />
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Border CornerRadius="4" BorderBrush="{TemplateBinding BorderBrush}" x:Name="templateRoot" BorderThickness="{TemplateBinding BorderThickness}" Background="White" SnapsToDevicePixels="true">
                        <Image Source="pack://application:,,,/LabInOne_ESARS;component/Images/PC/delLabel.png" Width="15" Height="15" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,2,5,0" >
                        </Image>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource  Mode=FindAncestor,AncestorType=ComboBox}, Path=Text}" Value="{x:Null}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ToggleButton}">
                            <Border CornerRadius="4" BorderBrush="{TemplateBinding BorderBrush}" x:Name="templateRoot" BorderThickness="{TemplateBinding BorderThickness}" Background="White" SnapsToDevicePixels="true">
                                <Image Source="pack://application:,,,/LabInOne_ESARS;component/Images/PC/DropDown.png" Width="15" Height="15" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,2,5,0" />
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </DataTrigger>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource  Mode=FindAncestor,AncestorType=ComboBox}, Path=Text}" Value="">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ToggleButton}">
                            <Border CornerRadius="4" BorderBrush="{TemplateBinding BorderBrush}" x:Name="templateRoot" BorderThickness="{TemplateBinding BorderThickness}" Background="White" SnapsToDevicePixels="true">
                                <Image Source="pack://application:,,,/LabInOne_ESARS;component/Images/PC/DropDown.png" Width="15" Height="15" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,2,5,0" />
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </DataTrigger>
        </Style.Triggers>
    </Style>
    <ControlTemplate x:Key="ComboBoxDeleteTemplate" TargetType="{x:Type ComboBox}">
        <Grid x:Name="templateRoot" SnapsToDevicePixels="true">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0" />
            </Grid.ColumnDefinitions>
            <Popup x:Name="PART_Popup" AllowsTransparency="true" VerticalOffset="3" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
                <Grid Margin="2" Width="{TemplateBinding ActualWidth}"  MaxHeight="{TemplateBinding MaxDropDownHeight}">
                    <Grid.Effect>
                        <DropShadowEffect BlurRadius="8" ShadowDepth="0" Opacity="0.8" Color="#bfbfbf" />
                    </Grid.Effect>
                    <Border x:Name="dropDownBorder" CornerRadius="4" Width="{TemplateBinding Width}" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" 
                            BorderThickness="0" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
                        <ScrollViewer x:Name="DropDownScrollViewer">
                            <Grid x:Name="grid" RenderOptions.ClearTypeHint="Enabled">
                                <Canvas x:Name="canvas" Height="0" VerticalAlignment="Top" Width="0">
                                    <Rectangle x:Name="opaqueRect"  Height="{Binding ActualHeight, ElementName=dropDownBorder}" Width="{Binding ActualWidth, ElementName=dropDownBorder}">
                                    </Rectangle>
                                </Canvas>
                                <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                            </Grid>
                        </ScrollViewer>
                    </Border>
                </Grid>
            </Popup>
            <ToggleButton Cursor="Hand" x:Name="toggleButton" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" 
                          Background="{TemplateBinding Background}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" 
                          Style="{StaticResource ComboBoxToggleButtonDelete}" />
            <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsHitTestVisible="false" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
            <!--水印提示内容-->
            <Border Grid.Column="0">
                <TextBlock FontSize="12" Name="Message" Visibility="Collapsed" Text="{TemplateBinding Tag}" HorizontalAlignment="Left" VerticalAlignment="Center"  Foreground="#999999" IsHitTestVisible="False"
                                   Margin="10,0,0,0" Opacity="1" />
            </Border>
        </Grid>

        <ControlTemplate.Triggers>

            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsGrouping" Value="true" />
                    <Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false" />
                </MultiTrigger.Conditions>
                <Setter Property="ScrollViewer.CanContentScroll" Value="false" />
            </MultiTrigger>
            <Trigger Property="ScrollViewer.CanContentScroll" SourceName="DropDownScrollViewer" Value="false">
                <Setter Property="Canvas.Top" TargetName="opaqueRect" Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}" />
                <Setter Property="Canvas.Left" TargetName="opaqueRect" Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}" />
            </Trigger>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="">
                <Setter TargetName="Message" Property="Visibility" Value="Visible" />
            </DataTrigger>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="{x:Null}">
                <Setter TargetName="Message" Property="Visibility" Value="Visible" />
            </DataTrigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
    <ControlTemplate x:Key="ComboBoxEditableDeleteTemplate" TargetType="{x:Type ComboBox}">
        <Grid x:Name="templateRoot" SnapsToDevicePixels="true">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="20" />
            </Grid.ColumnDefinitions>
            <Popup x:Name="PART_Popup" AllowsTransparency="true" VerticalOffset="3" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
                   Margin="1" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
                <Grid Margin="2" Width="{TemplateBinding ActualWidth}"  MaxHeight="{TemplateBinding MaxDropDownHeight}">
                    <Grid.Effect>
                        <DropShadowEffect BlurRadius="8" ShadowDepth="0" Opacity="0.8" Color="#bfbfbf" />
                    </Grid.Effect>
                    <Border x:Name="dropDownBorder" CornerRadius="4" Width="{TemplateBinding Width}" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="0" 
                            Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
                        <ScrollViewer x:Name="DropDownScrollViewer">
                            <Grid x:Name="grid" RenderOptions.ClearTypeHint="Enabled">
                                <Canvas x:Name="canvas" Height="0" VerticalAlignment="Top" Width="0">
                                    <Rectangle x:Name="opaqueRect"  Height="{Binding ActualHeight, ElementName=dropDownBorder}" Width="{Binding ActualWidth, ElementName=dropDownBorder}">
                                    </Rectangle>
                                </Canvas>
                                <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                            </Grid>
                        </ScrollViewer>
                    </Border>
                </Grid>
            </Popup>
            <ToggleButton x:Name="toggleButton" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" 
                          Background="{TemplateBinding Background}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"  
                          Style="{StaticResource ComboBoxToggleButtonDelete}" />

            <Border x:Name="border" Background="{TemplateBinding Background}" Margin="2">
                <TextBox x:Name="PART_EditableTextBox" Margin="2" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"  
                         IsReadOnly="{Binding IsReadOnly, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ComboBoxEditableTextBox}" 
                        VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
            </Border>
            <!--水印提示内容-->
            <Border Grid.Column="0">
                <TextBlock FontSize="12" Name="Message" Visibility="Collapsed" Text="{TemplateBinding Tag}" HorizontalAlignment="Left" VerticalAlignment="Center"  Foreground="#999999" IsHitTestVisible="False"
                                   Margin="10,0,0,0" Opacity="1" />
            </Border>
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="IsEnabled" Value="false">
                <Setter Property="Opacity" TargetName="border" Value="0.56" />
            </Trigger>
            <Trigger Property="IsKeyboardFocusWithin" Value="true">
                <Setter Property="Foreground" Value="Black" />
            </Trigger>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="">
                <Setter TargetName="Message" Property="Visibility" Value="Visible" />
            </DataTrigger>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="{x:Null}">
                <Setter TargetName="Message" Property="Visibility" Value="Visible" />
            </DataTrigger>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsGrouping" Value="true" />
                    <Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false" />
                </MultiTrigger.Conditions>
                <Setter Property="ScrollViewer.CanContentScroll" Value="false" />
            </MultiTrigger>
            <Trigger Property="ScrollViewer.CanContentScroll" SourceName="DropDownScrollViewer" Value="false">
                <Setter Property="Canvas.Top" TargetName="opaqueRect" Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}" />
                <Setter Property="Canvas.Left" TargetName="opaqueRect" Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}" />
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>

    <Style x:Key="ComboBoxTextStyle" TargetType="{x:Type ComboBox}">
        <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}" />
        <Setter Property="Background" Value="White" />
        <Setter Property="BorderBrush" Value="White" />
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}" />
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="Padding" Value="10,0,0,0" />
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
        <Setter Property="FontSize" Value="14" />
        <Setter Property="ScrollViewer.CanContentScroll" Value="true" />
        <Setter Property="ScrollViewer.PanningMode" Value="Both" />
        <Setter Property="Stylus.IsFlicksEnabled" Value="False" />
        <Setter Property="MaxDropDownHeight" Value="120" />
        <Setter Property="Template" Value="{StaticResource ComboBoxDeleteTemplate}" />
        <Setter Property="ItemContainerStyle" Value="{DynamicResource ComboBoxItemStyle}" />
        <Setter Property="VerticalAlignment" Value="Center" />
        <Setter Property="VerticalContentAlignment" Value="Center" />
        <Setter Property="HorizontalContentAlignment" Value="Left" />
        <Style.Triggers>
            <Trigger Property="IsEditable" Value="true">
                <Setter Property="IsTabStop" Value="false" />
                <Setter Property="Template" Value="{StaticResource ComboBoxEditableDeleteTemplate}" />
            </Trigger>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="BorderBrush" Value="#00CB7C" />
            </Trigger>
            <Trigger Property="IsMouseOver" Value="False">
                <Setter Property="BorderBrush" Value="#BFBFBF" />
            </Trigger>
        </Style.Triggers>
    </Style>

应用

<TextBlock FontSize="14" Text="项目编号:" Width="66" HorizontalAlignment="Left"  Margin="650,0,0,0" VerticalAlignment="Center"></TextBlock>
                        <local1:AutoCompleteComboBox Margin="719,0,0,0" IsEditable="True" x:Name="cbbprojectNoList" Tag="请选择"  
                                          Width="140" Height="24" VerticalAlignment="Center" HorizontalAlignment="Left" IsTextSearchEnabled="False" 
                                          ItemsSource="{Binding ProjectSearchPa.projectNoList}"  KeyUp="CbbprojectNoList_KeyUp" SelectedValue="{Binding ProjectSearchReq.projectNo}"
                                          Style="{StaticResource ComboBoxTextStyle}"  SelectionChanged="ComboBoxPro_SelectionChanged" ButtonBase.Click="cbbclassifyList_Click">
                        </local1:AutoCompleteComboBox>

 private void CbbprojectNoList_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                ComboBox combox = sender as ComboBox;
                if (combox == null) return;
                combox.Tag = null;
                string txt = combox.Text;
                combox.IsDropDownOpen = false;
                vm.查询(查询条件);

                TextBox textBox = (TextBox)combox.Template.FindName("PART_EditableTextBox", combox);
                combox.Text = txt;
                textBox.SelectionStart = textBox.Text.Length;
            }
        }

 private void ComboBoxPro_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            e.Handled = true;
            if (!(sender is ComboBox combox)) return;
                vm.查询(查询条件);
        }


        private void cbbclassifyList_Click(object sender, RoutedEventArgs e)
        {
            var accb = sender as AutoCompleteComboBox;
            var cbb = sender as ComboBox;
            if (accb == null)
            {
                if (cbb == null) return;
            }
            if (accb != null && !string.IsNullOrEmpty(accb.Text))
            {
                accb.Text = null;
                accb.SelectedValue = null;
                //vm.GetProjectList_New(vm.ProjectSearchReq);
                accb.Tag = "请选择";
                accb.IsDropDownOpen = false;
            }
            else if (cbb != null && !string.IsNullOrEmpty(cbb.Text))
            {
                cbb.Text = null;
                cbb.SelectedValue = null;
                //vm.GetProjectList_New(vm.ProjectSearchReq);
                cbb.Tag = "请选择";
                cbb.IsDropDownOpen = false;
            }
            else
            {
                if (accb != null)
                    accb.IsDropDownOpen = true;
                else if (cbb != null)
                    cbb.IsDropDownOpen = true;
            }
        }

 

效果

输入的时候会自动搜索并打开下拉框

 

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值