using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Linq;
using System.Windows.Media;
using System.Windows.Threading;
using Tango.Core.ExtensionMethods;
namespace Tango.SharedUI.Controls
{
public class SearchComboBox : ComboBox
{
private TextBox _textBox;
private ListBox _listBox;
private ICollectionView _view;
public bool IsOpened
{
get { return (bool)GetValue(IsOpenedProperty); }
set { SetValue(IsOpenedProperty, value); }
}
public static readonly DependencyProperty IsOpenedProperty =
DependencyProperty.Register("IsOpened", typeof(bool), typeof(SearchComboBox), new PropertyMetadata(false, (d, e) => (d as SearchComboBox).OnIsOpenedChanged()));
public String SearchProperty
{
get { return (String)GetValue(SearchPropertyProperty); }
set { SetValue(SearchPropertyProperty, value); }
}
public static readonly DependencyProperty SearchPropertyProperty =
DependencyProperty.Register("SearchProperty", typeof(String), typeof(SearchComboBox), new PropertyMetadata(null));
public String SearchFilter
{
get { return (String)GetValue(SearchFilterProperty); }
set { SetValue(SearchFilterProperty, value); }
}
public static readonly DependencyProperty SearchFilterProperty =
DependencyProperty.Register("SearchFilter", typeof(String), typeof(SearchComboBox), new PropertyMetadata(null, (d, e) => (d as SearchComboBox).OnFilterChanged()));
public IEnumerable ListItemsSource
{
get { return (IEnumerable)GetValue(ListItemsSourceProperty); }
set { SetValue(ListItemsSourceProperty, value); }
}
public static readonly DependencyProperty ListItemsSourceProperty =
DependencyProperty.Register("ListItemsSource", typeof(IEnumerable), typeof(SearchComboBox), new PropertyMetadata(null));
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_textBox = GetTemplateChild("txt") as TextBox;
_listBox = GetTemplateChild("list") as ListBox;
_textBox.PreviewKeyDown += _textBox_KeyDown;
_listBox.PreviewKeyDown += _listBox_PreviewKeyDown;
_listBox.PreviewMouseLeftButtonUp += _listBox_PreviewMouseLeftButtonUp;
KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Once);
}
private void _listBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Return)
{
IsOpened = false;
SelectedItem = _listBox.SelectedItem;
if (SelectedValuePath.IsNotNullOrEmpty() && SelectedItem != null)
{
SelectedValue = SelectedItem.GetPropertyValueByPath(SelectedValuePath);
}
}
else if (e.Key == Key.Up && _listBox.SelectedIndex == 0)
{
_textBox.Focus();
Keyboard.Focus(_textBox);
}
}
private void _textBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Down)
{
e.Handled = true;
FocusList();
}
}
private void FocusList()
{
if (!String.IsNullOrWhiteSpace(SearchFilter))
{
_listBox.SelectedIndex = 0;
}
Keyboard.Focus(_listBox);
if (_listBox.SelectedIndex != -1)
{
var container = _listBox.ItemContainerGenerator.ContainerFromIndex(_listBox.SelectedIndex) as UIElement;
if (container != null)
{
container.Focus();
Keyboard.Focus(container);
}
}
_listBox.ScrollIntoView(_listBox.SelectedItem);
}
private void _listBox_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (_listBox.SelectedItem != null)
{
if (SelectedItem != _listBox.SelectedItem)
{
IsOpened = false;
SelectedItem = _listBox.SelectedItem;
if (SelectedValuePath.IsNotNullOrEmpty() && SelectedItem != null)
{
SelectedValue = SelectedItem.GetPropertyValueByPath(SelectedValuePath);
}
}
}
}
private async void OnIsOpenedChanged()
{
if (IsOpened)
{
SearchFilter = String.Empty;
_listBox.SelectedItem = SelectedItem;
_listBox.ScrollIntoView(_listBox.SelectedItem);
await Task.Delay(100);
_textBox.Focus();
Keyboard.Focus(_textBox);
}
}
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
base.OnItemsSourceChanged(oldValue, newValue);
if (ItemsSource != null)
{
ListItemsSource = ItemsSource.Cast<Object>().ToList();
_view = CollectionViewSource.GetDefaultView(ListItemsSource);
_view.Filter = (x) =>
{
if (String.IsNullOrWhiteSpace(SearchFilter) || SearchFilter == null) return true;
if (x != null)
{
if (!String.IsNullOrWhiteSpace(SearchProperty))
{
var prop = x.GetType().GetProperty(SearchProperty, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
if (prop != null)
{
String propValue = prop.GetValue(x).ToString();
return propValue.ToLower().Contains(SearchFilter.ToLower());
}
}
return x.ToStringSafe().ToLower().Contains(SearchFilter.ToLower());
}
return false;
};
}
}
private void OnFilterChanged()
{
_view?.Refresh();
if (_listBox != null && _listBox.Items.Count > 0)
{
_listBox.ScrollIntoView(_listBox.Items[0]);
}
}
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
//base.OnPreviewKeyDown(e);
e.Handled = false;
}
protected override void OnPreviewKeyUp(KeyEventArgs e)
{
//base.OnPreviewKeyUp(e);
e.Handled = false;
}
protected override void OnKeyDown(KeyEventArgs e)
{
//base.OnKeyDown(e);
e.Handled = false;
}
protected override void OnKeyUp(KeyEventArgs e)
{
//base.OnKeyUp(e);
e.Handled = false;
}
protected override void OnPreviewMouseWheel(MouseWheelEventArgs e)
{
e.Handled = true;
if (!_listBox.IsFocused)
{
FocusList();
}
if (e.Delta > 0)
{
_listBox.RaiseEvent(
new KeyEventArgs(
System.Windows.Input.Keyboard.PrimaryDevice,
PresentationSource.FromVisual(_listBox), 0, Key.Up)
{ RoutedEvent = System.Windows.Input.Keyboard.KeyDownEvent });
_listBox.RaiseEvent(
new KeyEventArgs(
System.Windows.Input.Keyboard.PrimaryDevice,
PresentationSource.FromVisual(_listBox), 0, Key.Up)
{ RoutedEvent = System.Windows.Input.Keyboard.KeyUpEvent });
}
else
{
_listBox.RaiseEvent(
new KeyEventArgs(
System.Windows.Input.Keyboard.PrimaryDevice,
PresentationSource.FromVisual(_listBox), 0, Key.Down)
{ RoutedEvent = System.Windows.Input.Keyboard.KeyDownEvent });
_listBox.RaiseEvent(
new KeyEventArgs(
System.Windows.Input.Keyboard.PrimaryDevice,
PresentationSource.FromVisual(_listBox), 0, Key.Down)
{ RoutedEvent = System.Windows.Input.Keyboard.KeyUpEvent });
}
//base.OnPreviewMouseWheel(e);
}
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
e.Handled = true;
//base.OnMouseWheel(e);
}
static SearchComboBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(SearchComboBox), new FrameworkPropertyMetadata(typeof(SearchComboBox)));
}
}
}