Skip to content

Commit d8bca15

Browse files
committed
Refactor FieldsViewModel and enhance AutoSuggestBox
Refactored `FieldsViewModel` to use `CommunityToolkit.Mvvm` attributes, reducing boilerplate code and improving maintainability. Added `AutoSuggestBox3` with dynamic filtering, interactive item templates, and a command to remove suggestions. Enhanced `AutoSuggestBox` behavior to support interactive elements like buttons without closing the popup. Updated `Fields.xaml` to include new `AutoSuggestBox` variations and bindings. Introduced a new `AutoSuggestTextBoxWithInteractiveTemplate` sample to demonstrate interactive item templates. Added tests to validate interactive `AutoSuggestBox` behavior. Performed general cleanup and modernization, including concise syntax and collection initializers.
1 parent e5d0c3d commit d8bca15

File tree

7 files changed

+341
-121
lines changed

7 files changed

+341
-121
lines changed
Lines changed: 72 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,35 @@
11
using System.Collections.ObjectModel;
22
using System.Windows.Media;
3+
using CommunityToolkit.Mvvm.ComponentModel;
4+
using CommunityToolkit.Mvvm.Input;
35
using MaterialDesignDemo.Shared.Domain;
46

57
namespace MaterialDesignDemo.Domain;
6-
public class FieldsViewModel : ViewModelBase
8+
public partial class FieldsViewModel : ObservableObject
79
{
8-
private string? _name;
9-
private string? _name2;
10-
private string? _password1 = string.Empty;
11-
private string? _password2 = "pre-filled";
1210
private string? _password1Validated = "pre-filled";
1311
private string? _password2Validated = "pre-filled";
14-
private string? _text1;
15-
private string? _text2;
16-
private ObservableCollection<string>? _autoSuggestBox1Suggestions;
17-
private string? _autoSuggestBox1Text;
1812
private readonly List<string>? _originalAutoSuggestBox1Suggestions;
19-
private ObservableCollection<KeyValuePair<string, Color>>? _autoSuggestBox2Suggestions;
20-
private string? _autoSuggestBox2Text;
2113
private readonly List<KeyValuePair<string, Color>>? _originalAutoSuggestBox2Suggestions;
14+
private readonly List<string> _originalAutoSuggestBox3Suggestions;
2215

23-
public string? Name
24-
{
25-
get => _name;
26-
set => SetProperty(ref _name, value);
27-
}
16+
[ObservableProperty]
17+
private string? _name;
2818

29-
public string? Name2
30-
{
31-
get => _name2;
32-
set => SetProperty(ref _name2, value);
33-
}
19+
[ObservableProperty]
20+
private string? _name2;
3421

35-
public string? Text1
36-
{
37-
get => _text1;
38-
set => SetProperty(ref _text1, value);
39-
}
22+
[ObservableProperty]
23+
private string? _text1;
4024

41-
public string? Text2
42-
{
43-
get => _text2;
44-
set => SetProperty(ref _text2, value);
45-
}
25+
[ObservableProperty]
26+
private string? _text2;
4627

47-
public string? Password1
48-
{
49-
get => _password1;
50-
set => SetProperty(ref _password1, value);
51-
}
28+
[ObservableProperty]
29+
private string? _password1 = string.Empty;
5230

53-
public string? Password2
54-
{
55-
get => _password2;
56-
set => SetProperty(ref _password2, value);
57-
}
31+
[ObservableProperty]
32+
private string? _password2 = "pre-filled";
5833

5934
public string? Password1Validated
6035
{
@@ -80,43 +55,64 @@ public string? Password2Validated
8055

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

83-
public ObservableCollection<string>? AutoSuggestBox1Suggestions
58+
[ObservableProperty]
59+
private ObservableCollection<string>? _autoSuggestBox1Suggestions;
60+
61+
[ObservableProperty]
62+
private ObservableCollection<KeyValuePair<string, Color>>? _autoSuggestBox2Suggestions;
63+
64+
[ObservableProperty]
65+
private List<string> _autoSuggestBox3Suggestions;
66+
67+
68+
[ObservableProperty]
69+
private string? _autoSuggestBox1Text;
70+
71+
partial void OnAutoSuggestBox1TextChanged(string? value)
8472
{
85-
get => _autoSuggestBox1Suggestions;
86-
set => SetProperty(ref _autoSuggestBox1Suggestions, value);
73+
if (_originalAutoSuggestBox1Suggestions != null && value != null)
74+
{
75+
var searchResult = _originalAutoSuggestBox1Suggestions.Where(x => IsMatch(x, value));
76+
AutoSuggestBox1Suggestions = new(searchResult);
77+
}
8778
}
8879

89-
public ObservableCollection<KeyValuePair<string, Color>>? AutoSuggestBox2Suggestions
80+
[ObservableProperty]
81+
private string? _autoSuggestBox2Text;
82+
83+
partial void OnAutoSuggestBox2TextChanged(string? value)
9084
{
91-
get => _autoSuggestBox2Suggestions;
92-
set => SetProperty(ref _autoSuggestBox2Suggestions, value);
85+
if (_originalAutoSuggestBox2Suggestions != null && value != null)
86+
{
87+
var searchResult = _originalAutoSuggestBox2Suggestions.Where(x => IsMatch(x.Key, value));
88+
AutoSuggestBox2Suggestions = new(searchResult);
89+
}
9390
}
9491

95-
public string? AutoSuggestBox1Text
92+
[ObservableProperty]
93+
private string? _autoSuggestBox3Text;
94+
95+
partial void OnAutoSuggestBox3TextChanged(string? value)
9696
{
97-
get => _autoSuggestBox1Text;
98-
set
97+
if (value is not null)
9998
{
100-
if (SetProperty(ref _autoSuggestBox1Text, value) &&
101-
_originalAutoSuggestBox1Suggestions != null && value != null)
102-
{
103-
var searchResult = _originalAutoSuggestBox1Suggestions.Where(x => IsMatch(x, value));
104-
AutoSuggestBox1Suggestions = new ObservableCollection<string>(searchResult);
105-
}
99+
var searchResult = _originalAutoSuggestBox3Suggestions.Where(x => IsMatch(x, value));
100+
AutoSuggestBox3Suggestions = new(searchResult);
106101
}
107102
}
108103

109-
public string? AutoSuggestBox2Text
104+
[RelayCommand]
105+
private void RemoveAutoSuggestBox3Suggestion(string suggestion)
110106
{
111-
get => _autoSuggestBox2Text;
112-
set
107+
_originalAutoSuggestBox3Suggestions.Remove(suggestion);
108+
if (string.IsNullOrEmpty(AutoSuggestBox3Text))
109+
{
110+
AutoSuggestBox3Suggestions = new(_originalAutoSuggestBox3Suggestions);
111+
}
112+
else
113113
{
114-
if (SetProperty(ref _autoSuggestBox2Text, value) &&
115-
_originalAutoSuggestBox2Suggestions != null && value != null)
116-
{
117-
var searchResult = _originalAutoSuggestBox2Suggestions.Where(x => IsMatch(x.Key, value));
118-
AutoSuggestBox2Suggestions = new ObservableCollection<KeyValuePair<string, Color>>(searchResult);
119-
}
114+
var searchResult = _originalAutoSuggestBox3Suggestions.Where(x => IsMatch(x, AutoSuggestBox3Text!));
115+
AutoSuggestBox3Suggestions = new(searchResult);
120116
}
121117
}
122118

@@ -128,12 +124,16 @@ public FieldsViewModel()
128124
SetPassword1FromViewModelCommand = new AnotherCommandImplementation(_ => Password1 = "Set from ViewModel!");
129125
SetPassword2FromViewModelCommand = new AnotherCommandImplementation(_ => Password2 = "Set from ViewModel!");
130126

131-
_originalAutoSuggestBox1Suggestions = new List<string>()
132-
{
127+
_originalAutoSuggestBox1Suggestions =
128+
[
133129
"Burger", "Fries", "Shake", "Lettuce"
134-
};
130+
];
135131

136-
_originalAutoSuggestBox2Suggestions = new List<KeyValuePair<string, Color>>(GetColors());
132+
_originalAutoSuggestBox2Suggestions = new(GetColors());
133+
_originalAutoSuggestBox3Suggestions =
134+
[
135+
"jsmith", "jdoe", "mscott", "pparker", "bwilliams", "ljohnson", "abrown", "dlee", "cmiller", "tmoore"
136+
];
137137

138138
AutoSuggestBox1Suggestions = new ObservableCollection<string>(_originalAutoSuggestBox1Suggestions);
139139
}
@@ -158,20 +158,10 @@ private static IEnumerable<KeyValuePair<string, Color>> GetColors()
158158
}
159159
}
160160

161-
public class FieldsTestObject : ViewModelBase
161+
public partial class FieldsTestObject : ObservableObject
162162
{
163+
[ObservableProperty]
163164
private string? _name;
165+
[ObservableProperty]
164166
private string? _content;
165-
166-
public string? Name
167-
{
168-
get => _name;
169-
set => SetProperty(ref _name, value);
170-
}
171-
172-
public string? Content
173-
{
174-
get => _content;
175-
set => SetProperty(ref _content, value);
176-
}
177167
}

src/MainDemo.Wpf/Fields.xaml

Lines changed: 82 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -692,36 +692,36 @@
692692
<WrapPanel>
693693
<StackPanel Width="256" Margin="0,0,16,16">
694694
<TextBlock Margin="0,0,0,8"
695-
VerticalAlignment="Center"
696-
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
697-
Text="Simple source list" />
695+
VerticalAlignment="Center"
696+
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
697+
Text="Simple source list" />
698698

699699
<smtx:XamlDisplay UniqueKey="fields_autosuggestion_1">
700700
<materialDesign:AutoSuggestBox VerticalAlignment="Bottom"
701-
Suggestions="{Binding AutoSuggestBox1Suggestions}"
702-
Text="{Binding AutoSuggestBox1Text, UpdateSourceTrigger=PropertyChanged}" />
701+
Suggestions="{Binding AutoSuggestBox1Suggestions}"
702+
Text="{Binding AutoSuggestBox1Text, UpdateSourceTrigger=PropertyChanged}" />
703703
</smtx:XamlDisplay>
704704
</StackPanel>
705705

706706
<StackPanel Width="256" Margin="0,0,16,16">
707707
<TextBlock Margin="0,0,0,8"
708-
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
709-
Text="AutoSuggestBox with ItemTemplate" />
708+
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
709+
Text="AutoSuggestBox with ItemTemplate" />
710710
<smtx:XamlDisplay UniqueKey="fields_autosuggestion_2">
711711
<materialDesign:AutoSuggestBox materialDesign:HintAssist.HelperText="Select color"
712-
materialDesign:HintAssist.Hint="Color"
713-
materialDesign:TextFieldAssist.HasClearButton="True"
714-
DropDownElevation="Dp0"
715-
Suggestions="{Binding AutoSuggestBox2Suggestions}"
716-
Text="{Binding AutoSuggestBox2Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
717-
ValueMember="Key">
712+
materialDesign:HintAssist.Hint="Color"
713+
materialDesign:TextFieldAssist.HasClearButton="True"
714+
DropDownElevation="Dp0"
715+
Suggestions="{Binding AutoSuggestBox2Suggestions}"
716+
Text="{Binding AutoSuggestBox2Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
717+
ValueMember="Key">
718718
<materialDesign:AutoSuggestBox.ItemTemplate>
719719
<DataTemplate>
720720
<DockPanel>
721721
<Border Width="20"
722-
Height="20"
723-
Background="{Binding Value, Converter={StaticResource ColorToBrushConverter}}"
724-
CornerRadius="10" />
722+
Height="20"
723+
Background="{Binding Value, Converter={StaticResource ColorToBrushConverter}}"
724+
CornerRadius="10" />
725725
<TextBlock Margin="10,0,0,0" Text="{Binding Key}" />
726726
</DockPanel>
727727
</DataTemplate>
@@ -733,23 +733,23 @@
733733

734734
<StackPanel Width="256" Margin="0,0,16,16">
735735
<TextBlock Margin="0,0,0,8"
736-
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
737-
Text="Filled AutoSuggestBox" />
736+
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
737+
Text="Filled AutoSuggestBox" />
738738
<smtx:XamlDisplay UniqueKey="fields_autosuggestion_3">
739739
<materialDesign:AutoSuggestBox materialDesign:HintAssist.Hint="Color"
740-
materialDesign:TextFieldAssist.HasClearButton="True"
741-
DropDownElevation="Dp0"
742-
Style="{StaticResource MaterialDesignFilledAutoSuggestBox}"
743-
Suggestions="{Binding AutoSuggestBox2Suggestions}"
744-
Text="{Binding AutoSuggestBox2Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
745-
ValueMember="Key">
740+
materialDesign:TextFieldAssist.HasClearButton="True"
741+
DropDownElevation="Dp0"
742+
Style="{StaticResource MaterialDesignFilledAutoSuggestBox}"
743+
Suggestions="{Binding AutoSuggestBox2Suggestions}"
744+
Text="{Binding AutoSuggestBox2Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
745+
ValueMember="Key">
746746
<materialDesign:AutoSuggestBox.ItemTemplate>
747747
<DataTemplate>
748748
<DockPanel>
749749
<Border Width="20"
750-
Height="20"
751-
Background="{Binding Value, Converter={StaticResource ColorToBrushConverter}}"
752-
CornerRadius="10" />
750+
Height="20"
751+
Background="{Binding Value, Converter={StaticResource ColorToBrushConverter}}"
752+
CornerRadius="10" />
753753
<TextBlock Margin="10,0,0,0" Text="{Binding Key}" />
754754
</DockPanel>
755755
</DataTemplate>
@@ -760,30 +760,74 @@
760760

761761
<StackPanel Width="256" Margin="0,0,16,16">
762762
<TextBlock Margin="0,0,0,8"
763-
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
764-
Text="Outlined AutoSuggestBox" />
763+
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
764+
Text="Outlined AutoSuggestBox" />
765765
<smtx:XamlDisplay UniqueKey="fields_autosuggestion_4">
766766
<materialDesign:AutoSuggestBox materialDesign:HintAssist.Hint="Color"
767-
materialDesign:TextFieldAssist.HasClearButton="True"
768-
DropDownElevation="Dp0"
769-
Style="{StaticResource MaterialDesignOutlinedAutoSuggestBox}"
770-
Suggestions="{Binding AutoSuggestBox2Suggestions}"
771-
Text="{Binding AutoSuggestBox2Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
772-
ValueMember="Key">
767+
materialDesign:TextFieldAssist.HasClearButton="True"
768+
DropDownElevation="Dp0"
769+
Style="{StaticResource MaterialDesignOutlinedAutoSuggestBox}"
770+
Suggestions="{Binding AutoSuggestBox2Suggestions}"
771+
Text="{Binding AutoSuggestBox2Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
772+
ValueMember="Key">
773773
<materialDesign:AutoSuggestBox.ItemTemplate>
774774
<DataTemplate>
775775
<DockPanel>
776776
<Border Width="20"
777-
Height="20"
778-
Background="{Binding Value, Converter={StaticResource ColorToBrushConverter}}"
779-
CornerRadius="10" />
777+
Height="20"
778+
Background="{Binding Value, Converter={StaticResource ColorToBrushConverter}}"
779+
CornerRadius="10" />
780780
<TextBlock Margin="10,0,0,0" Text="{Binding Key}" />
781781
</DockPanel>
782782
</DataTemplate>
783783
</materialDesign:AutoSuggestBox.ItemTemplate>
784784
</materialDesign:AutoSuggestBox>
785785
</smtx:XamlDisplay>
786786
</StackPanel>
787+
788+
<StackPanel Width="512" Margin="0,0,16,16">
789+
<TextBlock Margin="0,0,0,8"
790+
Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
791+
Text="AutoSuggestBox with interactable content" />
792+
<smtx:XamlDisplay UniqueKey="fields_autosuggestion_5">
793+
<materialDesign:AutoSuggestBox materialDesign:HintAssist.Hint="Username"
794+
materialDesign:TextFieldAssist.HasLeadingIcon="True"
795+
materialDesign:TextFieldAssist.LeadingIcon="User"
796+
DropDownBackground="{DynamicResource MaterialDesign.Brush.ToolBar.Background}"
797+
DropDownElevation="Dp24"
798+
DropDownMaxHeight="500"
799+
Suggestions="{Binding AutoSuggestBox3Suggestions}"
800+
Text="{Binding AutoSuggestBox3Text, UpdateSourceTrigger=PropertyChanged}">
801+
<materialDesign:AutoSuggestBox.ItemTemplate>
802+
<DataTemplate>
803+
<Grid HorizontalAlignment="Stretch">
804+
<Grid.ColumnDefinitions>
805+
<ColumnDefinition Width="*" />
806+
<ColumnDefinition Width="auto" />
807+
</Grid.ColumnDefinitions>
808+
<TextBlock Grid.Column="0"
809+
VerticalAlignment="Center"
810+
Text="{Binding .}" />
811+
<Button Grid.Column="1"
812+
Padding="2,0,0,0"
813+
Command="{Binding DataContext.RemoveAutoSuggestBox3SuggestionCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
814+
CommandParameter="{Binding .}"
815+
Focusable="False"
816+
Style="{StaticResource MaterialDesignToolButton}">
817+
<materialDesign:PackIcon Width="16"
818+
Height="16"
819+
Margin="0"
820+
Kind="CloseCircle" />
821+
</Button>
822+
</Grid>
823+
</DataTemplate>
824+
</materialDesign:AutoSuggestBox.ItemTemplate>
825+
</materialDesign:AutoSuggestBox>
826+
</smtx:XamlDisplay>
827+
</StackPanel>
828+
829+
830+
787831
</WrapPanel>
788832
</StackPanel>
789833
</UserControl>

0 commit comments

Comments
 (0)