committed by
GitHub
22 changed files with 786 additions and 21 deletions
@ -0,0 +1,10 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Avalonia.Metadata |
||||
|
{ |
||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] |
||||
|
public class TrimSurroundingWhitespaceAttribute : Attribute |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Avalonia.Metadata |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Indicates that a collection type should be processed as being whitespace significant by a XAML processor.
|
||||
|
/// </summary>
|
||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] |
||||
|
public class WhitespaceSignificantCollectionAttribute : Attribute |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using Avalonia.Media; |
||||
|
|
||||
|
namespace Avalonia.Controls.Documents |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Bold element - markup helper for indicating bolded content.
|
||||
|
/// Equivalent to a Span with FontWeight property set to FontWeights.Bold.
|
||||
|
/// Can contain other inline elements.
|
||||
|
/// </summary>
|
||||
|
public sealed class Bold : Span |
||||
|
{ |
||||
|
static Bold() |
||||
|
{ |
||||
|
FontWeightProperty.OverrideDefaultValue<Bold>(FontWeight.Bold); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,71 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using Avalonia.Media; |
||||
|
using Avalonia.Media.TextFormatting; |
||||
|
using Avalonia.Utilities; |
||||
|
|
||||
|
namespace Avalonia.Controls.Documents |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Inline element.
|
||||
|
/// </summary>
|
||||
|
public abstract class Inline : TextElement |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// AvaloniaProperty for <see cref="TextDecorations" /> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly StyledProperty<TextDecorationCollection> TextDecorationsProperty = |
||||
|
AvaloniaProperty.Register<Inline, TextDecorationCollection>( |
||||
|
nameof(TextDecorations)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// AvaloniaProperty for <see cref="BaselineAlignment" /> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly StyledProperty<BaselineAlignment> BaselineAlignmentProperty = |
||||
|
AvaloniaProperty.Register<Inline, BaselineAlignment>( |
||||
|
nameof(BaselineAlignment), |
||||
|
BaselineAlignment.Baseline); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The TextDecorations property specifies decorations that are added to the text of an element.
|
||||
|
/// </summary>
|
||||
|
public TextDecorationCollection TextDecorations |
||||
|
{ |
||||
|
get { return GetValue(TextDecorationsProperty); } |
||||
|
set { SetValue(TextDecorationsProperty, value); } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Describes how the baseline for a text-based element is positioned on the vertical axis,
|
||||
|
/// relative to the established baseline for text.
|
||||
|
/// </summary>
|
||||
|
public BaselineAlignment BaselineAlignment |
||||
|
{ |
||||
|
get { return GetValue(BaselineAlignmentProperty); } |
||||
|
set { SetValue(BaselineAlignmentProperty, value); } |
||||
|
} |
||||
|
|
||||
|
internal abstract int BuildRun(StringBuilder stringBuilder, IList<ValueSpan<TextRunProperties>> textStyleOverrides, int firstCharacterIndex); |
||||
|
|
||||
|
internal abstract int AppendText(StringBuilder stringBuilder); |
||||
|
|
||||
|
protected TextRunProperties CreateTextRunProperties() |
||||
|
{ |
||||
|
return new GenericTextRunProperties(new Typeface(FontFamily, FontStyle, FontWeight), FontSize, |
||||
|
TextDecorations, Foreground, Background, BaselineAlignment); |
||||
|
} |
||||
|
|
||||
|
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change) |
||||
|
{ |
||||
|
base.OnPropertyChanged(change); |
||||
|
|
||||
|
switch (change.Property.Name) |
||||
|
{ |
||||
|
case nameof(TextDecorations): |
||||
|
case nameof(BaselineAlignment): |
||||
|
Invalidate(); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,123 @@ |
|||||
|
using System; |
||||
|
using System.Text; |
||||
|
using Avalonia.Collections; |
||||
|
using Avalonia.LogicalTree; |
||||
|
using Avalonia.Metadata; |
||||
|
|
||||
|
namespace Avalonia.Controls.Documents |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A collection of <see cref="Inline"/>s.
|
||||
|
/// </summary>
|
||||
|
[WhitespaceSignificantCollection] |
||||
|
public class InlineCollection : AvaloniaList<Inline> |
||||
|
{ |
||||
|
private string? _text = string.Empty; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="InlineCollection"/> class.
|
||||
|
/// </summary>
|
||||
|
public InlineCollection(ILogical parent) : base(0) |
||||
|
{ |
||||
|
ResetBehavior = ResetBehavior.Remove; |
||||
|
|
||||
|
this.ForEachItem( |
||||
|
x => |
||||
|
{ |
||||
|
((ISetLogicalParent)x).SetParent(parent); |
||||
|
x.Invalidated += Invalidate; |
||||
|
Invalidate(); |
||||
|
}, |
||||
|
x => |
||||
|
{ |
||||
|
((ISetLogicalParent)x).SetParent(null); |
||||
|
x.Invalidated -= Invalidate; |
||||
|
Invalidate(); |
||||
|
}, |
||||
|
() => throw new NotSupportedException()); |
||||
|
} |
||||
|
|
||||
|
public bool HasComplexContent => Count > 0; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or adds the text held by the inlines collection.
|
||||
|
/// <remarks>
|
||||
|
/// Can be null for complex content.
|
||||
|
/// </remarks>
|
||||
|
/// </summary>
|
||||
|
public string? Text |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
if (!HasComplexContent) |
||||
|
{ |
||||
|
return _text; |
||||
|
} |
||||
|
|
||||
|
var builder = new StringBuilder(); |
||||
|
|
||||
|
foreach(var inline in this) |
||||
|
{ |
||||
|
inline.AppendText(builder); |
||||
|
} |
||||
|
|
||||
|
return builder.ToString(); |
||||
|
} |
||||
|
set |
||||
|
{ |
||||
|
if (HasComplexContent) |
||||
|
{ |
||||
|
Add(new Run(value)); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
_text = value; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Add a text segment to the collection.
|
||||
|
/// <remarks>
|
||||
|
/// For non complex content this appends the text to the end of currently held text.
|
||||
|
/// For complex content this adds a <see cref="Run"/> to the collection.
|
||||
|
/// </remarks>
|
||||
|
/// </summary>
|
||||
|
/// <param name="text"></param>
|
||||
|
public void Add(string text) |
||||
|
{ |
||||
|
if (HasComplexContent) |
||||
|
{ |
||||
|
Add(new Run(text)); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
_text += text; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override void Add(Inline item) |
||||
|
{ |
||||
|
if (!HasComplexContent) |
||||
|
{ |
||||
|
base.Add(new Run(_text)); |
||||
|
|
||||
|
_text = string.Empty; |
||||
|
} |
||||
|
|
||||
|
base.Add(item); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Raised when an inline in the collection changes.
|
||||
|
/// </summary>
|
||||
|
public event EventHandler? Invalidated; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Raises the <see cref="Invalidated"/> event.
|
||||
|
/// </summary>
|
||||
|
protected void Invalidate() => Invalidated?.Invoke(this, EventArgs.Empty); |
||||
|
|
||||
|
private void Invalidate(object? sender, EventArgs e) => Invalidate(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using Avalonia.Media; |
||||
|
|
||||
|
namespace Avalonia.Controls.Documents |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Italic element - markup helper for indicating italicized content.
|
||||
|
/// Equivalent to a Span with FontStyle property set to FontStyles.Italic.
|
||||
|
/// Can contain other inline elements.
|
||||
|
/// </summary>
|
||||
|
public sealed class Italic : Span |
||||
|
{ |
||||
|
static Italic() |
||||
|
{ |
||||
|
FontStyleProperty.OverrideDefaultValue<Italic>(FontStyle.Italic); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using Avalonia.Media.TextFormatting; |
||||
|
using Avalonia.Metadata; |
||||
|
using Avalonia.Utilities; |
||||
|
|
||||
|
namespace Avalonia.Controls.Documents |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// LineBreak element that forces a line breaking.
|
||||
|
/// </summary>
|
||||
|
[TrimSurroundingWhitespace] |
||||
|
public class LineBreak : Inline |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Creates a new LineBreak instance.
|
||||
|
/// </summary>
|
||||
|
public LineBreak() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
internal override int BuildRun(StringBuilder stringBuilder, |
||||
|
IList<ValueSpan<TextRunProperties>> textStyleOverrides, int firstCharacterIndex) |
||||
|
{ |
||||
|
var length = AppendText(stringBuilder); |
||||
|
|
||||
|
textStyleOverrides.Add(new ValueSpan<TextRunProperties>(firstCharacterIndex, length, |
||||
|
CreateTextRunProperties())); |
||||
|
|
||||
|
return length; |
||||
|
} |
||||
|
|
||||
|
internal override int AppendText(StringBuilder stringBuilder) |
||||
|
{ |
||||
|
var text = Environment.NewLine; |
||||
|
|
||||
|
stringBuilder.Append(text); |
||||
|
|
||||
|
return text.Length; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,86 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using Avalonia.Data; |
||||
|
using Avalonia.Media.TextFormatting; |
||||
|
using Avalonia.Metadata; |
||||
|
using Avalonia.Utilities; |
||||
|
|
||||
|
namespace Avalonia.Controls.Documents |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A terminal element in text flow hierarchy - contains a uniformatted run of unicode characters
|
||||
|
/// </summary>
|
||||
|
public class Run : Inline |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes an instance of Run class.
|
||||
|
/// </summary>
|
||||
|
public Run() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes an instance of Run class specifying its text content.
|
||||
|
/// </summary>
|
||||
|
/// <param name="text">
|
||||
|
/// Text content assigned to the Run.
|
||||
|
/// </param>
|
||||
|
public Run(string? text) |
||||
|
{ |
||||
|
Text = text; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Dependency property backing Text.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// Note that when a TextRange that intersects with this Run gets modified (e.g. by editing
|
||||
|
/// a selection in RichTextBox), we will get two changes to this property since we delete
|
||||
|
/// and then insert when setting the content of a TextRange.
|
||||
|
/// </remarks>
|
||||
|
public static readonly StyledProperty<string?> TextProperty = AvaloniaProperty.Register<Run, string?> ( |
||||
|
nameof (Text), defaultBindingMode: BindingMode.TwoWay); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The content spanned by this TextElement.
|
||||
|
/// </summary>
|
||||
|
[Content] |
||||
|
public string? Text { |
||||
|
get { return GetValue (TextProperty); } |
||||
|
set { SetValue (TextProperty, value); } |
||||
|
} |
||||
|
|
||||
|
internal override int BuildRun(StringBuilder stringBuilder, |
||||
|
IList<ValueSpan<TextRunProperties>> textStyleOverrides, int firstCharacterIndex) |
||||
|
{ |
||||
|
var length = AppendText(stringBuilder); |
||||
|
|
||||
|
textStyleOverrides.Add(new ValueSpan<TextRunProperties>(firstCharacterIndex, length, |
||||
|
CreateTextRunProperties())); |
||||
|
|
||||
|
return length; |
||||
|
} |
||||
|
|
||||
|
internal override int AppendText(StringBuilder stringBuilder) |
||||
|
{ |
||||
|
var text = Text ?? ""; |
||||
|
|
||||
|
stringBuilder.Append(text); |
||||
|
|
||||
|
return text.Length; |
||||
|
} |
||||
|
|
||||
|
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change) |
||||
|
{ |
||||
|
base.OnPropertyChanged(change); |
||||
|
|
||||
|
switch (change.Property.Name) |
||||
|
{ |
||||
|
case nameof(Text): |
||||
|
Invalidate(); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,95 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using Avalonia.Media.TextFormatting; |
||||
|
using Avalonia.Metadata; |
||||
|
using Avalonia.Utilities; |
||||
|
|
||||
|
namespace Avalonia.Controls.Documents |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Span element used for grouping other Inline elements.
|
||||
|
/// </summary>
|
||||
|
public class Span : Inline |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="Inlines"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly DirectProperty<Span, InlineCollection> InlinesProperty = |
||||
|
AvaloniaProperty.RegisterDirect<Span, InlineCollection>( |
||||
|
nameof(Inlines), |
||||
|
o => o.Inlines); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of a Span element.
|
||||
|
/// </summary>
|
||||
|
public Span() |
||||
|
{ |
||||
|
Inlines = new InlineCollection(this); |
||||
|
|
||||
|
Inlines.Invalidated += (s, e) => Invalidate(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the inlines.
|
||||
|
/// </summary>
|
||||
|
[Content] |
||||
|
public InlineCollection Inlines { get; } |
||||
|
|
||||
|
internal override int BuildRun(StringBuilder stringBuilder, IList<ValueSpan<TextRunProperties>> textStyleOverrides, int firstCharacterIndex) |
||||
|
{ |
||||
|
var length = 0; |
||||
|
|
||||
|
if (Inlines.HasComplexContent) |
||||
|
{ |
||||
|
foreach (var inline in Inlines) |
||||
|
{ |
||||
|
var inlineLength = inline.BuildRun(stringBuilder, textStyleOverrides, firstCharacterIndex); |
||||
|
|
||||
|
firstCharacterIndex += inlineLength; |
||||
|
|
||||
|
length += inlineLength; |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (Inlines.Text == null) |
||||
|
{ |
||||
|
return length; |
||||
|
} |
||||
|
|
||||
|
stringBuilder.Append(Inlines.Text); |
||||
|
|
||||
|
length = Inlines.Text.Length; |
||||
|
|
||||
|
textStyleOverrides.Add(new ValueSpan<TextRunProperties>(firstCharacterIndex, length, |
||||
|
CreateTextRunProperties())); |
||||
|
} |
||||
|
|
||||
|
return length; |
||||
|
} |
||||
|
|
||||
|
internal override int AppendText(StringBuilder stringBuilder) |
||||
|
{ |
||||
|
if (Inlines.HasComplexContent) |
||||
|
{ |
||||
|
var length = 0; |
||||
|
|
||||
|
foreach (var inline in Inlines) |
||||
|
{ |
||||
|
length += inline.AppendText(stringBuilder); |
||||
|
} |
||||
|
|
||||
|
return length; |
||||
|
} |
||||
|
|
||||
|
if (Inlines.Text == null) |
||||
|
{ |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
stringBuilder.Append(Inlines.Text); |
||||
|
|
||||
|
return Inlines.Text.Length; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,129 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Media; |
||||
|
|
||||
|
namespace Avalonia.Controls.Documents |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// TextElement is an base class for content in text based controls.
|
||||
|
/// TextElements span other content, applying property values or providing structural information.
|
||||
|
/// </summary>
|
||||
|
public abstract class TextElement : StyledElement |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="Background"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly StyledProperty<IBrush?> BackgroundProperty = |
||||
|
AvaloniaProperty.Register<TextElement, IBrush?>(nameof(Background), inherits: true); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="FontFamily"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<FontFamily> FontFamilyProperty = |
||||
|
TextBlock.FontFamilyProperty.AddOwner<TextElement>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="FontSize"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<double> FontSizeProperty = |
||||
|
TextBlock.FontSizeProperty.AddOwner<TextElement>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="FontStyle"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<FontStyle> FontStyleProperty = |
||||
|
TextBlock.FontStyleProperty.AddOwner<TextElement>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="FontWeight"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<FontWeight> FontWeightProperty = |
||||
|
TextBlock.FontWeightProperty.AddOwner<TextElement>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="Foreground"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<IBrush?> ForegroundProperty = |
||||
|
TextBlock.ForegroundProperty.AddOwner<TextElement>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets a brush used to paint the control's background.
|
||||
|
/// </summary>
|
||||
|
public IBrush? Background |
||||
|
{ |
||||
|
get { return GetValue(BackgroundProperty); } |
||||
|
set { SetValue(BackgroundProperty, value); } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the font family.
|
||||
|
/// </summary>
|
||||
|
public FontFamily FontFamily |
||||
|
{ |
||||
|
get { return GetValue(FontFamilyProperty); } |
||||
|
set { SetValue(FontFamilyProperty, value); } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the font size.
|
||||
|
/// </summary>
|
||||
|
public double FontSize |
||||
|
{ |
||||
|
get { return GetValue(FontSizeProperty); } |
||||
|
set { SetValue(FontSizeProperty, value); } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the font style.
|
||||
|
/// </summary>
|
||||
|
public FontStyle FontStyle |
||||
|
{ |
||||
|
get { return GetValue(FontStyleProperty); } |
||||
|
set { SetValue(FontStyleProperty, value); } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the font weight.
|
||||
|
/// </summary>
|
||||
|
public FontWeight FontWeight |
||||
|
{ |
||||
|
get { return GetValue(FontWeightProperty); } |
||||
|
set { SetValue(FontWeightProperty, value); } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets a brush used to paint the text.
|
||||
|
/// </summary>
|
||||
|
public IBrush? Foreground |
||||
|
{ |
||||
|
get { return GetValue(ForegroundProperty); } |
||||
|
set { SetValue(ForegroundProperty, value); } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Raised when the visual representation of the text element changes.
|
||||
|
/// </summary>
|
||||
|
public event EventHandler? Invalidated; |
||||
|
|
||||
|
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change) |
||||
|
{ |
||||
|
base.OnPropertyChanged(change); |
||||
|
|
||||
|
switch (change.Property.Name) |
||||
|
{ |
||||
|
case nameof(Background): |
||||
|
case nameof(FontFamily): |
||||
|
case nameof(FontSize): |
||||
|
case nameof(FontStyle): |
||||
|
case nameof(FontWeight): |
||||
|
case nameof(Foreground): |
||||
|
Invalidate(); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Raises the <see cref="Invalidate"/> event.
|
||||
|
/// </summary>
|
||||
|
protected void Invalidate() => Invalidated?.Invoke(this, EventArgs.Empty); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
namespace Avalonia.Controls.Documents |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Underline element - markup helper for indicating superscript content.
|
||||
|
/// Equivalent to a Span with TextDecorations property set to TextDecorations.Underlined.
|
||||
|
/// Can contain other inline elements.
|
||||
|
/// </summary>
|
||||
|
public sealed class Underline : Span |
||||
|
{ |
||||
|
static Underline() |
||||
|
{ |
||||
|
TextDecorationsProperty.OverrideDefaultValue<Underline>(Media.TextDecorations.Underline); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue