Skip to content

Commit 6310490

Browse files
authored
Implementing a character counter when MaxLength is set (#2242)
* Implementing a character counter when MaxLength is set This replaces #1607 * Fixing broken UI tests
1 parent 376347d commit 6310490

File tree

4 files changed

+98
-11
lines changed

4 files changed

+98
-11
lines changed

MainDemo.Wpf/Fields.xaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<UserControl
1+
<UserControl
22
x:Class="MaterialDesignDemo.Fields"
33
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
44
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -99,6 +99,7 @@
9999
Grid.Column="1">
100100
<TextBox
101101
x:Name="PhoneTextBox"
102+
MaxLength="12"
102103
materialDesign:TransitionAssist.DisableTransitions="True"/>
103104
</smtx:XamlDisplay>
104105

MaterialDesignThemes.UITests/WPF/TextBox/TextBoxTests.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,5 +198,45 @@ public async Task OnOutlinedTextBox_FloatingHintOffsetWithinRange()
198198

199199
recorder.Success();
200200
}
201+
202+
[Fact]
203+
public async Task CharacterCount_WithMaxLengthSet_IsDisplayed()
204+
{
205+
await using var recorder = new TestRecorder(App);
206+
207+
IVisualElement grid = await LoadXaml(@"
208+
<Grid Margin=""30"">
209+
<TextBox
210+
MaxLength=""10""
211+
/>
212+
</Grid>");
213+
IVisualElement textBox = await grid.GetElement("/TextBox");
214+
IVisualElement characterCounter = await textBox.GetElement("CharacterCounterTextBlock");
215+
216+
Assert.Equal("0 / 10", await characterCounter.GetText());
217+
218+
await textBox.SetText("12345");
219+
220+
Assert.Equal("5 / 10", await characterCounter.GetText());
221+
222+
recorder.Success();
223+
}
224+
225+
[Fact]
226+
public async Task CharacterCount_WithoutMaxLengthSet_IsCollapsed()
227+
{
228+
await using var recorder = new TestRecorder(App);
229+
230+
IVisualElement grid = await LoadXaml(@"
231+
<Grid Margin=""30"">
232+
<TextBox />
233+
</Grid>");
234+
IVisualElement textBox = await grid.GetElement("/TextBox");
235+
IVisualElement characterCounter = await textBox.GetElement("CharacterCounterTextBlock");
236+
237+
Assert.Equal(Visibility.Collapsed, await characterCounter.GetVisibility());
238+
239+
recorder.Success();
240+
}
201241
}
202242
}

MaterialDesignThemes.Wpf/TextFieldAssist.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,13 @@ public static void SetTrailingIconSize(DependencyObject element, double value)
252252
public static double GetTrailingIconSize(DependencyObject element)
253253
=> (double)element.GetValue(TrailingIconSizeProperty);
254254

255+
public static Style GetCharacterCounterStyle(DependencyObject obj) => (Style)obj.GetValue(CharacterCounterStyleProperty);
256+
257+
public static void SetCharacterCounterStyle(DependencyObject obj, Style value) => obj.SetValue(CharacterCounterStyleProperty, value);
258+
259+
public static readonly DependencyProperty CharacterCounterStyleProperty =
260+
DependencyProperty.RegisterAttached("CharacterCounterStyle", typeof(Style), typeof(TextFieldAssist), new PropertyMetadata(null));
261+
255262
#region Methods
256263

257264
private static void IncludeSpellingSuggestionsChanged(DependencyObject element, DependencyPropertyChangedEventArgs e)

MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@
1414
<converters:MathConverter x:Key="MathMultiplyConverter" Operation="Multiply" />
1515
<converters:FloatingHintOffsetCalculationConverter x:Key="FloatingHintOffsetCalculationConverter" />
1616

17+
<Style x:Key="MaterialDesignCharacterCounterTextBlock" TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
18+
<Setter Property="FontSize" Value="10" />
19+
<Setter Property="VerticalAlignment" Value="Center" />
20+
<Setter Property="Opacity" Value="0.56" />
21+
<Setter Property="Margin" Value="0,0,16,0" />
22+
<Setter Property="Text">
23+
<Setter.Value>
24+
<MultiBinding StringFormat="{}{0} / {1}">
25+
<Binding Path="Text.Length" RelativeSource="{RelativeSource FindAncestor, AncestorType=TextBoxBase}" />
26+
<Binding Path="MaxLength" RelativeSource="{RelativeSource FindAncestor, AncestorType=TextBoxBase}" />
27+
</MultiBinding>
28+
</Setter.Value>
29+
</Setter>
30+
</Style>
31+
1732
<Style x:Key="MaterialDesignTextBoxBase" TargetType="{x:Type TextBoxBase}">
1833
<Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}"/>
1934
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDesignTextBoxBorder}" />
@@ -35,6 +50,7 @@
3550
<Setter Property="Cursor" Value="IBeam"/>
3651
<Setter Property="KeyboardNavigation.TabNavigation" Value="Local"/>
3752
<Setter Property="wpf:TextFieldAssist.IncludeSpellingSuggestions" Value="{Binding RelativeSource={RelativeSource Self}, Path=(SpellCheck.IsEnabled)}" />
53+
<Setter Property="wpf:TextFieldAssist.CharacterCounterStyle" Value="{StaticResource MaterialDesignCharacterCounterTextBlock}" />
3854
<Setter Property="Template">
3955
<Setter.Value>
4056
<ControlTemplate TargetType="{x:Type TextBoxBase}">
@@ -108,7 +124,7 @@
108124

109125
<Grid
110126
Grid.Column="1"
111-
x:Name="grid"
127+
x:Name="grid"
112128
MinWidth="1">
113129
<Grid
114130
Grid.Column="0">
@@ -221,14 +237,24 @@
221237
CornerRadius="{TemplateBinding wpf:TextFieldAssist.UnderlineCornerRadius}"
222238
Background="{TemplateBinding wpf:TextFieldAssist.UnderlineBrush}" />
223239
<Canvas
224-
x:Name="HelperTextWrapper"
225240
VerticalAlignment="Bottom">
226-
<TextBlock
227-
Canvas.Top="2"
228-
FontSize="{TemplateBinding wpf:HintAssist.HelperTextFontSize}"
229-
MaxWidth="{Binding ActualWidth, ElementName=border}"
230-
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
231-
Text="{TemplateBinding wpf:HintAssist.HelperText}" />
241+
<Grid Canvas.Top="2"
242+
x:Name="FooterGrid"
243+
Width="{Binding ActualWidth, ElementName=border}">
244+
<Grid.ColumnDefinitions>
245+
<ColumnDefinition />
246+
<ColumnDefinition Width="Auto"/>
247+
</Grid.ColumnDefinitions>
248+
<TextBlock
249+
x:Name="HelperTextTextBlock"
250+
FontSize="{TemplateBinding wpf:HintAssist.HelperTextFontSize}"
251+
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
252+
Text="{TemplateBinding wpf:HintAssist.HelperText}" />
253+
254+
<TextBlock
255+
Grid.Column="1"
256+
x:Name="CharacterCounterTextBlock" />
257+
</Grid>
232258
</Canvas>
233259
</Grid>
234260
<ControlTemplate.Triggers>
@@ -268,7 +294,7 @@
268294
<Setter Property="Padding" Value="16 8 12 8" />
269295
<Setter Property="Background" Value="{DynamicResource MaterialDesignTextFieldBoxBackground}" />
270296
<Setter Property="wpf:TextFieldAssist.TextBoxViewMargin" Value="{x:Static wpf:Constants.DefaultTextBoxViewMarginEmbedded}" />
271-
<Setter TargetName="HelperTextWrapper" Property="Margin" Value="16 0 0 0" />
297+
<Setter TargetName="HelperTextTextBlock" Property="Margin" Value="16 0 0 0" />
272298
</Trigger>
273299
<Trigger Property="wpf:TextFieldAssist.HasOutlinedTextField" Value="True">
274300
<Setter Property="VerticalContentAlignment" Value="Top" />
@@ -290,7 +316,7 @@
290316
</MultiBinding>
291317
</Setter.Value>
292318
</Setter>
293-
<Setter TargetName="HelperTextWrapper" Property="Margin" Value="16 0 0 0" />
319+
<Setter TargetName="HelperTextTextBlock" Property="Margin" Value="16 0 0 0" />
294320
</Trigger>
295321
<MultiTrigger>
296322
<MultiTrigger.Conditions>
@@ -309,6 +335,18 @@
309335
</MultiTrigger.Conditions>
310336
<Setter TargetName="HintWrapper" Property="Opacity" Value="1" />
311337
</MultiTrigger>
338+
<DataTrigger Value="0">
339+
<DataTrigger.Binding>
340+
<PriorityBinding>
341+
<Binding Path="MaxLength" RelativeSource="{RelativeSource Self}" FallbackValue="0" />
342+
<Binding Source="0" />
343+
</PriorityBinding>
344+
</DataTrigger.Binding>
345+
<Setter Property="Visibility" Value="Collapsed" TargetName="CharacterCounterTextBlock"/>
346+
</DataTrigger>
347+
<Trigger Property="Visibility" Value="Visible" SourceName="CharacterCounterTextBlock">
348+
<Setter Property="Style" Value="{Binding Path=(wpf:TextFieldAssist.CharacterCounterStyle), RelativeSource={RelativeSource TemplatedParent}}" TargetName="CharacterCounterTextBlock"/>
349+
</Trigger>
312350

313351
<!-- IsEnabled -->
314352
<MultiTrigger>
@@ -429,6 +467,7 @@
429467
<Setter TargetName="border" Property="Margin" Value="-1" />
430468
<Setter Property="BorderThickness" Value="2" />
431469
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDesignValidationErrorBrush}" />
470+
<Setter Property="Margin" Value="0,0,1,0" TargetName="FooterGrid" />
432471
</MultiTrigger>
433472
</ControlTemplate.Triggers>
434473
</ControlTemplate>

0 commit comments

Comments
 (0)