Browse Source

Make some TextBox/Block properties direct.

pull/494/merge
Steven Kirk 11 years ago
parent
commit
a91d21d0a4
  1. 20
      src/Perspex.Base/DirectProperty.cs
  2. 11
      src/Perspex.Base/PerspexProperty.cs
  3. 8
      src/Perspex.Base/PerspexProperty`1.cs
  4. 2
      src/Perspex.Base/StyledPropertyBase.cs
  5. 69
      src/Perspex.Controls/Presenters/TextPresenter.cs
  6. 19
      src/Perspex.Controls/TextBlock.cs
  7. 81
      src/Perspex.Controls/TextBox.cs

20
src/Perspex.Base/DirectProperty.cs

@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Perspex.Data;
namespace Perspex
{
@ -44,11 +45,13 @@ namespace Perspex
/// <param name="source">The property to copy.</param>
/// <param name="getter">Gets the current value of the property.</param>
/// <param name="setter">Sets the value of the property. May be null.</param>
/// <param name="metadata">Optional overridden metadata.</param>
private DirectProperty(
PerspexProperty<TValue> source,
Func<TOwner, TValue> getter,
Action<TOwner, TValue> setter)
: base(source, typeof(TOwner))
Action<TOwner, TValue> setter,
PropertyMetadata metadata)
: base(source, typeof(TOwner), metadata)
{
Contract.Requires<ArgumentNullException>(getter != null);
@ -76,16 +79,25 @@ namespace Perspex
/// Registers the direct property on another type.
/// </summary>
/// <typeparam name="TNewOwner">The type of the additional owner.</typeparam>
/// <param name="getter">Gets the current value of the property.</param>
/// <param name="setter">Sets the value of the property.</param>
/// <param name="unsetValue">
/// The value to use when the property is set to <see cref="PerspexProperty.UnsetValue"/>
/// </param>
/// <param name="defaultBindingMode">The default binding mode for the property.</param>
/// <returns>The property.</returns>
public DirectProperty<TNewOwner, TValue> AddOwner<TNewOwner>(
Func<TNewOwner, TValue> getter,
Action<TNewOwner, TValue> setter = null)
Action<TNewOwner, TValue> setter = null,
TValue unsetValue = default(TValue),
BindingMode defaultBindingMode = BindingMode.OneWay)
where TNewOwner : PerspexObject
{
var result = new DirectProperty<TNewOwner, TValue>(
this,
getter,
setter);
setter,
new DirectPropertyMetadata<TValue>(unsetValue, defaultBindingMode));
PerspexPropertyRegistry.Instance.Register(typeof(TNewOwner), result);
return result;

11
src/Perspex.Base/PerspexProperty.cs

@ -71,7 +71,11 @@ namespace Perspex
/// </summary>
/// <param name="source">The direct property to copy.</param>
/// <param name="ownerType">The new owner type.</param>
protected PerspexProperty(PerspexProperty source, Type ownerType)
/// <param name="metadata">Optional overridden metadata.</param>
protected PerspexProperty(
PerspexProperty source,
Type ownerType,
PropertyMetadata metadata)
{
Contract.Requires<ArgumentNullException>(source != null);
Contract.Requires<ArgumentNullException>(ownerType != null);
@ -86,6 +90,11 @@ namespace Perspex
Notifying = source.Notifying;
Id = source.Id;
_defaultMetadata = source._defaultMetadata;
if (metadata != null)
{
_metadata.Add(ownerType, metadata);
}
}
/// <summary>

8
src/Perspex.Base/PerspexProperty`1.cs

@ -32,8 +32,12 @@ namespace Perspex
/// </summary>
/// <param name="source">The property to copy.</param>
/// <param name="ownerType">The new owner type.</param>
protected PerspexProperty(PerspexProperty source, Type ownerType)
: base(source, ownerType)
/// <param name="metadata">Optional overridden metadata.</param>
protected PerspexProperty(
PerspexProperty source,
Type ownerType,
PropertyMetadata metadata)
: base(source, ownerType, metadata)
{
}
}

2
src/Perspex.Base/StyledPropertyBase.cs

@ -46,7 +46,7 @@ namespace Perspex
/// <param name="source">The property to add the owner to.</param>
/// <param name="ownerType">The type of the class that registers the property.</param>
protected StyledPropertyBase(StyledPropertyBase<TValue> source, Type ownerType)
: base(source, ownerType)
: base(source, ownerType, null)
{
_inherits = source.Inherits;
}

69
src/Perspex.Controls/Presenters/TextPresenter.cs

@ -12,24 +12,28 @@ namespace Perspex.Controls.Presenters
{
public class TextPresenter : TextBlock
{
public static readonly StyledProperty<int> CaretIndexProperty =
TextBox.CaretIndexProperty.AddOwner<TextPresenter>();
public static readonly DirectProperty<TextPresenter, int> CaretIndexProperty =
TextBox.CaretIndexProperty.AddOwner<TextPresenter>(
o => o.CaretIndex,
(o, v) => o.CaretIndex = v);
public static readonly StyledProperty<int> SelectionStartProperty =
TextBox.SelectionStartProperty.AddOwner<TextPresenter>();
public static readonly DirectProperty<TextPresenter, int> SelectionStartProperty =
TextBox.SelectionStartProperty.AddOwner<TextPresenter>(
o => o.SelectionStart,
(o, v) => o.SelectionStart = v);
public static readonly StyledProperty<int> SelectionEndProperty =
TextBox.SelectionEndProperty.AddOwner<TextPresenter>();
public static readonly DirectProperty<TextPresenter, int> SelectionEndProperty =
TextBox.SelectionEndProperty.AddOwner<TextPresenter>(
o => o.SelectionEnd,
(o, v) => o.SelectionEnd = v);
private readonly DispatcherTimer _caretTimer;
private int _caretIndex;
private int _selectionStart;
private int _selectionEnd;
private bool _caretBlink;
private IBrush _highlightBrush;
static TextPresenter()
{
CaretIndexProperty.OverrideValidation<TextPresenter>((o, v) => v);
}
public TextPresenter()
{
_caretTimer = new DispatcherTimer();
@ -47,20 +51,44 @@ namespace Perspex.Controls.Presenters
public int CaretIndex
{
get { return GetValue(CaretIndexProperty); }
set { SetValue(CaretIndexProperty, value); }
get
{
return _caretIndex;
}
set
{
value = CoerceCaretIndex(value);
SetAndRaise(CaretIndexProperty, ref _caretIndex, value);
}
}
public int SelectionStart
{
get { return GetValue(SelectionStartProperty); }
set { SetValue(SelectionStartProperty, value); }
get
{
return _selectionStart;
}
set
{
value = CoerceCaretIndex(value);
SetAndRaise(SelectionStartProperty, ref _selectionStart, value);
}
}
public int SelectionEnd
{
get { return GetValue(SelectionEndProperty); }
set { SetValue(SelectionEndProperty, value); }
get
{
return _selectionEnd;
}
set
{
value = CoerceCaretIndex(value);
SetAndRaise(SelectionEndProperty, ref _selectionEnd, value);
}
}
public int GetCaretIndex(Point point)
@ -206,6 +234,13 @@ namespace Perspex.Controls.Presenters
}
}
private int CoerceCaretIndex(int value)
{
var text = Text;
var length = text?.Length ?? 0;
return Math.Max(0, Math.Min(length, value));
}
private void CaretTimerTick(object sender, EventArgs e)
{
_caretBlink = !_caretBlink;

19
src/Perspex.Controls/TextBlock.cs

@ -72,8 +72,11 @@ namespace Perspex.Controls
/// <summary>
/// Defines the <see cref="Text"/> property.
/// </summary>
public static readonly StyledProperty<string> TextProperty =
PerspexProperty.Register<TextBlock, string>(nameof(Text));
public static readonly DirectProperty<TextBlock, string> TextProperty =
PerspexProperty.RegisterDirect<TextBlock, string>(
nameof(Text),
o => o.Text,
(o, v) => o.Text = v);
/// <summary>
/// Defines the <see cref="TextAlignment"/> property.
@ -87,14 +90,8 @@ namespace Perspex.Controls
public static readonly StyledProperty<TextWrapping> TextWrappingProperty =
PerspexProperty.Register<TextBlock, TextWrapping>(nameof(TextWrapping));
/// <summary>
/// The formatted text used for rendering.
/// </summary>
private string _text;
private FormattedText _formattedText;
/// <summary>
/// Stores the last constraint passed to MeasureOverride.
/// </summary>
private Size _constraint;
/// <summary>
@ -140,8 +137,8 @@ namespace Perspex.Controls
[Content]
public string Text
{
get { return GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
get { return _text; }
set { SetAndRaise(TextProperty, ref _text, value); }
}
/// <summary>

81
src/Perspex.Controls/TextBox.cs

@ -29,18 +29,29 @@ namespace Perspex.Controls
public static readonly DirectProperty<TextBox, bool> CanScrollHorizontallyProperty =
PerspexProperty.RegisterDirect<TextBox, bool>("CanScrollHorizontally", o => o.CanScrollHorizontally);
// TODO: Should CaretIndex, SelectionStart/End and Text be direct properties?
public static readonly StyledProperty<int> CaretIndexProperty =
PerspexProperty.Register<TextBox, int>("CaretIndex", validate: ValidateCaretIndex);
public static readonly StyledProperty<int> SelectionStartProperty =
PerspexProperty.Register<TextBox, int>("SelectionStart", validate: ValidateCaretIndex);
public static readonly StyledProperty<int> SelectionEndProperty =
PerspexProperty.Register<TextBox, int>("SelectionEnd", validate: ValidateCaretIndex);
public static readonly StyledProperty<string> TextProperty =
TextBlock.TextProperty.AddOwner<TextBox>();
public static readonly DirectProperty<TextBox, int> CaretIndexProperty =
PerspexProperty.RegisterDirect<TextBox, int>(
nameof(CaretIndex),
o => o.CaretIndex,
(o, v) => o.CaretIndex = v);
public static readonly DirectProperty<TextBox, int> SelectionStartProperty =
PerspexProperty.RegisterDirect<TextBox, int>(
nameof(SelectionStart),
o => o.SelectionStart,
(o, v) => o.SelectionStart = v);
public static readonly DirectProperty<TextBox, int> SelectionEndProperty =
PerspexProperty.RegisterDirect<TextBox, int>(
nameof(SelectionEnd),
o => o.SelectionEnd,
(o, v) => o.SelectionEnd = v);
public static readonly DirectProperty<TextBox, string> TextProperty =
TextBlock.TextProperty.AddOwner<TextBox>(
o => o.Text,
(o, v) => o.Text = v,
defaultBindingMode: BindingMode.TwoWay);
public static readonly StyledProperty<TextAlignment> TextAlignmentProperty =
TextBlock.TextAlignmentProperty.AddOwner<TextBox>();
@ -71,6 +82,10 @@ namespace Perspex.Controls
public bool Equals(UndoRedoState other) => ReferenceEquals(Text, other.Text) || Equals(Text, other.Text);
}
private string _text;
private int _caretIndex;
private int _selectionStart;
private int _selectionEnd;
private bool _canScrollHorizontally;
private TextPresenter _presenter;
private UndoRedoHelper<UndoRedoState> _undoRedoHelper;
@ -78,7 +93,6 @@ namespace Perspex.Controls
static TextBox()
{
FocusableProperty.OverrideDefaultValue(typeof(TextBox), true);
TextProperty.OverrideMetadata<TextBox>(new StyledPropertyMetadata<string>(defaultBindingMode: BindingMode.TwoWay));
}
public TextBox()
@ -117,10 +131,15 @@ namespace Perspex.Controls
public int CaretIndex
{
get { return GetValue(CaretIndexProperty); }
get
{
return _caretIndex;
}
set
{
SetValue(CaretIndexProperty, value);
value = CoerceCaretIndex(value);
SetAndRaise(CaretIndexProperty, ref _caretIndex, value);
if (_undoRedoHelper.IsLastState && _undoRedoHelper.LastState.Text == Text)
_undoRedoHelper.UpdateLastState();
}
@ -128,21 +147,37 @@ namespace Perspex.Controls
public int SelectionStart
{
get { return GetValue(SelectionStartProperty); }
set { SetValue(SelectionStartProperty, value); }
get
{
return _selectionStart;
}
set
{
value = CoerceCaretIndex(value);
SetAndRaise(SelectionStartProperty, ref _selectionStart, value);
}
}
public int SelectionEnd
{
get { return GetValue(SelectionEndProperty); }
set { SetValue(SelectionEndProperty, value); }
get
{
return _selectionEnd;
}
set
{
value = CoerceCaretIndex(value);
SetAndRaise(SelectionEndProperty, ref _selectionEnd, value);
}
}
[Content]
public string Text
{
get { return GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
get { return _text; }
set { SetAndRaise(TextProperty, ref _text, value); }
}
public TextAlignment TextAlignment
@ -426,9 +461,9 @@ namespace Perspex.Controls
}
}
private static int ValidateCaretIndex(PerspexObject o, int value)
private int CoerceCaretIndex(int value)
{
var text = o.GetValue(TextProperty);
var text = Text;
var length = text?.Length ?? 0;
return Math.Max(0, Math.Min(length, value));
}

Loading…
Cancel
Save