C# WPF组合框中的自动建议

C# WPF组合框中的自动建议,c#,wpf,visual-studio-2010,xaml,C#,Wpf,Visual Studio 2010,Xaml,My combobox从存储过程返回一组值,如下所示 private void BindCombo() { DataCombo.FillCombo(ComboDS(2313001), cmbClass, 0); DataCombo.FillCombo(DDCombo(5007), cmbGroup, 0); } 我设法给出了一个基本的自动完成建议,如IsTextSearchenabled,但无法获得我想要的自动建议框 我已经看到了很多自动完成/提示性文本框的例子,但没有一个适合

My combobox从存储过程返回一组值,如下所示

private void BindCombo()
{
    DataCombo.FillCombo(ComboDS(2313001), cmbClass, 0);
    DataCombo.FillCombo(DDCombo(5007), cmbGroup, 0);
}
我设法给出了一个基本的自动完成建议,如
IsTextSearchenabled
,但无法获得我想要的自动建议框

我已经看到了很多自动完成/提示性文本框的例子,但没有一个适合我

这个代码显然适合我

但我该如何使用这里的自动建议

using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace DotNetZen.AutoFilteredComboBox
{
    public class AutoFilteredComboBox : ComboBox
    {
        private int silenceEvents = 0;

    /// <summary>
    /// Creates a new instance of <see cref="AutoFilteredComboBox" />.
    /// </summary>
    public AutoFilteredComboBox()
    {
        DependencyPropertyDescriptor textProperty = DependencyPropertyDescriptor.FromProperty(
            ComboBox.TextProperty, typeof(AutoFilteredComboBox));
        textProperty.AddValueChanged(this, this.OnTextChanged);

        this.RegisterIsCaseSensitiveChangeNotification();
    }

    #region IsCaseSensitive Dependency Property
    /// <summary>
    /// The <see cref="DependencyProperty"/> object of the <see cref="IsCaseSensitive" /> dependency property.
    /// </summary>
    public static readonly DependencyProperty IsCaseSensitiveProperty =
        DependencyProperty.Register("IsCaseSensitive", typeof(bool), typeof(AutoFilteredComboBox), new UIPropertyMetadata(false));

    /// <summary>
    /// Gets or sets the way the combo box treats the case sensitivity of typed text.
    /// </summary>
    /// <value>The way the combo box treats the case sensitivity of typed text.</value>
    [System.ComponentModel.Description("The way the combo box treats the case sensitivity of typed text.")]
    [System.ComponentModel.Category("AutoFiltered ComboBox")]
    [System.ComponentModel.DefaultValue(true)]
    public bool IsCaseSensitive
    {
        [System.Diagnostics.DebuggerStepThrough]
        get
        {
            return (bool)this.GetValue(IsCaseSensitiveProperty);
        }
        [System.Diagnostics.DebuggerStepThrough]
        set
        {
            this.SetValue(IsCaseSensitiveProperty, value);
        }
    }

    protected virtual void OnIsCaseSensitiveChanged(object sender, EventArgs e)
    {
        if (this.IsCaseSensitive)
            this.IsTextSearchEnabled = false;

        this.RefreshFilter();
    }

    private void RegisterIsCaseSensitiveChangeNotification()
    {
        System.ComponentModel.DependencyPropertyDescriptor.FromProperty(IsCaseSensitiveProperty, typeof(AutoFilteredComboBox)).AddValueChanged(
            this, this.OnIsCaseSensitiveChanged);
    }
    #endregion

    #region DropDownOnFocus Dependency Property
    /// <summary>
    /// The <see cref="DependencyProperty"/> object of the <see cref="DropDownOnFocus" /> dependency property.
    /// </summary>
    public static readonly DependencyProperty DropDownOnFocusProperty =
        DependencyProperty.Register("DropDownOnFocus", typeof(bool), typeof(AutoFilteredComboBox), new UIPropertyMetadata(true));

    /// <summary>
    /// Gets or sets the way the combo box behaves when it receives focus.
    /// </summary>
    /// <value>The way the combo box behaves when it receives focus.</value>
    [System.ComponentModel.Description("The way the combo box behaves when it receives focus.")]
    [System.ComponentModel.Category("AutoFiltered ComboBox")]
    [System.ComponentModel.DefaultValue(true)]
    public bool DropDownOnFocus
    {
        [System.Diagnostics.DebuggerStepThrough]
        get
        {
            return (bool)this.GetValue(DropDownOnFocusProperty);
        }
        [System.Diagnostics.DebuggerStepThrough]
        set
        {
            this.SetValue(DropDownOnFocusProperty, value);
        }
    }
    #endregion

    #region | Handle selection |
    /// <summary>
    /// Called when <see cref="ComboBox.ApplyTemplate()"/> is called.
    /// </summary>
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        this.EditableTextBox.SelectionChanged += this.EditableTextBox_SelectionChanged;
    }

    /// <summary>
    /// Gets the text box in charge of the editable portion of the combo box.
    /// </summary>
    protected TextBox EditableTextBox
    {
        get
        {
            return ((TextBox)base.GetTemplateChild("PART_EditableTextBox"));
        }
    }

    private int start = 0, length = 0;

    private void EditableTextBox_SelectionChanged(object sender, RoutedEventArgs e)
    {
        if (this.silenceEvents == 0)
        {
            this.start = ((TextBox)(e.OriginalSource)).SelectionStart;
            this.length = ((TextBox)(e.OriginalSource)).SelectionLength;

            this.RefreshFilter();
        }
    }
    #endregion

    #region | Handle focus |
    /// <summary>
    /// Invoked whenever an unhandled <see cref="UIElement.GotFocus" /> event
    /// reaches this element in its route.
    /// </summary>
    /// <param name="e">The <see cref="RoutedEventArgs" /> that contains the event data.</param>
    protected override void OnGotFocus(RoutedEventArgs e)
    {
        base.OnGotFocus(e);

        if (this.ItemsSource != null && this.DropDownOnFocus)
        {
            this.IsDropDownOpen = true;
        }
    }
    #endregion

    #region | Handle filtering |
    private void RefreshFilter()
    {
        if (this.ItemsSource != null)
        {
            ICollectionView view = CollectionViewSource.GetDefaultView(this.ItemsSource);
            view.Refresh();
            this.IsDropDownOpen = true;
        }
    }

    private bool FilterPredicate(object value)
    {
        // We don't like nulls.
        if (value == null)
            return false;

        // If there is no text, there's no reason to filter.
        if (this.Text.Length == 0)
            return true;

        string prefix = this.Text;

        // If the end of the text is selected, do not mind it.
        if (this.length > 0 && this.start + this.length == this.Text.Length)
        {
            prefix = prefix.Substring(0, this.start);
        }

        return value.ToString()
            .StartsWith(prefix, !this.IsCaseSensitive, CultureInfo.CurrentCulture);
    }
    #endregion

    /// <summary>
    /// Called when the source of an item in a selector changes.
    /// </summary>
    /// <param name="oldValue">Old value of the source.</param>
    /// <param name="newValue">New value of the source.</param>
    protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue)
    {
        if (newValue != null)
        {
            ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
            view.Filter += this.FilterPredicate;
        }

        if (oldValue != null)
        {
            ICollectionView view = CollectionViewSource.GetDefaultView(oldValue);
            view.Filter -= this.FilterPredicate;
        }

        base.OnItemsSourceChanged(oldValue, newValue);
    }

    private void OnTextChanged(object sender, EventArgs e)
    {
        if (!this.IsTextSearchEnabled && this.silenceEvents == 0)
        {
            this.RefreshFilter();

            // Manually simulate the automatic selection that would have been
            // available if the IsTextSearchEnabled dependency property was set.
            if (this.Text.Length > 0)
            {
                foreach (object item in CollectionViewSource.GetDefaultView(this.ItemsSource))
                {
                    int text = item.ToString().Length, prefix = this.Text.Length;
                    this.SelectedItem = item;

                    this.silenceEvents++;
                    this.EditableTextBox.Text = item.ToString();
                    this.EditableTextBox.Select(prefix, text - prefix);
                    this.silenceEvents--;
                    break;
                }
            }
        }
    }
}
}
使用系统;
使用系统组件模型;
利用制度全球化;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Data;
命名空间DotNetZen.autofilteredcompobox
{
公共类AutoFilteredComboBox:ComboBox
{
私有int沉默事件=0;
/// 
///创建的新实例。
/// 
公共自动筛选邮箱()
{
DependencyPropertyDescriptor textProperty=DependencyPropertyDescriptor.FromProperty(
ComboBox.TextProperty,typeof(AutoFilteredComboBox));
textProperty.AddValueChanged(this,this.OnTextChanged);
this.RegisterIsCaseSensitiveChangeNotification();
}
#区域敏感依赖属性
/// 
///依赖项属性的对象。
/// 
public static readonly dependencProperty是CaseSensitiveProperty=
DependencyProperty.Register(“IsCaseSensitive”、typeof(bool)、typeof(AutoFilteredComboBox)、new UIPropertyMetadata(false));
/// 
///获取或设置组合框处理键入文本区分大小写的方式。
/// 
///组合框处理键入文本区分大小写的方式。
[System.ComponentModel.Description(“组合框处理键入文本的大小写敏感度的方式”)]
[System.ComponentModel.Category(“自动筛选组合框”)]
[System.ComponentModel.DefaultValue(true)]
公共场所是敏感的
{
[系统.诊断.调试步骤]
收到
{
返回(bool)this.GetValue(IsCaseSensitiveProperty);
}
[系统.诊断.调试步骤]
设置
{
此.SetValue(IsCaseSensitiveProperty,value);
}
}
受保护的虚拟空间OnIsCaseSensitiveChanged(对象发送方,事件参数e)
{
if(this.IsCaseSensitive)
this.IsTextSearchEnabled=false;
这个.RefreshFilter();
}
私有无效注册表ScaseSensitiveChangeNotification()
{
System.ComponentModel.DependencyPropertyDescriptor.FromProperty(IsCaseSensitiveProperty,typeof(AutoFilteredComboBox)).AddValueChanged(
这,这,只是"敏感的改变",;
}
#端区
#区域DropDownOnFocus依赖项属性
/// 
///依赖项属性的对象。
/// 
公共静态只读从属属性DropDownOnFocusProperty=
DependencyProperty.Register(“DropDownOnFocus”、typeof(bool)、typeof(AutoFilteredComboBox)、new UIPropertyMetadata(true));
/// 
///获取或设置组合框接收焦点时的行为方式。
/// 
///组合框接收焦点时的行为方式。
[System.ComponentModel.Description(“组合框接收焦点时的行为方式”)]
[System.ComponentModel.Category(“自动筛选组合框”)]
[System.ComponentModel.DefaultValue(true)]
公共广播下拉对焦
{
[系统.诊断.调试步骤]
收到
{
返回(bool)this.GetValue(DropDownOnFocusProperty);
}
[系统.诊断.调试步骤]
设置
{
此.SetValue(DropDownOnFocusProperty,值);
}
}
#端区
#区域|句柄选择|
/// 
///被召唤时被召唤。
/// 
应用程序模板()上的公共重写无效
{
base.OnApplyTemplate();
this.EditableTextBox.SelectionChanged+=this.EditableTextBox\u SelectionChanged;
}
/// 
///获取负责组合框可编辑部分的文本框。
/// 
受保护的文本框可编辑文本框
{
收到
{
return((TextBox)base.GetTemplateChild(“PART_EditableTextBox”);
}
}
private int start=0,length=0;
私有无效可编辑文本框\u选择已更改(对象发送方,路由目标)
{
如果(this.sileneevents==0)
{
this.start=((文本框)(e.OriginalSource)).SelectionStart;
this.length=((文本框)(e.OriginalSource)).SelectionLength;
这个.RefreshFilter();
}
}
#端区
#区域|处理焦点|
/// 
///每当发生未处理的事件时调用
///在其路径中到达此元素。
/// 
///包含事件数据的。
受保护的覆盖无效OnGotFocus(路由目标e)
{
基地,昂戈特福克斯(e);;
if(this.ItemsSource!=null&&this.DropDownOnFocus)
{
this.IsDropDownOpen=true;
}
}
#端区
#区域|句柄过滤|
私有空刷新筛选器()
{
如果(this.ItemsSource!=null)
{
ICollectionView视图=CollectionViewSource.GetDefaultView(this.ItemsSource);
view.Refresh();
this.IsDropDownOpen=true;
}
}
私有布尔筛选器预测(对象值)
{
//我们不喜欢空值。
如果(值==null)
返回false;
//如果没有文本,就没有理由进行筛选。
if(this.Text.Length==0)
返回true;
字符串前缀=this.Text;
//如果选择了文本的结尾,请不要介意。
if(this.length>0&&this.start+this.length==this.Text.length)
{
prefix=prefix.Substring(0,this.start);
}
返回值.ToString()
.StartsWith(前缀,!this.IsCaseSensitive,CultureInfo.CurrentCulture);
}
#端区
/// 
///当选择器中的项的源
Combobox.IsDropDownOpen = true
<Controls:AutoFilteredComboBox ItemsSource="{Binding ViewModel.AvailableItems}"
        SelectedValue="{Binding ViewModel.SelectedItem, Mode=TwoWay}"
        IsEditable="True" IsTextSearchEnabled="False"/>
public class AutoFilteredComboBox : ComboBox
{
    bool _ignoreTextChanged;
    string _currentText;

    /// <summary>
    /// Creates a new instance of <see cref="AutoFilteredComboBox" />.
    /// </summary>
    public AutoFilteredComboBox()
    {
        if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) return;
    }

    public event Func<object, string, bool> FilterItem;
    public event Action<string> FilterList;

    #region IsCaseSensitive Dependency Property
    /// <summary>
    /// The <see cref="DependencyProperty"/> object of the <see cref="IsCaseSensitive" /> dependency property.
    /// </summary>
    public static readonly DependencyProperty IsCaseSensitiveProperty =
        DependencyProperty.Register("IsCaseSensitive", typeof(bool), typeof(AutoFilteredComboBox), new UIPropertyMetadata(false));

    /// <summary>
    /// Gets or sets the way the combo box treats the case sensitivity of typed text.
    /// </summary>
    /// <value>The way the combo box treats the case sensitivity of typed text.</value>
    [Description("The way the combo box treats the case sensitivity of typed text.")]
    [Category("AutoFiltered ComboBox")]
    [DefaultValue(true)]
    public bool IsCaseSensitive
    {
        [System.Diagnostics.DebuggerStepThrough]
        get
        {
            return (bool)this.GetValue(IsCaseSensitiveProperty);
        }
        [System.Diagnostics.DebuggerStepThrough]
        set
        {
            this.SetValue(IsCaseSensitiveProperty, value);
        }
    }
    #endregion

    #region DropDownOnFocus Dependency Property
    /// <summary>
    /// The <see cref="DependencyProperty"/> object of the <see cref="DropDownOnFocus" /> dependency property.
    /// </summary>
    public static readonly DependencyProperty DropDownOnFocusProperty =
        DependencyProperty.Register("DropDownOnFocus", typeof(bool), typeof(AutoFilteredComboBox), new UIPropertyMetadata(false));

    /// <summary>
    /// Gets or sets the way the combo box behaves when it receives focus.
    /// </summary>
    /// <value>The way the combo box behaves when it receives focus.</value>
    [Description("The way the combo box behaves when it receives focus.")]
    [Category("AutoFiltered ComboBox")]
    [DefaultValue(false)]
    public bool DropDownOnFocus
    {
        [System.Diagnostics.DebuggerStepThrough]
        get
        {
            return (bool)this.GetValue(DropDownOnFocusProperty);
        }
        [System.Diagnostics.DebuggerStepThrough]
        set
        {
            this.SetValue(DropDownOnFocusProperty, value);
        }
    }
    #endregion

    #region | Handle focus |
    /// <summary>
    /// Invoked whenever an unhandled <see cref="UIElement.GotFocus" /> event
    /// reaches this element in its route.
    /// </summary>
    /// <param name="e">The <see cref="RoutedEventArgs" /> that contains the event data.</param>
    protected override void OnGotFocus(RoutedEventArgs e)
    {
        base.OnGotFocus(e);

        if (this.ItemsSource != null && this.DropDownOnFocus)
        {
            this.IsDropDownOpen = true;
        }
    }
    #endregion

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        AddHandler(TextBox.TextChangedEvent, new TextChangedEventHandler(OnTextChanged));
        KeyUp += AutoFilteredComboBox_KeyUp;
        this.IsTextSearchEnabled = false;
    }

    void AutoFilteredComboBox_KeyUp(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Down)
        {
            if (this.IsDropDownOpen == true)
            {
                // Ensure that focus is given to the dropdown list
                if (Keyboard.FocusedElement is TextBox)
                {
                    Keyboard.Focus(this);
                    if (this.Items.Count > 0)
                    {
                        if (this.SelectedIndex == -1 || this.SelectedIndex==0)
                            this.SelectedIndex = 0;
                    }
                }
            }
        }
        if (Keyboard.FocusedElement is TextBox)
        {
            if (e.OriginalSource is TextBox)
            {
                // Avoid the automatic selection of the first letter (As next letter will cause overwrite)
                TextBox textBox = e.OriginalSource as TextBox;
                if (textBox.Text.Length == 1 && textBox.SelectionLength == 1)
                {
                    textBox.SelectionLength = 0;
                    textBox.SelectionStart = 1;
                }
            }
        }
    }

    #region | Handle filtering |
    private void RefreshFilter()
    {
        if (this.ItemsSource != null)
        {
            Action<string> filterList = FilterList;
            if (filterList != null)
            {
                filterList(_currentText);
            }
            else
            {
                ICollectionView view = CollectionViewSource.GetDefaultView(this.ItemsSource);
                view.Refresh();
            }
            this.SelectedIndex = -1;    // Prepare so arrow down selects first
            this.IsDropDownOpen = true;
        }
    }

    private bool FilterPredicate(object value)
    {
        // We don't like nulls.
        if (value == null)
            return false;

        // If there is no text, there's no reason to filter.
        if (string.IsNullOrEmpty(_currentText))
            return true;

        Func<object, string, bool> filterItem = FilterItem;
        if (filterItem != null)
            return filterItem(value, _currentText);

        if (IsCaseSensitive)
            return value.ToString().Contains(_currentText);
        else
            return value.ToString().ToUpper().Contains(_currentText.ToUpper());                
    }
    #endregion

    protected override void OnSelectionChanged(SelectionChangedEventArgs e)
    {
        try
        {
            _ignoreTextChanged = true;  // Ignore the following TextChanged
            base.OnSelectionChanged(e);
        }
        finally
        {
            _ignoreTextChanged = false;
        }
    }

    /// <summary>
    /// Called when the source of an item in a selector changes.
    /// </summary>
    /// <param name="oldValue">Old value of the source.</param>
    /// <param name="newValue">New value of the source.</param>
    protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
    {
        if (newValue != null)
        {
            ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
            if (FilterList == null)
                view.Filter += this.FilterPredicate;
        }

        if (oldValue != null)
        {
            ICollectionView view = CollectionViewSource.GetDefaultView(oldValue);
            view.Filter -= this.FilterPredicate;
        }
        base.OnItemsSourceChanged(oldValue, newValue);
    }

    private void OnTextChanged(object sender, TextChangedEventArgs e)
    {
        if (_ignoreTextChanged)
            return;

        _currentText = Text;

        if (!this.IsTextSearchEnabled)
        {
            this.RefreshFilter();
        }
    }