Goffo.WpfAutoCompleteTextbox 1.4.0

dotnet add package Goffo.WpfAutoCompleteTextbox --version 1.4.0
NuGet\Install-Package Goffo.WpfAutoCompleteTextbox -Version 1.4.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Goffo.WpfAutoCompleteTextbox" Version="1.4.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Goffo.WpfAutoCompleteTextbox --version 1.4.0
#r "nuget: Goffo.WpfAutoCompleteTextbox, 1.4.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Goffo.WpfAutoCompleteTextbox as a Cake Addin
#addin nuget:?package=Goffo.WpfAutoCompleteTextbox&version=1.4.0

// Install Goffo.WpfAutoCompleteTextbox as a Cake Tool
#tool nuget:?package=Goffo.WpfAutoCompleteTextbox&version=1.4.0

README

What is this repository for?

  • Resuable Autocomplete TextBox for WPF Applications
  • NuGet Package: Goffo.WpfAutoCompleteTextbox
  • Learn Markdown

How do I get set up?

  • XAML Example
<Window x:Class="AutoCompleteTextBox.WPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AutoCompleteTextBox.WPF"
        xmlns:custom="clr-namespace:WPFAutoCompleteTextBox.CustomControl;assembly=WPFAutoCompleteTextBox.CustomControl"
        xmlns:eventattachments="clr-namespace:AutoCompleteTextBox.WPF.EventAttachments"
        mc:Ignorable="d"
        x:Name="thisWindow"
        Title="Auto Complete Text Box Demo" Height="450" Width="800">
    <Window.Resources>
        <Style TargetType="TextBox" x:Key="AutoCompleteTB">
            <Setter Property="VerticalContentAlignment" Value="Center"></Setter>
            <Setter Property="HorizontalContentAlignment" Value="Left"></Setter>
            <Setter Property="VerticalAlignment" Value="Center"></Setter>
            <Setter Property="HorizontalAlignment" Value="Center"></Setter>
            <Setter Property="Width" Value="125"></Setter>
            <Setter Property="Height" Value="25"></Setter>
            <Setter Property="BorderBrush" Value="Black"></Setter>
            <Setter Property="BorderThickness" Value="1.5"></Setter>
            <Style.Resources>
                <Style TargetType="Border">
                    <Setter Property="CornerRadius" Value="3"></Setter>
                </Style>
            </Style.Resources>
            
        </Style>

        <Style TargetType="ListBox" x:Key="AutoCompleteLB">
            <Setter Property="Height" Value="Auto"></Setter>
            <Setter Property="Width" Value="Auto"></Setter>
            <Setter Property="MaxHeight" Value="65"></Setter>
            <Setter Property="Background" Value="LightGray"></Setter>
            <Setter Property="FontWeight" Value="SemiBold"></Setter>
            <Style.Resources>
                <Style TargetType="Border">
                    <Setter Property="CornerRadius" Value="3"></Setter>
                </Style>
            </Style.Resources>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Top">
            <StackPanel Orientation="Horizontal" Margin="10" HorizontalAlignment="Center" VerticalAlignment="Center">
                <TextBlock HorizontalAlignment="Center" 
                           VerticalAlignment="Center" 
                           FontSize="16" 
                           FontWeight="SemiBold"
                           Text="Product ID">
                </TextBlock>
            </StackPanel>
            <custom:AutoCompleteTextBox
                    Grid.Row="0"
                    x:Name="AutoComplete"
                    AutoCompleteMargin="0 12 0 0"
                    AutoCompleteOrientation="Horizontal"
                    TextBoxStyle="{StaticResource AutoCompleteTB}"
                    SearchText="{Binding Search}"
                    SearchTextIsReadOnly="{Binding SearchIsReadOnly}"
                    ListBoxStyle="{StaticResource AutoCompleteLB}"
                    SearchItems="{Binding Products}"
                    DisplayMemberPath="ProductID"
                    SelectedSearchItem="{Binding SelectedProduct}"
                    IsSearchItemsVisible="{Binding IsSearchItemsVisible}"
                    OnLoadedCommand="{Binding OnLoadedCommand}"
                >
            </custom:AutoCompleteTextBox>
            <StackPanel Orientation="Horizontal" Margin="10" HorizontalAlignment="Center" VerticalAlignment="Center">
                <Button eventattachments:FocusOnButtonClickEventAttachment.ElementToFocus="{Binding ElementName=AutoComplete}" Width="100" Height="25" FontSize="16" FontWeight="SemiBold" Command="{Binding ClearCommand}" HorizontalAlignment="Center" VerticalAlignment="Center">Clear</Button>
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>

  • ViewModel Example - Don't forget to set the DataContext of the Window to the ViewModel

using AutoCompleteTextBox.WPF.Commands;
using AutoCompleteTextBox.WPF.Data;
using AutoCompleteTextBox.WPF.Models;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;

namespace AutoCompleteTextBox.WPF.ViewModels
{
    public class MainViewModel : INotifyPropertyChanged
    {
        private readonly DataAccess _dataAccess;

        public MainViewModel(DataAccess dataAccess)
        {
            _dataAccess = dataAccess;
            ClearCommand = new ClearCommand(this);
            OnLoadedCommand = new OnLoadedCommand();
        }

        public event PropertyChangedEventHandler? PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public ICommand ClearCommand { get; set; }
        public ICommand OnLoadedCommand { get; set; }

        private void setProductsAsync(string searchText)
        {
            SearchIsReadOnly = true;

            if(string.IsNullOrWhiteSpace(searchText))
            {
                Products.Clear();
                IsSearchItemsVisible = false;
            }
            else
            {
                toggleLoadingProducts();

                _dataAccess.GetProductsAsync(searchText)
                    .ContinueWith(t =>
                    {
                        if (t.Exception is null)
                        {
                            Products = t.Result.ToList();
                        }
                        else
                        {
                            MessageBox.Show(t.Exception.Message, "ERROR", MessageBoxButton.OK, MessageBoxImage.Error);
                        }
                    });

                toggleLoadingProducts();
            }

            SearchIsReadOnly = false;
        }

        private bool _isLoadingProducts = false;
        private void toggleLoadingProducts()
        {
            _isLoadingProducts = !_isLoadingProducts;

            if (_isLoadingProducts)
            {
                Products = new List<ProductModel> { new ProductModel { ProductID = "LOADING..." } };
                IsSearchItemsVisible = true;
            }
        }

        private string _search = string.Empty;

        public string Search
        {
            get => _search;

            set
            {
                if(_search == value || SearchIsReadOnly)
                {
                    return;
                }

                _search = value;
                OnPropertyChanged(nameof(Search));
                setProductsAsync(value);
            }
        }

        private List<ProductModel> _products = new();

        public List<ProductModel> Products
        {
            get => _products;

            set
            {
                _products = value;
                OnPropertyChanged(nameof(Products));
            }
        }

        private bool _searchIsReadOnly = false;

        public bool SearchIsReadOnly
        {
            get => _searchIsReadOnly;

            set
            {
                _searchIsReadOnly = value;
                OnPropertyChanged(nameof(SearchIsReadOnly));
            }
        }

        private ProductModel _selectedProduct = new ProductModel();

        public ProductModel SelectedProduct
        {
            get => _selectedProduct;

            set
            {
                if (_selectedProduct == value || value is null)
                {
                    return;
                }

                _selectedProduct = value;
                OnPropertyChanged(nameof(SelectedProduct));

                Search = value.ProductID;
                IsSearchItemsVisible = false;
            }
        }

        private bool _isSearchItemsVisible = false;

        public bool IsSearchItemsVisible
        {
            get => _isSearchItemsVisible;

            set
            {
                _isSearchItemsVisible = value;
                OnPropertyChanged(nameof(IsSearchItemsVisible));
            }
        }
    }
}

Commands

using AutoCompleteTextBox.WPF.ViewModels;
using System;
using System.Windows.Input;

namespace AutoCompleteTextBox.WPF.Commands
{
    public class ClearCommand : ICommand
    {
        private readonly MainViewModel _mainViewModel;

        public ClearCommand(MainViewModel mainViewModel)
        {
            _mainViewModel = mainViewModel;
        }

        public event EventHandler? CanExecuteChanged;

        public bool CanExecute(object? parameter)
        {
            return true;
        }

        public void Execute(object? parameter)
        {
            _mainViewModel.Search = string.Empty;
        }
    }
}

using System;
using System.Windows.Input;

namespace AutoCompleteTextBox.WPF.Commands
{
    public class OnLoadedCommand : ICommand
    {
        public event EventHandler? CanExecuteChanged;

        public bool CanExecute(object? parameter)
        {
            return true;
        }

        public void Execute(object? parameter)
        {
            if(parameter is null)
            {
                return;
            }

            WPFAutoCompleteTextBox.CustomControl.AutoCompleteTextBox autoComplete = (WPFAutoCompleteTextBox.CustomControl.AutoCompleteTextBox)parameter;
            autoComplete.SetFocus();
        }
    }
}

Event Attachments


using System.Windows.Controls;
using System.Windows;

namespace AutoCompleteTextBox.WPF.EventAttachments
{
    public static class FocusOnButtonClickEventAttachment
    {
        public static Control GetElementToFocus(Button button)
        {
            return (Control)button.GetValue(ElementToFocusProperty);
        }

        public static void SetElementToFocus(Button button, Control value)
        {
            button.SetValue(ElementToFocusProperty, value);
        }

        public static readonly DependencyProperty ElementToFocusProperty =
            DependencyProperty.RegisterAttached("ElementToFocus", typeof(Control),
            typeof(FocusOnButtonClickEventAttachment), new UIPropertyMetadata(null, ElementToFocusPropertyChanged));

        public static void ElementToFocusPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var button = sender as Button;
            if (button != null)
            {
                button.Click += (sender, args) =>
                {
                    Control control = GetElementToFocus(button);

                    if (control != null)
                    {
                        WPFAutoCompleteTextBox.CustomControl.AutoCompleteTextBox autoComplete = (WPFAutoCompleteTextBox.CustomControl.AutoCompleteTextBox)control;
                        autoComplete.SetFocus();
                    }
                };
            }
        }
    }
}


Contribution guidelines

  • Contact Repo Owner

Who do I talk to?

  • Repo owner or admin
  • Other community or team contact
Product Compatible and additional computed target framework versions.
.NET net6.0-windows7.0 is compatible.  net7.0-windows was computed.  net7.0-windows7.0 is compatible.  net8.0-windows was computed.  net8.0-windows7.0 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0-windows7.0

    • No dependencies.
  • net7.0-windows7.0

    • No dependencies.
  • net8.0-windows7.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.4.0 91 3/19/2024
1.3.0 109 1/23/2024
1.2.1 196 11/7/2023
1.2.0 79 11/7/2023
1.1.0 87 11/6/2023
1.0.0 97 10/18/2023

Add dependency property for the list box item hover over background and border