Skip to content

Commit

Permalink
Implementing a character counter when MaxLength is set (MaterialDesig…
Browse files Browse the repository at this point in the history
…nInXAML#2242)

* Implementing a character counter when MaxLength is set

This replaces MaterialDesignInXAML#1607

* Fixing broken UI tests
  • Loading branch information
Keboo committed Feb 13, 2021
1 parent 376347d commit 6310490
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 11 deletions.
3 changes: 2 additions & 1 deletion MainDemo.Wpf/Fields.xaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<UserControl
<UserControl
x:Class="MaterialDesignDemo.Fields"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Expand Down Expand Up @@ -99,6 +99,7 @@
Grid.Column="1">
<TextBox
x:Name="PhoneTextBox"
MaxLength="12"
materialDesign:TransitionAssist.DisableTransitions="True"/>
</smtx:XamlDisplay>

Expand Down
40 changes: 40 additions & 0 deletions MaterialDesignThemes.UITests/WPF/TextBox/TextBoxTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,5 +198,45 @@ public async Task OnOutlinedTextBox_FloatingHintOffsetWithinRange()

recorder.Success();
}

[Fact]
public async Task CharacterCount_WithMaxLengthSet_IsDisplayed()
{
await using var recorder = new TestRecorder(App);

IVisualElement grid = await LoadXaml(@"
<Grid Margin=""30"">
<TextBox
MaxLength=""10""
/>
</Grid>");
IVisualElement textBox = await grid.GetElement("/TextBox");
IVisualElement characterCounter = await textBox.GetElement("CharacterCounterTextBlock");

Assert.Equal("0 / 10", await characterCounter.GetText());

await textBox.SetText("12345");

Assert.Equal("5 / 10", await characterCounter.GetText());

recorder.Success();
}

[Fact]
public async Task CharacterCount_WithoutMaxLengthSet_IsCollapsed()
{
await using var recorder = new TestRecorder(App);

IVisualElement grid = await LoadXaml(@"
<Grid Margin=""30"">
<TextBox />
</Grid>");
IVisualElement textBox = await grid.GetElement("/TextBox");
IVisualElement characterCounter = await textBox.GetElement("CharacterCounterTextBlock");

Assert.Equal(Visibility.Collapsed, await characterCounter.GetVisibility());

recorder.Success();
}
}
}
7 changes: 7 additions & 0 deletions MaterialDesignThemes.Wpf/TextFieldAssist.cs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,13 @@ public static void SetTrailingIconSize(DependencyObject element, double value)
public static double GetTrailingIconSize(DependencyObject element)
=> (double)element.GetValue(TrailingIconSizeProperty);

public static Style GetCharacterCounterStyle(DependencyObject obj) => (Style)obj.GetValue(CharacterCounterStyleProperty);

public static void SetCharacterCounterStyle(DependencyObject obj, Style value) => obj.SetValue(CharacterCounterStyleProperty, value);

public static readonly DependencyProperty CharacterCounterStyleProperty =
DependencyProperty.RegisterAttached("CharacterCounterStyle", typeof(Style), typeof(TextFieldAssist), new PropertyMetadata(null));

#region Methods

private static void IncludeSpellingSuggestionsChanged(DependencyObject element, DependencyPropertyChangedEventArgs e)
Expand Down
59 changes: 49 additions & 10 deletions MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@
<converters:MathConverter x:Key="MathMultiplyConverter" Operation="Multiply" />
<converters:FloatingHintOffsetCalculationConverter x:Key="FloatingHintOffsetCalculationConverter" />

<Style x:Key="MaterialDesignCharacterCounterTextBlock" TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="FontSize" Value="10" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Opacity" Value="0.56" />
<Setter Property="Margin" Value="0,0,16,0" />
<Setter Property="Text">
<Setter.Value>
<MultiBinding StringFormat="{}{0} / {1}">
<Binding Path="Text.Length" RelativeSource="{RelativeSource FindAncestor, AncestorType=TextBoxBase}" />
<Binding Path="MaxLength" RelativeSource="{RelativeSource FindAncestor, AncestorType=TextBoxBase}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>

<Style x:Key="MaterialDesignTextBoxBase" TargetType="{x:Type TextBoxBase}">
<Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}"/>
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDesignTextBoxBorder}" />
Expand All @@ -35,6 +50,7 @@
<Setter Property="Cursor" Value="IBeam"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="Local"/>
<Setter Property="wpf:TextFieldAssist.IncludeSpellingSuggestions" Value="{Binding RelativeSource={RelativeSource Self}, Path=(SpellCheck.IsEnabled)}" />
<Setter Property="wpf:TextFieldAssist.CharacterCounterStyle" Value="{StaticResource MaterialDesignCharacterCounterTextBlock}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBoxBase}">
Expand Down Expand Up @@ -108,7 +124,7 @@

<Grid
Grid.Column="1"
x:Name="grid"
x:Name="grid"
MinWidth="1">
<Grid
Grid.Column="0">
Expand Down Expand Up @@ -221,14 +237,24 @@
CornerRadius="{TemplateBinding wpf:TextFieldAssist.UnderlineCornerRadius}"
Background="{TemplateBinding wpf:TextFieldAssist.UnderlineBrush}" />
<Canvas
x:Name="HelperTextWrapper"
VerticalAlignment="Bottom">
<TextBlock
Canvas.Top="2"
FontSize="{TemplateBinding wpf:HintAssist.HelperTextFontSize}"
MaxWidth="{Binding ActualWidth, ElementName=border}"
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
Text="{TemplateBinding wpf:HintAssist.HelperText}" />
<Grid Canvas.Top="2"
x:Name="FooterGrid"
Width="{Binding ActualWidth, ElementName=border}">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock
x:Name="HelperTextTextBlock"
FontSize="{TemplateBinding wpf:HintAssist.HelperTextFontSize}"
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
Text="{TemplateBinding wpf:HintAssist.HelperText}" />

<TextBlock
Grid.Column="1"
x:Name="CharacterCounterTextBlock" />
</Grid>
</Canvas>
</Grid>
<ControlTemplate.Triggers>
Expand Down Expand Up @@ -268,7 +294,7 @@
<Setter Property="Padding" Value="16 8 12 8" />
<Setter Property="Background" Value="{DynamicResource MaterialDesignTextFieldBoxBackground}" />
<Setter Property="wpf:TextFieldAssist.TextBoxViewMargin" Value="{x:Static wpf:Constants.DefaultTextBoxViewMarginEmbedded}" />
<Setter TargetName="HelperTextWrapper" Property="Margin" Value="16 0 0 0" />
<Setter TargetName="HelperTextTextBlock" Property="Margin" Value="16 0 0 0" />
</Trigger>
<Trigger Property="wpf:TextFieldAssist.HasOutlinedTextField" Value="True">
<Setter Property="VerticalContentAlignment" Value="Top" />
Expand All @@ -290,7 +316,7 @@
</MultiBinding>
</Setter.Value>
</Setter>
<Setter TargetName="HelperTextWrapper" Property="Margin" Value="16 0 0 0" />
<Setter TargetName="HelperTextTextBlock" Property="Margin" Value="16 0 0 0" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
Expand All @@ -309,6 +335,18 @@
</MultiTrigger.Conditions>
<Setter TargetName="HintWrapper" Property="Opacity" Value="1" />
</MultiTrigger>
<DataTrigger Value="0">
<DataTrigger.Binding>
<PriorityBinding>
<Binding Path="MaxLength" RelativeSource="{RelativeSource Self}" FallbackValue="0" />
<Binding Source="0" />
</PriorityBinding>
</DataTrigger.Binding>
<Setter Property="Visibility" Value="Collapsed" TargetName="CharacterCounterTextBlock"/>
</DataTrigger>
<Trigger Property="Visibility" Value="Visible" SourceName="CharacterCounterTextBlock">
<Setter Property="Style" Value="{Binding Path=(wpf:TextFieldAssist.CharacterCounterStyle), RelativeSource={RelativeSource TemplatedParent}}" TargetName="CharacterCounterTextBlock"/>
</Trigger>

<!-- IsEnabled -->
<MultiTrigger>
Expand Down Expand Up @@ -429,6 +467,7 @@
<Setter TargetName="border" Property="Margin" Value="-1" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDesignValidationErrorBrush}" />
<Setter Property="Margin" Value="0,0,1,0" TargetName="FooterGrid" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Expand Down

0 comments on commit 6310490

Please sign in to comment.