using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
namespace FWindSoft.Wpf.Controls
{
///
/// 带搜索功能的comboBox
///
/// [TemplatePart(Name = "PART_textBoxNewItem", Type=typeof(TextBox))]
[TemplatePart(Name = "PART_SearchText", Type = typeof(TextBox))]
[TemplatePart(Name = "PART_Popup", Type = typeof(Popup))]
[TemplatePart(Name = "PART_Button", Type = typeof(Button))]
public class SearchComboBox : ListBox
{
static SearchComboBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(SearchComboBox), new FrameworkPropertyMetadata(typeof(SearchComboBox)));
}
public SearchComboBox()
{
Keyboard.AddPreviewKeyDownHandler(this, OnKeyDown);
Keyboard.AddPreviewKeyUpHandler(this, OnKeyUp);
this.AddHandler(ListBoxItem.PreviewMouseDownEvent,new MouseButtonEventHandler(MouseButtonEventHandler));
this.IsTextSearchCaseSensitive = false;
this.IsTextSearchEnabled = false;
this.InEdit = false;
this.SetValue(KeyboardNavigation.DirectionalNavigationProperty, KeyboardNavigationMode.Contained);
}
private void MouseButtonEventHandler(object sender, MouseButtonEventArgs e)
{
var element = e.OriginalSource as UIElement;
if (element == null)
return;
var listItem = element.GetParentTypeSelf();
if (listItem == null)
return;
if (listItem.DataContext == this.SelectedItem)
{
SyncSelectedItemText();
}
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter && IsDropDownOpen)
{
this.IsDropDownOpen = false;
if (this.SelectedItem != null)
{
SyncSelectedItemText();
}
return;
}
if (!(Key.Up == e.Key || Key.Down == e.Key))
{
//EditableTextBox.Focus();
}
else
{
UIElement item = ItemContainerGenerator.ContainerFromItem(SelectedItem) as UIElement;
if ((item == null) && (Items.Count > 0))
item = ItemContainerGenerator.ContainerFromItem(Items[0]) as UIElement;
if (item != null)
item.Focus();
}
}
private void OnKeyUp(object sender, KeyEventArgs e)
{
EditableTextBox.Focus();
}
#region 属性相关
///
/// 关联文本
///
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(SearchComboBox));
///
/// 关联文本
///
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
///
/// 是否下拉打开
///
public static readonly DependencyProperty IsDropDownOpenProperty =
DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(SearchComboBox));
///
/// 是否下拉打开
///
public bool IsDropDownOpen
{
get { return (bool)GetValue(IsDropDownOpenProperty); }
set { SetValue(IsDropDownOpenProperty, value); }
}
///
/// Dependency backing for the MaxDropDownHeight property.
///
public static readonly DependencyProperty MaxDropDownHeightProperty =
ComboBox.MaxDropDownHeightProperty.AddOwner(typeof(SearchComboBox));
///
/// Gets or sets a value indicating the maximium height of the drop down.
///
public double MaxDropDownHeight
{
get { return (double)GetValue(MaxDropDownHeightProperty); }
set { SetValue(MaxDropDownHeightProperty, value); }
}
///
/// 是否下拉打开
///
public static readonly DependencyProperty IsReadOnlyProperty =
DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(SearchComboBox));
///
/// 是否下拉打开
///
public bool IsReadOnly
{
get { return (bool)GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
#endregion
/*
* 选中项会在数据源发生变化时变化,所以要保证全局的选中项
*/
///
/// 真实的选中项
///
private object RealSelectedItem { get; set; }
#region 内部编辑
private bool InEdit { get; set; }
public void BeginInEdit()
{
InEdit = true;
}
public void EndInEdit()
{
InEdit = false;
}
#endregion
#region 相关
/*
* 1、过滤过程中,对SelectedItem赋值,不要引起Text的变化
* 2、内部引发的Text事件,不触发过滤事件
* 3、编辑完成是离开控件
*/
#endregion
private static readonly DependencyProperty m_DisplayProperty =
DependencyProperty.Register("m_DisplayProperty", typeof(object), typeof(SearchComboBox));
private string GetDisplay(object item)
{
BindingOperations.SetBinding(this, m_DisplayProperty, new Binding(DisplayMemberPath) { Source = item });
var propertyValue = GetValue(m_DisplayProperty);
BindingOperations.ClearBinding(this, m_DisplayProperty);
return propertyValue?.ToString() ?? string.Empty;
}
private Popup Popup { get; set; }
protected TextBox EditableTextBox { get; set; }
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Popup = (Popup)this.Template.FindName("PART_Popup", this);
EditableTextBox = (TextBox) this.Template.FindName("PART_SearchText", this);
this.EditableTextBox.TextChanged += EditableTextBox_TextChanged;
this.EditableTextBox.LostFocus += EditableTextBox_LostFocus;
var toggle = (Button)this.Template.FindName("PART_Button", this);
toggle.Click += Toggle_Click;
this.PreviewMouseLeftButtonDown += Toggle_PreviewMouseLeftButtonDown;
}
private void Toggle_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
m_IsOpen = this.IsDropDownOpen;
}
private bool m_IsOpen;
private void Toggle_Click(object sender, RoutedEventArgs e)
{
if (this.ItemsSource == null)
return;
GlobalFlag = true;
RefreshFilter();
SetSelectedItem();
this.IsDropDownOpen = !m_IsOpen;
//Popup.StaysOpen = false;
}
private void EditableTextBox_LostFocus(object sender, RoutedEventArgs e)
{
GlobalFlag = true;
RefreshFilter();
SetSelectedItem();
}
private void SetSelectedItem()
{
if(this.RealSelectedItem==null)
{
if (this.ItemsSource != null)
{
foreach (var item in ItemsSource)
{
this.RealSelectedItem = item;//.FirstOrDefault();
break;
}
}
}
this.SelectedItem = this.RealSelectedItem;
try
{
BeginInEdit();
this.Text = GetDisplay(this.SelectedItem);
}
finally
{
EndInEdit();
}
}
private void EditableTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
TextChanged();
}
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
try
{
BeginInEdit();
base.OnSelectionChanged(e);
if (!InSelected)
{
this.Text = GetDisplay(this.SelectedItem);
this.EditableTextBox.Select(this.Text.Length, 0);
this.RealSelectedItem = this.SelectedItem;
}
}
finally
{
EndInEdit();
}
}
///
/// 同步text显示
///
private void SyncSelectedItemText()
{
try
{
BeginInEdit();
if (!InSelected)
{
var text= GetDisplay(this.SelectedItem);
//this.Text = this.SelectedItem?.ToString() ?? string.Empty;
this.EditableTextBox.Text = text;
this.EditableTextBox.Select(text.Length, 0);
this.RealSelectedItem = this.SelectedItem;
}
}
finally
{
EndInEdit();
}
}
#region 选项控制
///
/// 是否是内部选择
///
private bool InSelected { get; set; } = false;
private void SetSelectedItem(object item)
{
try
{
InSelected = true;
this.SelectedItem = item;
}
finally
{
InSelected = false;
}
}
#endregion
#region 过滤相关
private void RefreshFilter()
{
if (this.ItemsSource != null)
{
try
{
BeginInEdit();
InSelected = true;
ICollectionView view = CollectionViewSource.GetDefaultView(this.ItemsSource);
view.Refresh();
}
finally
{
InSelected = false;
EndInEdit();
}
}
}
///
/// 全局过滤标志,为true 则不进行过滤,初始值为ture
///
private bool GlobalFlag { get; set; } = true;
private bool FilterPredicate(object value)
{
if (GlobalFlag)
return true;
if (value == null)
return false;
var text = this.EditableTextBox.Text;
if (text.Length== 0)
return true;
string prefix = text;
return GetDisplay(value).Contains(prefix);
}
#endregion
protected override void OnItemsSourceChanged(IEnumerable oldValue, 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 TextChanged()
{
if (!this.IsTextSearchEnabled && !this.InEdit)
{
var text = this.EditableTextBox.Text??string.Empty;
if (true||text.Length > 0)
{
GlobalFlag = false;
this.RefreshFilter();
//Poupup.IsOpen = true;
IsDropDownOpen = true;
foreach (object item in CollectionViewSource.GetDefaultView(this.ItemsSource))
{
string display = item.ToString();
SetSelectedItem(item);
if (display == text)
{
this.RealSelectedItem = item;
}
break;
}
}
}
}
}
}