Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Add AutoSuggestion option for TextBox #3207

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2a90e3c
Implement the AutoSuggestion in TextBox by using TextFieldAssist.Auto…
AbderrahmaneAhmam May 20, 2023
b3e1d3f
Fixing the code warnings about the null values
AbderrahmaneAhmam May 21, 2023
1e7552d
Fix warnings in the FieldsViewModel 0 Warning(s)
AbderrahmaneAhmam May 21, 2023
0f1bb1c
Add underscore prefix to the private properties
AbderrahmaneAhmam May 22, 2023
6d41235
Reset changes of the AutoSuggestion in the TextFieldAssist
AbderrahmaneAhmam May 27, 2023
d509195
creation of control AutoSuggestBox Based on TextBox with custom Templ…
AbderrahmaneAhmam Jun 19, 2023
dbaa4e3
Fix Warnings
AbderrahmaneAhmam Jun 19, 2023
e0d3ed0
Rebase build fixing
Keboo Aug 10, 2023
7d85d89
Adding some TODOs, starting on the UI tests
Keboo Aug 10, 2023
03ec8e4
Merge branch 'MaterialDesignInXAML:master' into feature/AutoSuggestion
AbderrahmaneAhmam Aug 12, 2023
aa7b202
Merge branch 'master' of https://github.com/AbderrahmaneAhmam/Materia…
AbderrahmaneAhmam Aug 12, 2023
0fdfbd7
Merge branch 'feature/AutoSuggestion' of https://github.com/Abderrahm…
AbderrahmaneAhmam Aug 12, 2023
829e298
Remove AutoSuggestBox from properties
AbderrahmaneAhmam Aug 12, 2023
e6b148a
Implement the tests:
AbderrahmaneAhmam Aug 12, 2023
26f2c22
WIP showing sample test for ICollectionView
Keboo Aug 13, 2023
9946cab
Merge branch 'MaterialDesignInXAML:master' into feature/AutoSuggestion
AbderrahmaneAhmam Aug 14, 2023
408708b
Merge branch 'MaterialDesignInXAML:master' into feature/AutoSuggestion
AbderrahmaneAhmam Aug 17, 2023
8d8889e
Use ICollectionView for keyboard navigation and ensure completion of …
AbderrahmaneAhmam Sep 3, 2023
d47c665
rename key
AbderrahmaneAhmam Sep 3, 2023
e1f4419
Merge branch 'MaterialDesignInXAML:master' into feature/AutoSuggestion
AbderrahmaneAhmam Sep 3, 2023
596f708
Merge branch 'master' of https://github.com/AbderrahmaneAhmam/Materia…
AbderrahmaneAhmam Sep 3, 2023
82bee7a
Merge branch 'feature/AutoSuggestion' of https://github.com/Abderrahm…
AbderrahmaneAhmam Sep 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions MainDemo.Wpf/Converters/ColorToBrushConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@ namespace MaterialDesignDemo.Converters;
[ValueConversion(typeof(Color), typeof(Brush))]
public class ColorToBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is Color color)
{
return new SolidColorBrush(color);
SolidColorBrush rv = new(color);
rv.Freeze();
return rv;
}
return Binding.DoNothing;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is SolidColorBrush brush)
{
Expand Down
78 changes: 77 additions & 1 deletion MainDemo.Wpf/Domain/FieldsViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
namespace MaterialDesignDemo.Domain;
using System.Collections.ObjectModel;
using System.Windows.Media;

namespace MaterialDesignDemo.Domain;
public class FieldsViewModel : ViewModelBase
{
private string? _name;
Expand All @@ -10,6 +12,12 @@ public class FieldsViewModel : ViewModelBase
private string? _password2Validated = "pre-filled";
private string? _text1;
private string? _text2;
private ObservableCollection<string>? _autoSuggestBox1Suggestions;
private string? _autoSuggestBox1Text;
private readonly List<string>? _originalAutoSuggestBox1Suggestions;
private ObservableCollection<KeyValuePair<string, Color>>? _autoSuggestBox2Suggestions;
private string? _autoSuggestBox2Text;
private readonly List<KeyValuePair<string, Color>>? _originalAutoSuggestBox2Suggestions;

public string? Name
{
Expand Down Expand Up @@ -71,13 +79,81 @@ public string? Password2Validated

public FieldsTestObject TestObject => new() { Name = "Mr. Test" };

public ObservableCollection<string>? AutoSuggestBox1Suggestions
{
get => _autoSuggestBox1Suggestions;
set => SetProperty(ref _autoSuggestBox1Suggestions, value);
}

public ObservableCollection<KeyValuePair<string, Color>>? AutoSuggestBox2Suggestions
{
get => _autoSuggestBox2Suggestions;
set => SetProperty(ref _autoSuggestBox2Suggestions, value);
}

public string? AutoSuggestBox1Text
{
get => _autoSuggestBox1Text;
set
{
if (SetProperty(ref _autoSuggestBox1Text, value) &&
_originalAutoSuggestBox1Suggestions != null && value != null)
{
var searchResult = _originalAutoSuggestBox1Suggestions.Where(x => IsMatch(x, value));
AutoSuggestBox1Suggestions = new ObservableCollection<string>(searchResult);
}
}
}

public string? AutoSuggestBox2Text
{
get => _autoSuggestBox2Text;
set
{
if (SetProperty(ref _autoSuggestBox2Text, value) &&
_originalAutoSuggestBox2Suggestions != null && value != null)
{
var searchResult = _originalAutoSuggestBox2Suggestions.Where(x => IsMatch(x.Key, value));
AutoSuggestBox2Suggestions = new ObservableCollection<KeyValuePair<string, Color>>(searchResult);
}
}
}

public ICommand SetPassword1FromViewModelCommand { get; }
public ICommand SetPassword2FromViewModelCommand { get; }

public FieldsViewModel()
{
SetPassword1FromViewModelCommand = new AnotherCommandImplementation(_ => Password1 = "Set from ViewModel!");
SetPassword2FromViewModelCommand = new AnotherCommandImplementation(_ => Password2 = "Set from ViewModel!");

_originalAutoSuggestBox1Suggestions = new List<string>()
{
"Burger", "Fries", "Shake", "Lettuce"
};

_originalAutoSuggestBox2Suggestions = new List<KeyValuePair<string, Color>>(GetColors());

AutoSuggestBox1Suggestions = new ObservableCollection<string>(_originalAutoSuggestBox1Suggestions);
}

private static bool IsMatch(string item, string currentText)
{
#if NET6_0_OR_GREATER
return item.Contains(currentText, StringComparison.OrdinalIgnoreCase);
#else
return item.IndexOf(currentText, StringComparison.OrdinalIgnoreCase) >= 0;
#endif
}

private static IEnumerable<KeyValuePair<string, Color>> GetColors()
{
return typeof(Colors)
.GetProperties()
.Where(prop =>
typeof(Color).IsAssignableFrom(prop.PropertyType))
.Select(prop =>
new KeyValuePair<string, Color>(prop.Name, (Color)prop.GetValue(null)!));
}
}

Expand Down
123 changes: 123 additions & 0 deletions MainDemo.Wpf/Fields.xaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<UserControl x:Class="MaterialDesignDemo.Fields"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:MaterialDesignDemo.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:domain="clr-namespace:MaterialDesignDemo.Domain"
xmlns:domain1="clr-namespace:MaterialDesignDemo.Domain"
Expand All @@ -14,6 +15,8 @@
mc:Ignorable="d">

<UserControl.Resources>
<converters:ColorToBrushConverter x:Key="ColorToBrushConverter" />

<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource MaterialDesignTextBox}">
<Setter Property="Margin" Value="0,8" />
<Setter Property="VerticalAlignment" Value="Center" />
Expand Down Expand Up @@ -757,5 +760,125 @@
</smtx:XamlDisplay>
</StackPanel>
</Grid>

<Grid Margin="0,48,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="0,0,0,10"
VerticalAlignment="Center"
Style="{StaticResource MaterialDesignHeadline5TextBlock}"
Text="AutoSuggestBox" />
<TextBlock Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center"
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
Text="Simple source list" />

<smtx:XamlDisplay Grid.Row="2"
Grid.Column="0"
UniqueKey="fields_autosuggestion_1">
<materialDesign:AutoSuggestBox VerticalAlignment="Bottom"
Suggestions="{Binding AutoSuggestBox1Suggestions}"
Text="{Binding AutoSuggestBox1Text, UpdateSourceTrigger=PropertyChanged}" />
</smtx:XamlDisplay>

<TextBlock Grid.Row="1"
Grid.Column="1"
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
Text="AutoSuggestBox with ItemTemplate" />
<smtx:XamlDisplay Grid.Row="2"
Grid.Column="1"
UniqueKey="fields_autosuggestion_2">
<materialDesign:AutoSuggestBox materialDesign:HintAssist.HelperText="Select color"
materialDesign:HintAssist.Hint="Color"
materialDesign:TextFieldAssist.HasClearButton="True"
DropDownElevation="Dp0"
Suggestions="{Binding AutoSuggestBox2Suggestions}"
Text="{Binding AutoSuggestBox2Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
ValueMember="Key">
<materialDesign:AutoSuggestBox.ItemTemplate>
<DataTemplate>
<DockPanel>
<Border Width="20"
Height="20"
Background="{Binding Value, Converter={StaticResource ColorToBrushConverter}}"
CornerRadius="10" />
<TextBlock Margin="10,0,0,0" Text="{Binding Key}" />
</DockPanel>
</DataTemplate>
</materialDesign:AutoSuggestBox.ItemTemplate>
</materialDesign:AutoSuggestBox>
</smtx:XamlDisplay>

<TextBlock Grid.Row="1"
Grid.Column="2"
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
Text="Filled AutoSuggestBox" />
<smtx:XamlDisplay Grid.Row="2"
Grid.Column="2"
UniqueKey="fields_autosuggestion_3">
<materialDesign:AutoSuggestBox materialDesign:HintAssist.Hint="Color"
materialDesign:TextFieldAssist.HasClearButton="True"
DropDownElevation="Dp0"
Style="{StaticResource MaterialDesignFilledAutoSuggestBox}"
Suggestions="{Binding AutoSuggestBox2Suggestions}"
Text="{Binding AutoSuggestBox2Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
ValueMember="Key">
<materialDesign:AutoSuggestBox.ItemTemplate>
<DataTemplate>
<DockPanel>
<Border Width="20"
Height="20"
Background="{Binding Value, Converter={StaticResource ColorToBrushConverter}}"
CornerRadius="10" />
<TextBlock Margin="10,0,0,0" Text="{Binding Key}" />
</DockPanel>
</DataTemplate>
</materialDesign:AutoSuggestBox.ItemTemplate>
</materialDesign:AutoSuggestBox>
</smtx:XamlDisplay>

<TextBlock Grid.Row="1"
Grid.Column="2"
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
Text="Outlined AutoSuggestBox" />
<smtx:XamlDisplay Grid.Row="2"
Grid.Column="2"
UniqueKey="fields_autosuggestion_4">
<materialDesign:AutoSuggestBox materialDesign:HintAssist.Hint="Color"
materialDesign:TextFieldAssist.HasClearButton="True"
DropDownElevation="Dp0"
Style="{StaticResource MaterialDesignOutlinedAutoSuggestBox}"
Suggestions="{Binding AutoSuggestBox2Suggestions}"
Text="{Binding AutoSuggestBox2Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
ValueMember="Key">
<materialDesign:AutoSuggestBox.ItemTemplate>
<DataTemplate>
<DockPanel>
<Border Width="20"
Height="20"
Background="{Binding Value, Converter={StaticResource ColorToBrushConverter}}"
CornerRadius="10" />
<TextBlock Margin="10,0,0,0" Text="{Binding Key}" />
</DockPanel>
</DataTemplate>
</materialDesign:AutoSuggestBox.ItemTemplate>
</materialDesign:AutoSuggestBox>
</smtx:XamlDisplay>
</Grid>
</StackPanel>
</UserControl>
2 changes: 1 addition & 1 deletion MainDemo.Wpf/Fields.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Windows.Navigation;
using System.Windows.Navigation;
using MaterialDesignDemo.Domain;

namespace MaterialDesignDemo;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<UserControl x:Class="MaterialDesignThemes.UITests.Samples.AutoSuggestBoxes.AutoSuggestTextBoxWithCollectionView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MaterialDesignThemes.UITests.Samples.AutoSuggestBoxes"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type={x:Type local:AutoSuggestTextBoxWithCollectionViewViewModel}}"
d:DesignHeight="450" d:DesignWidth="800">
<!-- TODO: Selction Similar to SelectedItem="{Binding Suggestions/}" perhaps needing IsSynchronizedWithCurrentItem="True" -->
<StackPanel>
<materialDesign:AutoSuggestBox
materialDesign:HintAssist.HelperText="Name"
materialDesign:TextFieldAssist.HasClearButton="True"
Text="{Binding AutoSuggestText, UpdateSourceTrigger=PropertyChanged}"
Suggestions="{Binding Suggestions}">
</materialDesign:AutoSuggestBox>
<!--
<ComboBox ItemsSource="{Binding Suggestions}"
Margin="0,10"
IsSynchronizedWithCurrentItem="True"/>
<ListBox ItemsSource="{Binding Suggestions}"
IsSynchronizedWithCurrentItem="True"/>
-->

</StackPanel>
</UserControl>
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using CommunityToolkit.Mvvm.ComponentModel;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Data;

namespace MaterialDesignThemes.UITests.Samples.AutoSuggestBoxes;

/// <summary>
/// Interaction logic for AutoSuggestTextBoxWithCollectionView.xaml
/// </summary>
public partial class AutoSuggestTextBoxWithCollectionView
{
public AutoSuggestTextBoxWithCollectionView()
{
DataContext = new AutoSuggestTextBoxWithCollectionViewViewModel();
InitializeComponent();
}
}

public partial class AutoSuggestTextBoxWithCollectionViewViewModel : ObservableObject
{
private ObservableCollection<string> BaseSuggestions { get; }

public ICollectionView Suggestions { get; }

[ObservableProperty]
private string? _autoSuggestText;

partial void OnAutoSuggestTextChanged(string? oldValue, string? newValue)
{
if (!string.IsNullOrWhiteSpace(newValue))
{
Suggestions.Filter = x => IsMatch((string)x, newValue);
}
else
{
Suggestions.Filter = null;
}
base.OnPropertyChanged(nameof(Suggestions));
}

public AutoSuggestTextBoxWithCollectionViewViewModel()
{
BaseSuggestions = new()
{
"Apples",
"Bananas",
"Beans",
"Mtn Dew",
"Orange",
};
Suggestions = CollectionViewSource.GetDefaultView(BaseSuggestions);
}

private static bool IsMatch(string item, string currentText)
{
#if NET6_0_OR_GREATER
return item.Contains(currentText, StringComparison.OrdinalIgnoreCase);
#else
return item.IndexOf(currentText, StringComparison.OrdinalIgnoreCase) >= 0;
#endif
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<UserControl x:Class="MaterialDesignThemes.UITests.Samples.AutoSuggestTextBoxes.AutoSuggestTextBoxWithTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MaterialDesignThemes.UITests.Samples.AutoSuggestTextBoxes"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
d:DataContext="{d:DesignInstance Type=local:AutoSuggestTextBoxWithTemplateViewModel}"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<!-- TODO SELECTED ITEM -->
<materialDesign:AutoSuggestBox
materialDesign:HintAssist.HelperText="Name"
materialDesign:TextFieldAssist.HasClearButton="True"
Text="{Binding AutoSuggestText, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Suggestions="{Binding Suggestions}"
ValueMember="Name"
DisplayMember="Name">
</materialDesign:AutoSuggestBox>
</UserControl>
Loading
Loading