Sicherung

This commit is contained in:
Maier Stephan SI
2023-01-20 16:09:00 +01:00
parent e5257d8413
commit b684704bf8
139 changed files with 95678 additions and 499 deletions

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<TargetFrameworks>net48;netcoreapp3.1;net6.0-windows</TargetFrameworks>
<UseWPF>true</UseWPF>
<Version>1.6.0.0</Version>
<PackageProjectUrl>https://github.com/quicoli/WPF-AutoComplete-TextBox</PackageProjectUrl>
<RepositoryType />
<RepositoryUrl>https://github.com/quicoli/WPF-AutoComplete-TextBox</RepositoryUrl>
<PackageTags>wpf, autocomplete, usercontrol</PackageTags>
<PackageIconUrl>https://github.com/quicoli/WPF-AutoComplete-TextBox/blob/develop/AutoCompleteTextBox/Logo/AutoCompleteTextBox.ico?raw=true</PackageIconUrl>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<ApplicationIcon>AutoCompleteTextBox.ico</ApplicationIcon>
<PackageReleaseNotes>
Better support for keyboard focus
</PackageReleaseNotes>
<Description>An auto complete textbox and combo box for WPF</Description>
<PackageIcon>AutoCompleteTextBox.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<None Include="..\..\README.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
<None Include="..\Logo\AutoCompleteTextBox.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

View File

@@ -0,0 +1,49 @@
using System.Windows;
using System.Windows.Data;
namespace AutoCompleteTextBox
{
public class BindingEvaluator : FrameworkElement
{
#region "Fields"
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(BindingEvaluator), new FrameworkPropertyMetadata(string.Empty));
#endregion
#region "Constructors"
public BindingEvaluator(Binding binding)
{
ValueBinding = binding;
}
#endregion
#region "Properties"
public string Value
{
get => (string)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public Binding ValueBinding { get; set; }
#endregion
#region "Methods"
public string Evaluate(object dataItem)
{
DataContext = dataItem;
SetBinding(ValueProperty, ValueBinding);
return Value;
}
#endregion
}
}

View File

@@ -0,0 +1,612 @@
using System;
using System.Collections;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
namespace AutoCompleteTextBox.Editors
{
[TemplatePart(Name = PartEditor, Type = typeof(TextBox))]
[TemplatePart(Name = PartPopup, Type = typeof(Popup))]
[TemplatePart(Name = PartSelector, Type = typeof(Selector))]
[TemplatePart(Name = PartExpander, Type = typeof(Expander))]
public class AutoCompleteComboBox : Control
{
#region "Fields"
public const string PartEditor = "PART_Editor";
public const string PartPopup = "PART_Popup";
public const string PartSelector = "PART_Selector";
public const string PartExpander = "PART_Expander";
public static readonly DependencyProperty DelayProperty = DependencyProperty.Register("Delay", typeof(int), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(200));
public static readonly DependencyProperty DisplayMemberProperty = DependencyProperty.Register("DisplayMember", typeof(string), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(string.Empty));
public static readonly DependencyProperty IconPlacementProperty = DependencyProperty.Register("IconPlacement", typeof(IconPlacement), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(IconPlacement.Left));
public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(object), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty IconVisibilityProperty = DependencyProperty.Register("IconVisibility", typeof(Visibility), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(Visibility.Visible));
public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty IsLoadingProperty = DependencyProperty.Register("IsLoading", typeof(bool), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty ItemTemplateSelectorProperty = DependencyProperty.Register("ItemTemplateSelector", typeof(DataTemplateSelector), typeof(AutoCompleteComboBox));
public static readonly DependencyProperty LoadingContentProperty = DependencyProperty.Register("LoadingContent", typeof(object), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty ProviderProperty = DependencyProperty.Register("Provider", typeof(IComboSuggestionProvider), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(null, OnSelectedItemChanged));
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(string.Empty, propertyChangedCallback: null, coerceValueCallback: null, isAnimationProhibited: false, defaultUpdateSourceTrigger: UpdateSourceTrigger.LostFocus, flags: FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public static readonly DependencyProperty FilterProperty = DependencyProperty.Register("Filter", typeof(string), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(string.Empty));
public static readonly DependencyProperty MaxLengthProperty = DependencyProperty.Register("MaxLength", typeof(int), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(0));
public static readonly DependencyProperty CharacterCasingProperty = DependencyProperty.Register("CharacterCasing", typeof(CharacterCasing), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(CharacterCasing.Normal));
public static readonly DependencyProperty MaxPopUpHeightProperty = DependencyProperty.Register("MaxPopUpHeight", typeof(int), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(600));
public static readonly DependencyProperty MaxPopUpWidthProperty = DependencyProperty.Register("MaxPopUpWidth", typeof(int), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(2000));
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register("Watermark", typeof(string), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(string.Empty));
public static readonly DependencyProperty SuggestionBackgroundProperty = DependencyProperty.Register("SuggestionBackground", typeof(Brush), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(Brushes.White));
private bool _isUpdatingText;
private bool _selectionCancelled;
private SuggestionsAdapter _suggestionsAdapter;
#endregion
#region "Constructors"
static AutoCompleteComboBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(typeof(AutoCompleteComboBox)));
}
#endregion
#region "Properties"
public int MaxPopupHeight
{
get => (int)GetValue(MaxPopUpHeightProperty);
set => SetValue(MaxPopUpHeightProperty, value);
}
public int MaxPopupWidth
{
get => (int)GetValue(MaxPopUpWidthProperty);
set => SetValue(MaxPopUpWidthProperty, value);
}
public BindingEvaluator BindingEvaluator { get; set; }
public CharacterCasing CharacterCasing
{
get => (CharacterCasing)GetValue(CharacterCasingProperty);
set => SetValue(CharacterCasingProperty, value);
}
public int MaxLength
{
get => (int)GetValue(MaxLengthProperty);
set => SetValue(MaxLengthProperty, value);
}
public int Delay
{
get => (int)GetValue(DelayProperty);
set => SetValue(DelayProperty, value);
}
public string DisplayMember
{
get => (string)GetValue(DisplayMemberProperty);
set => SetValue(DisplayMemberProperty, value);
}
public TextBox Editor { get; set; }
public Expander Expander { get; set; }
public DispatcherTimer FetchTimer { get; set; }
public string Filter
{
get => (string)GetValue(FilterProperty);
set => SetValue(FilterProperty, value);
}
public object Icon
{
get => GetValue(IconProperty);
set => SetValue(IconProperty, value);
}
public IconPlacement IconPlacement
{
get => (IconPlacement)GetValue(IconPlacementProperty);
set => SetValue(IconPlacementProperty, value);
}
public Visibility IconVisibility
{
get => (Visibility)GetValue(IconVisibilityProperty);
set => SetValue(IconVisibilityProperty, value);
}
public bool IsDropDownOpen
{
get => (bool)GetValue(IsDropDownOpenProperty);
set
{
this.Expander.IsExpanded = value;
SetValue(IsDropDownOpenProperty, value);
}
}
public bool IsLoading
{
get => (bool)GetValue(IsLoadingProperty);
set => SetValue(IsLoadingProperty, value);
}
public bool IsReadOnly
{
get => (bool)GetValue(IsReadOnlyProperty);
set => SetValue(IsReadOnlyProperty, value);
}
public Selector ItemsSelector { get; set; }
public DataTemplate ItemTemplate
{
get => (DataTemplate)GetValue(ItemTemplateProperty);
set => SetValue(ItemTemplateProperty, value);
}
public DataTemplateSelector ItemTemplateSelector
{
get => ((DataTemplateSelector)(GetValue(ItemTemplateSelectorProperty)));
set => SetValue(ItemTemplateSelectorProperty, value);
}
public object LoadingContent
{
get => GetValue(LoadingContentProperty);
set => SetValue(LoadingContentProperty, value);
}
public Popup Popup { get; set; }
public IComboSuggestionProvider Provider
{
get => (IComboSuggestionProvider)GetValue(ProviderProperty);
set => SetValue(ProviderProperty, value);
}
public object SelectedItem
{
get => GetValue(SelectedItemProperty);
set => SetValue(SelectedItemProperty, value);
}
public SelectionAdapter SelectionAdapter { get; set; }
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public string Watermark
{
get => (string)GetValue(WatermarkProperty);
set => SetValue(WatermarkProperty, value);
}
public Brush SuggestionBackground
{
get => (Brush)GetValue(SuggestionBackgroundProperty);
set => SetValue(SuggestionBackgroundProperty, value);
}
#endregion
#region "Methods"
public static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
AutoCompleteComboBox act = null;
act = d as AutoCompleteComboBox;
if (act != null)
{
if (act.Editor != null & !act._isUpdatingText)
{
act._isUpdatingText = true;
act.Editor.Text = act.BindingEvaluator.Evaluate(e.NewValue);
act._isUpdatingText = false;
}
}
}
private void ScrollToSelectedItem()
{
if (ItemsSelector is ListBox listBox && listBox.SelectedItem != null)
listBox.ScrollIntoView(listBox.SelectedItem);
}
public new BindingExpressionBase SetBinding(DependencyProperty dp, BindingBase binding){
var res = base.SetBinding(dp, binding);
CheckForParentTextBindingChange();
return res;
}
public new BindingExpressionBase SetBinding(DependencyProperty dp, String path) {
var res = base.SetBinding(dp, path);
CheckForParentTextBindingChange();
return res;
}
public new void ClearValue(DependencyPropertyKey key) {
base.ClearValue(key);
CheckForParentTextBindingChange();
}
public new void ClearValue(DependencyProperty dp) {
base.ClearValue(dp);
CheckForParentTextBindingChange();
}
private void CheckForParentTextBindingChange(bool force=false) {
var CurrentBindingMode = BindingOperations.GetBinding(this, TextProperty)?.UpdateSourceTrigger ?? UpdateSourceTrigger.Default;
if (CurrentBindingMode != UpdateSourceTrigger.PropertyChanged)//preventing going any less frequent than property changed
CurrentBindingMode = UpdateSourceTrigger.Default;
if (CurrentBindingMode == CurrentTextboxTextBindingUpdateMode && force == false)
return;
var binding = new Binding {
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = CurrentBindingMode,
Path = new PropertyPath(nameof(Text)),
RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
};
CurrentTextboxTextBindingUpdateMode = CurrentBindingMode;
Editor?.SetBinding(TextBox.TextProperty, binding);
}
private UpdateSourceTrigger CurrentTextboxTextBindingUpdateMode;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Editor = Template.FindName(PartEditor, this) as TextBox;
Popup = Template.FindName(PartPopup, this) as Popup;
ItemsSelector = Template.FindName(PartSelector, this) as Selector;
Expander = Template.FindName(PartExpander, this) as Expander;
BindingEvaluator = new BindingEvaluator(new Binding(DisplayMember));
if (Editor != null)
{
Editor.TextChanged += OnEditorTextChanged;
Editor.PreviewKeyDown += OnEditorKeyDown;
Editor.LostFocus += OnEditorLostFocus;
CheckForParentTextBindingChange(true);
if (SelectedItem != null)
{
_isUpdatingText = true;
Editor.Text = BindingEvaluator.Evaluate(SelectedItem);
_isUpdatingText = false;
}
}
if (Expander != null)
{
Expander.IsExpanded = false;
Expander.Collapsed += Expander_Expanded;
Expander.Expanded += Expander_Expanded;
}
GotFocus += AutoCompleteComboBox_GotFocus;
if (Popup != null)
{
Popup.StaysOpen = false;
Popup.Opened += OnPopupOpened;
Popup.Closed += OnPopupClosed;
}
if (ItemsSelector != null)
{
SelectionAdapter = new SelectionAdapter(ItemsSelector);
SelectionAdapter.Commit += OnSelectionAdapterCommit;
SelectionAdapter.Cancel += OnSelectionAdapterCancel;
SelectionAdapter.SelectionChanged += OnSelectionAdapterSelectionChanged;
ItemsSelector.PreviewMouseDown += ItemsSelector_PreviewMouseDown;
}
}
private void Expander_Expanded(object sender, RoutedEventArgs e)
{
this.IsDropDownOpen = Expander.IsExpanded;
if (!this.IsDropDownOpen)
{
return;
}
if (_suggestionsAdapter == null)
{
_suggestionsAdapter = new SuggestionsAdapter(this);
}
if (SelectedItem != null || String.IsNullOrWhiteSpace(Editor.Text))
_suggestionsAdapter.ShowFullCollection();
}
private void ItemsSelector_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if ((e.OriginalSource as FrameworkElement)?.DataContext == null)
return;
if (!ItemsSelector.Items.Contains(((FrameworkElement)e.OriginalSource)?.DataContext))
return;
ItemsSelector.SelectedItem = ((FrameworkElement)e.OriginalSource)?.DataContext;
OnSelectionAdapterCommit(SelectionAdapter.EventCause.ItemClicked);
e.Handled = true;
}
private void AutoCompleteComboBox_GotFocus(object sender, RoutedEventArgs e)
{
Editor?.Focus();
}
private string GetDisplayText(object dataItem)
{
if (BindingEvaluator == null)
{
BindingEvaluator = new BindingEvaluator(new Binding(DisplayMember));
}
if (dataItem == null)
{
return string.Empty;
}
if (string.IsNullOrEmpty(DisplayMember))
{
return dataItem.ToString();
}
return BindingEvaluator.Evaluate(dataItem);
}
private void OnEditorKeyDown(object sender, KeyEventArgs e)
{
if (SelectionAdapter != null)
{
if (IsDropDownOpen)
SelectionAdapter.HandleKeyDown(e);
else
IsDropDownOpen = e.Key == Key.Down || e.Key == Key.Up;
}
}
private void OnEditorLostFocus(object sender, RoutedEventArgs e)
{
if (!IsKeyboardFocusWithin)
{
IsDropDownOpen = false;
}
}
private void OnEditorTextChanged(object sender, TextChangedEventArgs e)
{
Text = Editor.Text;
if (_isUpdatingText)
return;
if (FetchTimer == null)
{
FetchTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(Delay) };
FetchTimer.Tick += OnFetchTimerTick;
}
FetchTimer.IsEnabled = false;
FetchTimer.Stop();
SetSelectedItem(null);
if (Editor.Text.Length > 0)
{
FetchTimer.IsEnabled = true;
FetchTimer.Start();
}
else
{
IsDropDownOpen = false;
}
}
private void OnFetchTimerTick(object sender, EventArgs e)
{
FetchTimer.IsEnabled = false;
FetchTimer.Stop();
if (Provider != null && ItemsSelector != null)
{
Filter = Editor.Text;
if (_suggestionsAdapter == null)
{
_suggestionsAdapter = new SuggestionsAdapter(this);
}
_suggestionsAdapter.GetSuggestions(Filter);
}
}
private void OnPopupClosed(object sender, EventArgs e)
{
if (!_selectionCancelled)
{
OnSelectionAdapterCommit(SelectionAdapter.EventCause.PopupClosed);
}
}
private void OnPopupOpened(object sender, EventArgs e)
{
_selectionCancelled = false;
ItemsSelector.SelectedItem = SelectedItem;
}
public event EventHandler<SelectionAdapter.PreSelectionAdapterFinishArgs> PreSelectionAdapterFinish;
private bool PreSelectionEventSomeoneHandled(SelectionAdapter.EventCause cause, bool is_cancel) {
if (PreSelectionAdapterFinish == null)
return false;
var args = new SelectionAdapter.PreSelectionAdapterFinishArgs { cause = cause, is_cancel = is_cancel };
PreSelectionAdapterFinish?.Invoke(this, args);
return args.handled;
}
private void OnSelectionAdapterCancel(SelectionAdapter.EventCause cause)
{
if (PreSelectionEventSomeoneHandled(cause, true))
return;
_isUpdatingText = true;
Editor.Text = SelectedItem == null ? Filter : GetDisplayText(SelectedItem);
Editor.SelectionStart = Editor.Text.Length;
Editor.SelectionLength = 0;
_isUpdatingText = false;
IsDropDownOpen = false;
_selectionCancelled = true;
}
private void OnSelectionAdapterCommit(SelectionAdapter.EventCause cause)
{
if (PreSelectionEventSomeoneHandled(cause, false))
return;
if (ItemsSelector.SelectedItem != null)
{
SelectedItem = ItemsSelector.SelectedItem;
_isUpdatingText = true;
Editor.Text = GetDisplayText(ItemsSelector.SelectedItem);
SetSelectedItem(ItemsSelector.SelectedItem);
_isUpdatingText = false;
IsDropDownOpen = false;
}
}
private void OnSelectionAdapterSelectionChanged()
{
_isUpdatingText = true;
Editor.Text = ItemsSelector.SelectedItem == null ? Filter : GetDisplayText(ItemsSelector.SelectedItem);
Editor.SelectionStart = Editor.Text.Length;
Editor.SelectionLength = 0;
ScrollToSelectedItem();
_isUpdatingText = false;
}
private void SetSelectedItem(object item)
{
_isUpdatingText = true;
SelectedItem = item;
_isUpdatingText = false;
}
#endregion
#region "Nested Types"
private class SuggestionsAdapter
{
#region "Fields"
private readonly AutoCompleteComboBox _actb;
private string _filter;
#endregion
#region "Constructors"
public SuggestionsAdapter(AutoCompleteComboBox actb)
{
_actb = actb;
}
#endregion
#region "Methods"
public void GetSuggestions(string searchText)
{
_actb.IsLoading = true;
// Do not open drop down if control is not focused
if (_actb.IsKeyboardFocusWithin)
_actb.IsDropDownOpen = true;
_actb.ItemsSelector.ItemsSource = null;
ParameterizedThreadStart thInfo = GetSuggestionsAsync;
Thread th = new Thread(thInfo);
_filter = searchText;
th.Start(new object[] { searchText, _actb.Provider });
}
public void ShowFullCollection()
{
_filter = string.Empty;
_actb.IsLoading = true;
// Do not open drop down if control is not focused
if (_actb.IsKeyboardFocusWithin)
_actb.IsDropDownOpen = true;
_actb.ItemsSelector.ItemsSource = null;
ParameterizedThreadStart thInfo = GetFullCollectionAsync;
Thread th = new Thread(thInfo);
th.Start(_actb.Provider);
}
private void DisplaySuggestions(IEnumerable suggestions, string filter)
{
if (_filter != filter)
{
return;
}
_actb.IsLoading = false;
_actb.ItemsSelector.ItemsSource = suggestions;
// Close drop down if there are no items
if (_actb.IsDropDownOpen)
{
_actb.IsDropDownOpen = _actb.ItemsSelector.HasItems;
}
}
private void GetSuggestionsAsync(object param)
{
if (param is object[] args)
{
string searchText = Convert.ToString(args[0]);
if (args[1] is IComboSuggestionProvider provider)
{
IEnumerable list = provider.GetSuggestions(searchText);
_actb.Dispatcher.BeginInvoke(new Action<IEnumerable, string>(DisplaySuggestions), DispatcherPriority.Background, list, searchText);
}
}
}
private void GetFullCollectionAsync(object param)
{
if (param is IComboSuggestionProvider provider)
{
IEnumerable list = provider.GetFullCollection();
_actb.Dispatcher.BeginInvoke(new Action<IEnumerable, string>(DisplaySuggestions), DispatcherPriority.Background, list, string.Empty);
}
}
#endregion
}
#endregion
}
}

View File

@@ -0,0 +1,569 @@
using System;
using System.Collections;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
namespace AutoCompleteTextBox.Editors
{
[TemplatePart(Name = PartEditor, Type = typeof(TextBox))]
[TemplatePart(Name = PartPopup, Type = typeof(Popup))]
[TemplatePart(Name = PartSelector, Type = typeof(Selector))]
public class AutoCompleteTextBox : Control
{
#region "Fields"
public const string PartEditor = "PART_Editor";
public const string PartPopup = "PART_Popup";
public const string PartSelector = "PART_Selector";
public static readonly DependencyProperty DelayProperty = DependencyProperty.Register("Delay", typeof(int), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(200));
public static readonly DependencyProperty DisplayMemberProperty = DependencyProperty.Register("DisplayMember", typeof(string), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(string.Empty));
public static readonly DependencyProperty IconPlacementProperty = DependencyProperty.Register("IconPlacement", typeof(IconPlacement), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(IconPlacement.Left));
public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(object), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty IconVisibilityProperty = DependencyProperty.Register("IconVisibility", typeof(Visibility), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(Visibility.Visible));
public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty IsLoadingProperty = DependencyProperty.Register("IsLoading", typeof(bool), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty ItemTemplateSelectorProperty = DependencyProperty.Register("ItemTemplateSelector", typeof(DataTemplateSelector), typeof(AutoCompleteTextBox));
public static readonly DependencyProperty LoadingContentProperty = DependencyProperty.Register("LoadingContent", typeof(object), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty ProviderProperty = DependencyProperty.Register("Provider", typeof(ISuggestionProvider), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(null, OnSelectedItemChanged));
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(string.Empty, propertyChangedCallback:null,coerceValueCallback:null, isAnimationProhibited:false, defaultUpdateSourceTrigger: UpdateSourceTrigger.LostFocus, flags: FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public static readonly DependencyProperty FilterProperty = DependencyProperty.Register("Filter", typeof(string), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(string.Empty));
public static readonly DependencyProperty MaxLengthProperty = DependencyProperty.Register("MaxLength", typeof(int), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(0));
public static readonly DependencyProperty CharacterCasingProperty = DependencyProperty.Register("CharacterCasing", typeof(CharacterCasing), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(CharacterCasing.Normal));
public static readonly DependencyProperty MaxPopUpHeightProperty = DependencyProperty.Register("MaxPopUpHeight", typeof(int), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(600));
public static readonly DependencyProperty MaxPopUpWidthProperty = DependencyProperty.Register("MaxPopUpWidth", typeof(int), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(2000));
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register("Watermark", typeof(string), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(string.Empty));
public static readonly DependencyProperty SuggestionBackgroundProperty = DependencyProperty.Register("SuggestionBackground", typeof(Brush), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(Brushes.White));
private bool _isUpdatingText;
private bool _selectionCancelled;
private SuggestionsAdapter _suggestionsAdapter;
#endregion
#region "Constructors"
static AutoCompleteTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(typeof(AutoCompleteTextBox)));
FocusableProperty.OverrideMetadata(typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(true));
}
#endregion
#region "Properties"
public int MaxPopupHeight
{
get => (int)GetValue(MaxPopUpHeightProperty);
set => SetValue(MaxPopUpHeightProperty, value);
}
public int MaxPopupWidth
{
get => (int)GetValue(MaxPopUpWidthProperty);
set => SetValue(MaxPopUpWidthProperty, value);
}
public BindingEvaluator BindingEvaluator { get; set; }
public CharacterCasing CharacterCasing
{
get => (CharacterCasing)GetValue(CharacterCasingProperty);
set => SetValue(CharacterCasingProperty, value);
}
public int MaxLength
{
get => (int)GetValue(MaxLengthProperty);
set => SetValue(MaxLengthProperty, value);
}
public int Delay
{
get => (int)GetValue(DelayProperty);
set => SetValue(DelayProperty, value);
}
public string DisplayMember
{
get => (string)GetValue(DisplayMemberProperty);
set => SetValue(DisplayMemberProperty, value);
}
public TextBox Editor { get; set; }
public DispatcherTimer FetchTimer { get; set; }
public string Filter
{
get => (string)GetValue(FilterProperty);
set => SetValue(FilterProperty, value);
}
public object Icon
{
get => GetValue(IconProperty);
set => SetValue(IconProperty, value);
}
public IconPlacement IconPlacement
{
get => (IconPlacement)GetValue(IconPlacementProperty);
set => SetValue(IconPlacementProperty, value);
}
public Visibility IconVisibility
{
get => (Visibility)GetValue(IconVisibilityProperty);
set => SetValue(IconVisibilityProperty, value);
}
public bool IsDropDownOpen
{
get => (bool)GetValue(IsDropDownOpenProperty);
set => SetValue(IsDropDownOpenProperty, value);
}
public bool IsLoading
{
get => (bool)GetValue(IsLoadingProperty);
set => SetValue(IsLoadingProperty, value);
}
public bool IsReadOnly
{
get => (bool)GetValue(IsReadOnlyProperty);
set => SetValue(IsReadOnlyProperty, value);
}
public Selector ItemsSelector { get; set; }
public DataTemplate ItemTemplate
{
get => (DataTemplate)GetValue(ItemTemplateProperty);
set => SetValue(ItemTemplateProperty, value);
}
public DataTemplateSelector ItemTemplateSelector
{
get => ((DataTemplateSelector)(GetValue(ItemTemplateSelectorProperty)));
set => SetValue(ItemTemplateSelectorProperty, value);
}
public object LoadingContent
{
get => GetValue(LoadingContentProperty);
set => SetValue(LoadingContentProperty, value);
}
public Popup Popup { get; set; }
public ISuggestionProvider Provider
{
get => (ISuggestionProvider)GetValue(ProviderProperty);
set => SetValue(ProviderProperty, value);
}
public object SelectedItem
{
get => GetValue(SelectedItemProperty);
set => SetValue(SelectedItemProperty, value);
}
public SelectionAdapter SelectionAdapter { get; set; }
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public string Watermark
{
get => (string)GetValue(WatermarkProperty);
set => SetValue(WatermarkProperty, value);
}
public Brush SuggestionBackground
{
get => (Brush)GetValue(SuggestionBackgroundProperty);
set => SetValue(SuggestionBackgroundProperty, value);
}
#endregion
#region "Methods"
public static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
AutoCompleteTextBox act = null;
act = d as AutoCompleteTextBox;
if (act != null)
{
if (act.Editor != null & !act._isUpdatingText)
{
act._isUpdatingText = true;
act.Editor.Text = act.BindingEvaluator.Evaluate(e.NewValue);
act._isUpdatingText = false;
}
}
}
private void ScrollToSelectedItem()
{
if (ItemsSelector is ListBox listBox && listBox.SelectedItem != null)
listBox.ScrollIntoView(listBox.SelectedItem);
}
public new BindingExpressionBase SetBinding(DependencyProperty dp, BindingBase binding){
var res = base.SetBinding(dp, binding);
CheckForParentTextBindingChange();
return res;
}
public new BindingExpressionBase SetBinding(DependencyProperty dp, String path) {
var res = base.SetBinding(dp, path);
CheckForParentTextBindingChange();
return res;
}
public new void ClearValue(DependencyPropertyKey key) {
base.ClearValue(key);
CheckForParentTextBindingChange();
}
public new void ClearValue(DependencyProperty dp) {
base.ClearValue(dp);
CheckForParentTextBindingChange();
}
private void CheckForParentTextBindingChange(bool force=false) {
var CurrentBindingMode = BindingOperations.GetBinding(this, TextProperty)?.UpdateSourceTrigger ?? UpdateSourceTrigger.Default;
if (CurrentBindingMode != UpdateSourceTrigger.PropertyChanged)//preventing going any less frequent than property changed
CurrentBindingMode = UpdateSourceTrigger.Default;
if (CurrentBindingMode == CurrentTextboxTextBindingUpdateMode && force == false)
return;
var binding = new Binding {
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = CurrentBindingMode,
Path = new PropertyPath(nameof(Text)),
RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
};
CurrentTextboxTextBindingUpdateMode = CurrentBindingMode;
Editor?.SetBinding(TextBox.TextProperty, binding);
}
private UpdateSourceTrigger CurrentTextboxTextBindingUpdateMode;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Editor = Template.FindName(PartEditor, this) as TextBox;
Editor.Focus();
Popup = Template.FindName(PartPopup, this) as Popup;
ItemsSelector = Template.FindName(PartSelector, this) as Selector;
BindingEvaluator = new BindingEvaluator(new Binding(DisplayMember));
if (Editor != null)
{
Editor.TextChanged += OnEditorTextChanged;
Editor.PreviewKeyDown += OnEditorKeyDown;
Editor.LostFocus += OnEditorLostFocus;
CheckForParentTextBindingChange(true);
if (SelectedItem != null)
{
_isUpdatingText = true;
Editor.Text = BindingEvaluator.Evaluate(SelectedItem);
_isUpdatingText = false;
}
}
GotFocus += AutoCompleteTextBox_GotFocus;
GotKeyboardFocus += AutoCompleteTextBox_GotKeyboardFocus;
if (Popup != null)
{
Popup.StaysOpen = false;
Popup.Opened += OnPopupOpened;
Popup.Closed += OnPopupClosed;
}
if (ItemsSelector != null)
{
SelectionAdapter = new SelectionAdapter(ItemsSelector);
SelectionAdapter.Commit += OnSelectionAdapterCommit;
SelectionAdapter.Cancel += OnSelectionAdapterCancel;
SelectionAdapter.SelectionChanged += OnSelectionAdapterSelectionChanged;
ItemsSelector.PreviewMouseDown += ItemsSelector_PreviewMouseDown;
}
}
private void ItemsSelector_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if ((e.OriginalSource as FrameworkElement)?.DataContext == null)
return;
if (!ItemsSelector.Items.Contains(((FrameworkElement)e.OriginalSource)?.DataContext))
return;
ItemsSelector.SelectedItem = ((FrameworkElement)e.OriginalSource)?.DataContext;
OnSelectionAdapterCommit(SelectionAdapter.EventCause.MouseDown);
e.Handled = true;
}
private void AutoCompleteTextBox_GotFocus(object sender, RoutedEventArgs e)
{
Editor?.Focus();
}
private void AutoCompleteTextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) {
if (e.NewFocus != this)
return;
if (e.OldFocus == Editor)
MoveFocus(new TraversalRequest(FocusNavigationDirection.Previous));
}
private string GetDisplayText(object dataItem)
{
if (BindingEvaluator == null)
{
BindingEvaluator = new BindingEvaluator(new Binding(DisplayMember));
}
if (dataItem == null)
{
return string.Empty;
}
if (string.IsNullOrEmpty(DisplayMember))
{
return dataItem.ToString();
}
return BindingEvaluator.Evaluate(dataItem);
}
private void OnEditorKeyDown(object sender, KeyEventArgs e)
{
if (SelectionAdapter != null)
{
if (IsDropDownOpen)
SelectionAdapter.HandleKeyDown(e);
else
IsDropDownOpen = e.Key == Key.Down || e.Key == Key.Up;
}
}
private void OnEditorLostFocus(object sender, RoutedEventArgs e)
{
if (!IsKeyboardFocusWithin)
{
IsDropDownOpen = false;
}
}
private void OnEditorTextChanged(object sender, TextChangedEventArgs e)
{
Text = Editor.Text;
if (_isUpdatingText)
return;
if (FetchTimer == null)
{
FetchTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(Delay) };
FetchTimer.Tick += OnFetchTimerTick;
}
FetchTimer.IsEnabled = false;
FetchTimer.Stop();
SetSelectedItem(null);
if (Editor.Text.Length > 0)
{
FetchTimer.IsEnabled = true;
FetchTimer.Start();
}
else
{
IsDropDownOpen = false;
}
}
private void OnFetchTimerTick(object sender, EventArgs e)
{
FetchTimer.IsEnabled = false;
FetchTimer.Stop();
if (Provider != null && ItemsSelector != null)
{
Filter = Editor.Text;
if (_suggestionsAdapter == null)
{
_suggestionsAdapter = new SuggestionsAdapter(this);
}
_suggestionsAdapter.GetSuggestions(Filter);
}
}
private void OnPopupClosed(object sender, EventArgs e)
{
if (!_selectionCancelled)
{
OnSelectionAdapterCommit(SelectionAdapter.EventCause.PopupClosed);
}
}
private void OnPopupOpened(object sender, EventArgs e)
{
_selectionCancelled = false;
ItemsSelector.SelectedItem = SelectedItem;
}
private void OnSelectionAdapterCancel(SelectionAdapter.EventCause cause)
{
if (PreSelectionEventSomeoneHandled(cause, true))
return;
_isUpdatingText = true;
Editor.Text = SelectedItem == null ? Filter : GetDisplayText(SelectedItem);
Editor.SelectionStart = Editor.Text.Length;
Editor.SelectionLength = 0;
_isUpdatingText = false;
IsDropDownOpen = false;
_selectionCancelled = true;
}
public event EventHandler<SelectionAdapter.PreSelectionAdapterFinishArgs> PreSelectionAdapterFinish;
private bool PreSelectionEventSomeoneHandled(SelectionAdapter.EventCause cause, bool is_cancel) {
if (PreSelectionAdapterFinish == null)
return false;
var args = new SelectionAdapter.PreSelectionAdapterFinishArgs { cause = cause, is_cancel = is_cancel };
PreSelectionAdapterFinish?.Invoke(this, args);
return args.handled;
}
private void OnSelectionAdapterCommit(SelectionAdapter.EventCause cause)
{
if (PreSelectionEventSomeoneHandled(cause, false))
return;
if (ItemsSelector.SelectedItem != null)
{
SelectedItem = ItemsSelector.SelectedItem;
_isUpdatingText = true;
Editor.Text = GetDisplayText(ItemsSelector.SelectedItem);
SetSelectedItem(ItemsSelector.SelectedItem);
_isUpdatingText = false;
IsDropDownOpen = false;
}
}
private void OnSelectionAdapterSelectionChanged()
{
_isUpdatingText = true;
Editor.Text = ItemsSelector.SelectedItem == null ? Filter : GetDisplayText(ItemsSelector.SelectedItem);
Editor.SelectionStart = Editor.Text.Length;
Editor.SelectionLength = 0;
ScrollToSelectedItem();
_isUpdatingText = false;
}
private void SetSelectedItem(object item)
{
_isUpdatingText = true;
SelectedItem = item;
_isUpdatingText = false;
}
#endregion
#region "Nested Types"
private class SuggestionsAdapter
{
#region "Fields"
private readonly AutoCompleteTextBox _actb;
private string _filter;
#endregion
#region "Constructors"
public SuggestionsAdapter(AutoCompleteTextBox actb)
{
_actb = actb;
}
#endregion
#region "Methods"
public void GetSuggestions(string searchText)
{
_filter = searchText;
_actb.IsLoading = true;
// Do not open drop down if control is not focused
if (_actb.IsKeyboardFocusWithin)
_actb.IsDropDownOpen = true;
_actb.ItemsSelector.ItemsSource = null;
ParameterizedThreadStart thInfo = GetSuggestionsAsync;
Thread th = new Thread(thInfo);
th.Start(new object[] { searchText, _actb.Provider });
}
private void DisplaySuggestions(IEnumerable suggestions, string filter)
{
if (_filter != filter)
{
return;
}
_actb.IsLoading = false;
_actb.ItemsSelector.ItemsSource = suggestions;
// Close drop down if there are no items
if (_actb.IsDropDownOpen)
{
_actb.IsDropDownOpen = _actb.ItemsSelector.HasItems;
}
}
private void GetSuggestionsAsync(object param)
{
if (param is object[] args)
{
string searchText = Convert.ToString(args[0]);
if (args[1] is ISuggestionProvider provider)
{
IEnumerable list = provider.GetSuggestions(searchText);
_actb.Dispatcher.BeginInvoke(new Action<IEnumerable, string>(DisplaySuggestions), DispatcherPriority.Background, list, searchText);
}
}
}
#endregion
}
#endregion
}
}

View File

@@ -0,0 +1,16 @@
using System.Collections;
namespace AutoCompleteTextBox.Editors
{
public interface IComboSuggestionProvider
{
#region Public Methods
IEnumerable GetSuggestions(string filter);
IEnumerable GetFullCollection();
#endregion Public Methods
}
}

View File

@@ -0,0 +1,15 @@
using System.Collections;
namespace AutoCompleteTextBox.Editors
{
public interface ISuggestionProvider
{
#region Public Methods
IEnumerable GetSuggestions(string filter);
#endregion Public Methods
}
}

View File

@@ -0,0 +1,122 @@
using System.Diagnostics;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
namespace AutoCompleteTextBox.Editors
{
public class SelectionAdapter
{
public class PreSelectionAdapterFinishArgs {
public EventCause cause;
public bool is_cancel;
public bool handled;
}
#region "Fields"
#endregion
#region "Constructors"
public SelectionAdapter(Selector selector)
{
SelectorControl = selector;
SelectorControl.PreviewMouseUp += OnSelectorMouseDown;
}
#endregion
#region "Events"
public enum EventCause { Other, PopupClosed, ItemClicked, EnterPressed, EscapePressed, TabPressed, MouseDown}
public delegate void CancelEventHandler(EventCause cause);
public delegate void CommitEventHandler(EventCause cause);
public delegate void SelectionChangedEventHandler();
public event CancelEventHandler Cancel;
public event CommitEventHandler Commit;
public event SelectionChangedEventHandler SelectionChanged;
#endregion
#region "Properties"
public Selector SelectorControl { get; set; }
#endregion
#region "Methods"
public void HandleKeyDown(KeyEventArgs key)
{
switch (key.Key)
{
case Key.Down:
IncrementSelection();
break;
case Key.Up:
DecrementSelection();
break;
case Key.Enter:
Commit?.Invoke(EventCause.EnterPressed);
break;
case Key.Escape:
Cancel?.Invoke(EventCause.EscapePressed);
break;
case Key.Tab:
Commit?.Invoke(EventCause.TabPressed);
break;
default:
return;
}
key.Handled = true;
}
private void DecrementSelection()
{
if (SelectorControl.SelectedIndex == -1)
{
SelectorControl.SelectedIndex = SelectorControl.Items.Count - 1;
}
else
{
SelectorControl.SelectedIndex -= 1;
}
SelectionChanged?.Invoke();
}
private void IncrementSelection()
{
if (SelectorControl.SelectedIndex == SelectorControl.Items.Count - 1)
{
SelectorControl.SelectedIndex = -1;
}
else
{
SelectorControl.SelectedIndex += 1;
}
SelectionChanged?.Invoke();
}
private void OnSelectorMouseDown(object sender, MouseButtonEventArgs e)
{
// If sender is the RepeatButton from the scrollbar we need to
// to skip this event otherwise focus get stuck in the RepeatButton
// and list is scrolled up or down til the end.
if (e.OriginalSource.GetType() != typeof(RepeatButton))
{
Commit?.Invoke(EventCause.MouseDown);
e.Handled = true;
}
}
#endregion
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections;
namespace AutoCompleteTextBox.Editors
{
public class SuggestionProvider : ISuggestionProvider
{
#region Private Fields
private readonly Func<string, IEnumerable> _method;
#endregion Private Fields
#region Public Constructors
public SuggestionProvider(Func<string, IEnumerable> method)
{
_method = method ?? throw new ArgumentNullException(nameof(method));
}
#endregion Public Constructors
#region Public Methods
public IEnumerable GetSuggestions(string filter)
{
return _method(filter);
}
#endregion Public Methods
}
}

View File

@@ -0,0 +1,268 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:editors="clr-namespace:AutoCompleteTextBox.Editors">
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
<Style x:Key="TextBoxSuggestionItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="ContentBorder" Background="{Binding Path=SuggestionBackground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editors:AutoCompleteTextBox}, Mode=OneWay}">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="ContentBorder" Property="Background" Value="{x:Static SystemColors.HighlightBrush}" />
<Setter Property="TextElement.Foreground" Value="{x:Static SystemColors.HighlightTextBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ComboBoxSuggestionItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="ContentBorder" Background="{Binding Path=SuggestionBackground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editors:AutoCompleteComboBox}, Mode=OneWay}">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="ContentBorder" Property="Background" Value="{x:Static SystemColors.HighlightBrush}" />
<Setter Property="TextElement.Foreground" Value="{x:Static SystemColors.HighlightTextBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="TransparentTextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<ScrollViewer
x:Name="PART_ContentHost"
Background="Transparent"
CanContentScroll="True"
Focusable="True"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type editors:AutoCompleteTextBox}">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="#FFABADB3" />
<Setter Property="SuggestionBackground" Value="White" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Top" />
<Setter Property="AllowDrop" Value="true" />
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst" />
<Setter Property="Stylus.IsFlicksEnabled" Value="False" />
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type editors:AutoCompleteTextBox}">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="0">
<Grid>
<DockPanel>
<ContentPresenter
x:Name="PART_Icon"
ContentSource="Icon"
Visibility="{TemplateBinding IconVisibility}" />
<Grid>
<TextBlock
x:Name="PART_Watermark"
Margin="3,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Focusable="False"
Foreground="Gray"
Text="{TemplateBinding Watermark}"
Visibility="Collapsed" />
<TextBox
x:Name="PART_Editor"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
CharacterCasing="{Binding Path=CharacterCasing, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=OneWay}"
MaxLength="{Binding Path=MaxLength, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
Style="{StaticResource ResourceKey=TransparentTextBoxStyle}" />
</Grid>
</DockPanel>
<Popup
x:Name="PART_Popup"
MinWidth="{TemplateBinding ActualWidth}"
MinHeight="25"
MaxHeight="600"
AllowsTransparency="True"
Focusable="False"
HorizontalOffset="0"
IsOpen="{Binding Path=IsDropDownOpen, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
PopupAnimation="Slide">
<Border
Padding="2"
Background="{Binding Path=SuggestionBackground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editors:AutoCompleteTextBox}, Mode=OneWay}"
BorderBrush="Gray"
BorderThickness="1"
CornerRadius="5">
<Grid Background="{Binding Path=SuggestionBackground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editors:AutoCompleteTextBox}, Mode=OneWay}">
<ListBox
x:Name="PART_Selector"
MaxWidth="{Binding Path=MaxPopupWidth, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
MaxHeight="{Binding Path=MaxPopupHeight, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
Background="{Binding Path=SuggestionBackground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editors:AutoCompleteTextBox}, Mode=OneWay}"
BorderThickness="0"
Focusable="False"
ItemContainerStyle="{StaticResource ResourceKey=TextBoxSuggestionItemStyle}"
ItemTemplate="{TemplateBinding ItemTemplate}"
ItemTemplateSelector="{TemplateBinding ItemTemplateSelector}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto" />
<Border Visibility="{Binding Path=IsLoading, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource ResourceKey=BoolToVisConverter}}">
<ContentPresenter ContentSource="LoadingContent" />
</Border>
</Grid>
</Border>
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger SourceName="PART_Editor" Property="Text" Value="">
<Setter TargetName="PART_Watermark" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="IconPlacement" Value="Left">
<Setter TargetName="PART_Icon" Property="DockPanel.Dock" Value="Left" />
</Trigger>
<Trigger Property="IconPlacement" Value="Right">
<Setter TargetName="PART_Icon" Property="DockPanel.Dock" Value="Right" />
</Trigger>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="editors:AutoCompleteComboBox">
<Setter Property="Focusable" Value="True" />
<Setter Property="SuggestionBackground" Value="White" />
<Setter Property="BorderThickness" Value="0,0,0,1" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Top" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="AllowDrop" Value="true" />
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst" />
<Setter Property="Stylus.IsFlicksEnabled" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type editors:AutoCompleteComboBox}">
<Grid>
<DockPanel>
<ContentPresenter
x:Name="PART_Icon"
ContentSource="Icon"
Visibility="{TemplateBinding IconVisibility}" />
<Grid>
<TextBlock
x:Name="PART_Watermark"
HorizontalAlignment="Left"
VerticalAlignment="Center"
DockPanel.Dock="Left"
Focusable="False"
Foreground="Gray"
Text="{TemplateBinding Watermark}"
Visibility="Collapsed" />
<DockPanel Margin="3,0">
<Expander x:Name="PART_Expander" DockPanel.Dock="Right" />
<TextBox
x:Name="PART_Editor"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
CharacterCasing="{Binding Path=CharacterCasing, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
Focusable="True"
MaxLength="{Binding Path=MaxLength, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}" />
</DockPanel>
</Grid>
</DockPanel>
<Popup
x:Name="PART_Popup"
MinWidth="{TemplateBinding ActualWidth}"
MinHeight="25"
MaxHeight="600"
AllowsTransparency="True"
Focusable="False"
HorizontalOffset="0"
IsOpen="{Binding Path=IsDropDownOpen, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
PopupAnimation="Slide">
<Border
Padding="2"
Background="{Binding Path=SuggestionBackground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editors:AutoCompleteComboBox}, Mode=OneWay}"
BorderBrush="Gray"
BorderThickness="1"
CornerRadius="5">
<Grid>
<ListBox
x:Name="PART_Selector"
MaxWidth="{Binding Path=MaxPopupWidth, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
MaxHeight="{Binding Path=MaxPopupHeight, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
Background="{Binding Path=SuggestionBackground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editors:AutoCompleteComboBox}, Mode=OneWay}"
BorderThickness="0"
Focusable="False"
ItemContainerStyle="{StaticResource ResourceKey=ComboBoxSuggestionItemStyle}"
ItemTemplate="{TemplateBinding ItemTemplate}"
ItemTemplateSelector="{TemplateBinding ItemTemplateSelector}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto" />
<Border Visibility="{Binding Path=IsLoading, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource ResourceKey=BoolToVisConverter}}">
<ContentPresenter ContentSource="LoadingContent" />
</Border>
</Grid>
</Border>
</Popup>
</Grid>
<!--</Border>-->
<ControlTemplate.Triggers>
<Trigger SourceName="PART_Editor" Property="Text" Value="">
<Setter TargetName="PART_Watermark" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="IconPlacement" Value="Left">
<Setter TargetName="PART_Icon" Property="DockPanel.Dock" Value="Left" />
</Trigger>
<Trigger Property="IconPlacement" Value="Right">
<Setter TargetName="PART_Icon" Property="DockPanel.Dock" Value="Right" />
</Trigger>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,8 @@
namespace AutoCompleteTextBox
{
public enum IconPlacement
{
Left,
Right
}
}

View File

@@ -0,0 +1,53 @@
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Markup;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("AutoCompleteTextBox")]
[assembly: AssemblyDescription("An autocomplete textbox for WPF")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AutoCompleteTextBox")]
[assembly: AssemblyCopyright("Copyright © 2019")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly:ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.1.1.0")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: XmlnsDefinition("http://wpfcontrols.com/", "AutoCompleteTextBox")]
[assembly: XmlnsDefinition("http://wpfcontrols.com/", "AutoCompleteTextBox.Editors")]

View File

@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace AutoCompleteTextBox.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AutoCompleteTextBox.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace AutoCompleteTextBox.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -0,0 +1,6 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/AutoCompleteTextBox;component/editors/themes/generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>