Browse Source

Merge pull request #1544 from AvaloniaUI/feature/password-box

PasswordChar support for TextBox
pull/1329/merge
Steven Kirk 8 years ago
committed by GitHub
parent
commit
ffbc42d6eb
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      samples/ControlCatalog/Pages/TextBoxPage.xaml
  2. 29
      src/Avalonia.Controls/Presenters/TextPresenter.cs
  3. 17
      src/Avalonia.Controls/Primitives/AccessText.cs
  4. 7
      src/Avalonia.Controls/TextBlock.cs
  5. 35
      src/Avalonia.Controls/TextBox.cs
  6. 7
      src/Avalonia.Themes.Default/TextBox.xaml

10
samples/ControlCatalog/Pages/TextBoxPage.xaml

@ -10,10 +10,16 @@
<StackPanel Orientation="Vertical" Gap="8">
<TextBox Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit." Width="200" />
<TextBox Width="200" Watermark="Watermark" />
<TextBox Width="200"
Watermark="Floating Watermark"
<TextBox Width="200"
Watermark="Floating Watermark"
UseFloatingWatermark="True"
Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."/>
<TextBox Width="200"
Watermark="Password Box"
UseFloatingWatermark="True"
PasswordChar="*"
Text="Password" />
<TextBox Width="200" Text="Left aligned text" TextAlignment="Left" />
<TextBox Width="200" Text="Center aligned text" TextAlignment="Center" />
<TextBox Width="200" Text="Right aligned text" TextAlignment="Right" />

29
src/Avalonia.Controls/Presenters/TextPresenter.cs

@ -17,6 +17,9 @@ namespace Avalonia.Controls.Presenters
o => o.CaretIndex,
(o, v) => o.CaretIndex = v);
public static readonly StyledProperty<char> PasswordCharProperty =
AvaloniaProperty.Register<TextPresenter, char>(nameof(PasswordChar));
public static readonly DirectProperty<TextPresenter, int> SelectionStartProperty =
TextBox.SelectionStartProperty.AddOwner<TextPresenter>(
o => o.SelectionStart,
@ -63,6 +66,12 @@ namespace Avalonia.Controls.Presenters
}
}
public char PasswordChar
{
get => GetValue(PasswordCharProperty);
set => SetValue(PasswordCharProperty, value);
}
public int SelectionStart
{
get
@ -202,9 +211,25 @@ namespace Avalonia.Controls.Presenters
}
}
protected override FormattedText CreateFormattedText(Size constraint)
/// <summary>
/// Creates the <see cref="FormattedText"/> used to render the text.
/// </summary>
/// <param name="constraint">The constraint of the text.</param>
/// <param name="text">The text to generated the <see cref="FormattedText"/> for.</param>
/// <returns>A <see cref="FormattedText"/> object.</returns>
protected override FormattedText CreateFormattedText(Size constraint, string text)
{
var result = base.CreateFormattedText(constraint);
FormattedText result = null;
if (PasswordChar != default(char))
{
result = base.CreateFormattedText(constraint, new string(PasswordChar, Text.Length));
}
else
{
result = base.CreateFormattedText(constraint, Text);
}
var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;
var start = Math.Min(selectionStart, selectionEnd);

17
src/Avalonia.Controls/Primitives/AccessText.cs

@ -78,21 +78,10 @@ namespace Avalonia.Controls.Primitives
}
}
/// <summary>
/// Creates the <see cref="FormattedText"/> used to render the text.
/// </summary>
/// <param name="constraint">The constraint of the text.</param>
/// <returns>A <see cref="FormattedText"/> object.</returns>
protected override FormattedText CreateFormattedText(Size constraint)
/// <inheritdoc/>
protected override FormattedText CreateFormattedText(Size constraint, string text)
{
return new FormattedText
{
Constraint = constraint,
Typeface = new Typeface(FontFamily, FontSize, FontStyle, FontWeight),
Text = StripAccessKey(Text),
TextAlignment = TextAlignment,
Wrapping = TextWrapping,
};
return base.CreateFormattedText(constraint, StripAccessKey(text));
}
/// <summary>

7
src/Avalonia.Controls/TextBlock.cs

@ -197,7 +197,7 @@ namespace Avalonia.Controls
{
if (_formattedText == null)
{
_formattedText = CreateFormattedText(_constraint);
_formattedText = CreateFormattedText(_constraint, Text);
}
return _formattedText;
@ -348,14 +348,15 @@ namespace Avalonia.Controls
/// Creates the <see cref="FormattedText"/> used to render the text.
/// </summary>
/// <param name="constraint">The constraint of the text.</param>
/// <param name="text">The text to format.</param>
/// <returns>A <see cref="FormattedText"/> object.</returns>
protected virtual FormattedText CreateFormattedText(Size constraint)
protected virtual FormattedText CreateFormattedText(Size constraint, string text)
{
return new FormattedText
{
Constraint = constraint,
Typeface = new Typeface(FontFamily, FontSize, FontStyle, FontWeight),
Text = Text ?? string.Empty,
Text = text ?? string.Empty,
TextAlignment = TextAlignment,
Wrapping = TextWrapping,
};

35
src/Avalonia.Controls/TextBox.cs

@ -30,10 +30,13 @@ namespace Avalonia.Controls
nameof(CaretIndex),
o => o.CaretIndex,
(o, v) => o.CaretIndex = v);
public static readonly StyledProperty<bool> IsReadOnlyProperty =
AvaloniaProperty.Register<TextBox, bool>(nameof(IsReadOnly));
public static readonly StyledProperty<char> PasswordCharProperty =
AvaloniaProperty.Register<TextBox, char>(nameof(PasswordChar));
public static readonly DirectProperty<TextBox, int> SelectionStartProperty =
AvaloniaProperty.RegisterDirect<TextBox, int>(
nameof(SelectionStart),
@ -87,7 +90,7 @@ namespace Avalonia.Controls
private UndoRedoHelper<UndoRedoState> _undoRedoHelper;
private bool _isUndoingRedoing;
private bool _ignoreTextChanges;
private static readonly string[] invalidCharacters = new String[1]{"\u007f"};
private static readonly string[] invalidCharacters = new String[1] { "\u007f" };
static TextBox()
{
@ -116,7 +119,7 @@ namespace Avalonia.Controls
ScrollViewer.HorizontalScrollBarVisibilityProperty,
horizontalScrollBarVisibility,
BindingPriority.Style);
_undoRedoHelper = new UndoRedoHelper<UndoRedoState>(this);
_undoRedoHelper = new UndoRedoHelper<UndoRedoState>(this);
}
public bool AcceptsReturn
@ -147,13 +150,19 @@ namespace Avalonia.Controls
_undoRedoHelper.UpdateLastState();
}
}
public bool IsReadOnly
{
get { return GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
public char PasswordChar
{
get => GetValue(PasswordCharProperty);
set => SetValue(PasswordCharProperty, value);
}
public int SelectionStart
{
get
@ -237,7 +246,7 @@ namespace Avalonia.Controls
_presenter = e.NameScope.Get<TextPresenter>("PART_TextPresenter");
_presenter.Cursor = new Cursor(StandardCursorType.Ibeam);
if(IsFocused)
if (IsFocused)
{
_presenter.ShowCaret();
}
@ -349,7 +358,10 @@ namespace Avalonia.Controls
case Key.C:
if (modifiers == InputModifiers.Control)
{
Copy();
if (!IsPasswordBox)
{
Copy();
}
handled = true;
}
break;
@ -357,8 +369,11 @@ namespace Avalonia.Controls
case Key.X:
if (modifiers == InputModifiers.Control)
{
Copy();
DeleteSelection();
if (!IsPasswordBox)
{
Copy();
DeleteSelection();
}
handled = true;
}
break;
@ -578,7 +593,7 @@ namespace Avalonia.Controls
DataValidationErrors.SetError(this, status.Error);
}
}
private int CoerceCaretIndex(int value) => CoerceCaretIndex(value, Text?.Length ?? 0);
private int CoerceCaretIndex(int value, int length)
@ -856,6 +871,8 @@ namespace Avalonia.Controls
SelectionEnd = CaretIndex;
}
private bool IsPasswordBox => PasswordChar != default(char);
UndoRedoState UndoRedoHelper<UndoRedoState>.IUndoRedoHost.UndoRedoState
{
get { return new UndoRedoState(Text, CaretIndex); }

7
src/Avalonia.Themes.Default/TextBox.xaml

@ -11,7 +11,7 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<DockPanel Margin="{TemplateBinding Padding}">
<TextBlock Name="floatingWatermark"
Foreground="{DynamicResource ThemeAccentBrush}"
FontSize="{DynamicResource FontSizeSmall}"
@ -31,7 +31,7 @@
<DataValidationErrors>
<ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
<Panel>
<TextBlock Name="watermark"
Opacity="0.5"
@ -43,7 +43,8 @@
SelectionStart="{TemplateBinding SelectionStart}"
SelectionEnd="{TemplateBinding SelectionEnd}"
TextAlignment="{TemplateBinding TextAlignment}"
TextWrapping="{TemplateBinding TextWrapping}"/>
TextWrapping="{TemplateBinding TextWrapping}"
PasswordChar="{TemplateBinding PasswordChar}"/>
</Panel>
</ScrollViewer>
</DataValidationErrors>

Loading…
Cancel
Save