Browse Source

Use IAddChild for TextBlock and RichTextBlock

pull/8541/head
Benedikt Stebner 4 years ago
parent
commit
3ad71d4bea
  1. 9
      samples/Sandbox/MainWindow.axaml
  2. 4
      src/Avalonia.Base/Metadata/IAddChild.cs
  3. 34
      src/Avalonia.Controls/Documents/Inline.cs
  4. 60
      src/Avalonia.Controls/Documents/InlineCollection.cs
  5. 34
      src/Avalonia.Controls/Documents/Span.cs
  6. 12
      src/Avalonia.Controls/Documents/TextElement.cs
  7. 65
      src/Avalonia.Controls/RichTextBlock.cs
  8. 13
      src/Avalonia.Controls/TextBlock.cs
  9. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs
  10. 1
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

9
samples/Sandbox/MainWindow.axaml

@ -1,4 +1,13 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
x:Class="Sandbox.MainWindow">
<RichTextBlock Margin="10" TextWrapping="Wrap">
This <Span FontWeight="Bold">is</Span> a
<Span Background="Silver" Foreground="Maroon">TextBlock</Span>
with <Span TextDecorations="Underline">several</Span>
<Span FontStyle="Italic">Span</Span> elements,
<Span Foreground="Blue">
using a <Bold>variety</Bold> of <Italic>styles</Italic>
</Span>.
</RichTextBlock>
</Window>

4
src/Markup/Avalonia.Markup.Xaml/IAddChild.cs → src/Avalonia.Base/Metadata/IAddChild.cs

@ -1,11 +1,11 @@
namespace Avalonia.Markup.Xaml
namespace Avalonia.Metadata
{
public interface IAddChild
{
void AddChild(object child);
}
public interface IAddChild<T> : IAddChild
public interface IAddChild<T>
{
void AddChild(T child);
}

34
src/Avalonia.Controls/Documents/Inline.cs

@ -50,8 +50,38 @@ namespace Avalonia.Controls.Documents
protected TextRunProperties CreateTextRunProperties()
{
return new GenericTextRunProperties(new Typeface(FontFamily, FontStyle, FontWeight), FontSize,
TextDecorations, Foreground, Background, BaselineAlignment);
var textDecorations = TextDecorations;
var background = Background;
if(Parent is Inline inline)
{
if(textDecorations == null)
{
textDecorations = inline.TextDecorations;
}
if(background == null)
{
background = inline.Background;
}
}
var fontStyle = FontStyle;
if(Parent is Italic)
{
fontStyle = FontStyle.Italic;
}
var fontWeight = FontWeight;
if(Parent is Bold)
{
fontWeight = FontWeight.Bold;
}
return new GenericTextRunProperties(new Typeface(FontFamily, fontStyle, fontWeight), FontSize,
textDecorations, Foreground, background, BaselineAlignment);
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)

60
src/Avalonia.Controls/Documents/InlineCollection.cs

@ -14,7 +14,6 @@ namespace Avalonia.Controls.Documents
{
private ILogical? _parent;
private IInlineHost? _inlineHost;
private string? _text = string.Empty;
/// <summary>
/// Initializes a new instance of the <see cref="InlineCollection"/> class.
@ -22,7 +21,7 @@ namespace Avalonia.Controls.Documents
public InlineCollection()
{
ResetBehavior = ResetBehavior.Remove;
this.ForEachItem(
x =>
{
@ -36,16 +35,16 @@ namespace Avalonia.Controls.Documents
x.InlineHost = InlineHost;
Invalidate();
},
() => throw new NotSupportedException());
() => throw new NotSupportedException());
}
internal ILogical? Parent
internal ILogical? Parent
{
get => _parent;
set
{
_parent = value;
OnParentChanged(value);
}
}
@ -61,8 +60,6 @@ namespace Avalonia.Controls.Documents
}
}
public bool HasComplexContent => Count > 0;
/// <summary>
/// Gets or adds the text held by the inlines collection.
/// <remarks>
@ -73,11 +70,6 @@ namespace Avalonia.Controls.Documents
{
get
{
if (!HasComplexContent)
{
return _text;
}
var builder = new StringBuilder();
foreach (var inline in this)
@ -87,17 +79,7 @@ namespace Avalonia.Controls.Documents
return builder.ToString();
}
set
{
if (HasComplexContent)
{
Add(new Run(value));
}
else
{
_text = value;
}
}
}
/// <summary>
@ -110,36 +92,12 @@ namespace Avalonia.Controls.Documents
/// <param name="text"></param>
public void Add(string text)
{
if (HasComplexContent)
{
Add(new Run(text));
}
else
{
_text = text;
}
Add(new Run(text));
}
public void Add(IControl child)
{
var implicitRun = new InlineUIContainer(child);
Add(implicitRun);
}
public override void Add(Inline item)
{
if (!HasComplexContent)
{
if (!string.IsNullOrEmpty(_text))
{
base.Add(new Run(_text));
}
_text = null;
}
base.Add(item);
Add(new InlineUIContainer(child));
}
/// <summary>
@ -152,7 +110,7 @@ namespace Avalonia.Controls.Documents
/// </summary>
protected void Invalidate()
{
if(InlineHost != null)
if (InlineHost != null)
{
InlineHost.Invalidate();
}
@ -162,7 +120,7 @@ namespace Avalonia.Controls.Documents
private void OnParentChanged(ILogical? parent)
{
foreach(var child in this)
foreach (var child in this)
{
((ISetLogicalParent)child).SetParent(parent);
}

34
src/Avalonia.Controls/Documents/Span.cs

@ -38,41 +38,17 @@ namespace Avalonia.Controls.Documents
internal override void BuildTextRun(IList<TextRun> textRuns)
{
if (Inlines.HasComplexContent)
foreach (var inline in Inlines)
{
foreach (var inline in Inlines)
{
inline.BuildTextRun(textRuns);
}
}
else
{
if (Inlines.Text is string text)
{
var textRunProperties = CreateTextRunProperties();
var textCharacters = new TextCharacters(text.AsMemory(), textRunProperties);
textRuns.Add(textCharacters);
}
inline.BuildTextRun(textRuns);
}
}
internal override void AppendText(StringBuilder stringBuilder)
{
if (Inlines.HasComplexContent)
{
foreach (var inline in Inlines)
{
inline.AppendText(stringBuilder);
}
}
else
foreach (var inline in Inlines)
{
if (Inlines.Text is string text)
{
stringBuilder.Append(text);
}
inline.AppendText(stringBuilder);
}
}
@ -93,7 +69,7 @@ namespace Avalonia.Controls.Documents
{
base.OnInlineHostChanged(oldValue, newValue);
if(Inlines is not null)
if (Inlines is not null)
{
Inlines.InlineHost = newValue;
}

12
src/Avalonia.Controls/Documents/TextElement.cs

@ -18,7 +18,7 @@ namespace Avalonia.Controls.Documents
/// Defines the <see cref="FontFamily"/> property.
/// </summary>
public static readonly AttachedProperty<FontFamily> FontFamilyProperty =
AvaloniaProperty.RegisterAttached<TextElement, Control, FontFamily>(
AvaloniaProperty.RegisterAttached<TextElement, TextElement, FontFamily>(
nameof(FontFamily),
defaultValue: FontFamily.Default,
inherits: true);
@ -27,7 +27,7 @@ namespace Avalonia.Controls.Documents
/// Defines the <see cref="FontSize"/> property.
/// </summary>
public static readonly AttachedProperty<double> FontSizeProperty =
AvaloniaProperty.RegisterAttached<TextElement, Control, double>(
AvaloniaProperty.RegisterAttached<TextElement, TextElement, double>(
nameof(FontSize),
defaultValue: 12,
inherits: true);
@ -36,7 +36,7 @@ namespace Avalonia.Controls.Documents
/// Defines the <see cref="FontStyle"/> property.
/// </summary>
public static readonly AttachedProperty<FontStyle> FontStyleProperty =
AvaloniaProperty.RegisterAttached<TextElement, Control, FontStyle>(
AvaloniaProperty.RegisterAttached<TextElement, TextElement, FontStyle>(
nameof(FontStyle),
inherits: true);
@ -44,7 +44,7 @@ namespace Avalonia.Controls.Documents
/// Defines the <see cref="FontWeight"/> property.
/// </summary>
public static readonly AttachedProperty<FontWeight> FontWeightProperty =
AvaloniaProperty.RegisterAttached<TextElement, Control, FontWeight>(
AvaloniaProperty.RegisterAttached<TextElement, TextElement, FontWeight>(
nameof(FontWeight),
inherits: true,
defaultValue: FontWeight.Normal);
@ -53,7 +53,7 @@ namespace Avalonia.Controls.Documents
/// Defines the <see cref="FontStretch"/> property.
/// </summary>
public static readonly AttachedProperty<FontStretch> FontStretchProperty =
AvaloniaProperty.RegisterAttached<TextElement, Control, FontStretch>(
AvaloniaProperty.RegisterAttached<TextElement, TextElement, FontStretch>(
nameof(FontStretch),
inherits: true,
defaultValue: FontStretch.Normal);
@ -62,7 +62,7 @@ namespace Avalonia.Controls.Documents
/// Defines the <see cref="Foreground"/> property.
/// </summary>
public static readonly AttachedProperty<IBrush?> ForegroundProperty =
AvaloniaProperty.RegisterAttached<TextElement, Control, IBrush?>(
AvaloniaProperty.RegisterAttached<TextElement, TextElement, IBrush?>(
nameof(Foreground),
Brushes.Black,
inherits: true);

65
src/Avalonia.Controls/RichTextBlock.cs

@ -16,7 +16,7 @@ namespace Avalonia.Controls
/// <summary>
/// A control that displays a block of formatted text.
/// </summary>
public class RichTextBlock : TextBlock, IInlineHost
public class RichTextBlock : TextBlock, IInlineHost, IAddChild<string>, IAddChild<Inline>, IAddChild<IControl>
{
public static readonly StyledProperty<bool> IsTextSelectionEnabledProperty =
AvaloniaProperty.Register<RichTextBlock, bool>(nameof(IsTextSelectionEnabled), false);
@ -148,7 +148,6 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets the inlines.
/// </summary>
[Content]
public InlineCollection Inlines
{
get => GetValue(InlinesProperty);
@ -170,6 +169,8 @@ namespace Avalonia.Controls
remove => RemoveHandler(CopyingToClipboardEvent, value);
}
internal bool HasComplexContent => Inlines.Count > 0;
/// <summary>
/// Copies the current selection to the Clipboard.
/// </summary>
@ -251,25 +252,69 @@ namespace Avalonia.Controls
SelectionEnd = SelectionStart;
}
protected override string? GetText()
void IAddChild<string>.AddChild(string text)
{
return _text ?? Inlines.Text;
AddText(text);
}
protected override void SetText(string? text)
void IAddChild<Inline>.AddChild(Inline inline)
{
var oldValue = _text ?? Inlines?.Text;
if (!HasComplexContent && !string.IsNullOrEmpty(_text))
{
Inlines.Add(_text);
_text = null;
}
Inlines.Add(inline);
}
if (Inlines is not null && Inlines.HasComplexContent)
void IAddChild<IControl>.AddChild(IControl child)
{
if (!HasComplexContent && !string.IsNullOrEmpty(_text))
{
Inlines.Text = text;
Inlines.Add(_text);
_text = null;
}
else
Inlines.Add(new InlineUIContainer(child));
}
protected void AddText(string? text)
{
if (string.IsNullOrEmpty(text))
{
return;
}
if (!HasComplexContent && string.IsNullOrEmpty(_text))
{
_text = text;
}
else
{
if (!string.IsNullOrEmpty(_text))
{
Inlines.Add(_text);
_text = null;
}
Inlines.Add(text);
}
}
protected override string? GetText()
{
return _text ?? Inlines.Text;
}
protected override void SetText(string? text)
{
var oldValue = _text ?? Inlines?.Text;
AddText(text);
RaisePropertyChanged(TextProperty, oldValue, text);
}
@ -293,7 +338,7 @@ namespace Avalonia.Controls
var inlines = Inlines;
if (inlines is not null && inlines.HasComplexContent)
if (HasComplexContent)
{
var textRuns = new List<TextRun>();

13
src/Avalonia.Controls/TextBlock.cs

@ -4,6 +4,7 @@ using Avalonia.Controls.Documents;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Media.TextFormatting;
using Avalonia.Metadata;
using Avalonia.Utilities;
namespace Avalonia.Controls
@ -11,7 +12,7 @@ namespace Avalonia.Controls
/// <summary>
/// A control that displays a block of text.
/// </summary>
public class TextBlock : Control
public class TextBlock : Control, IAddChild<string>
{
/// <summary>
/// Defines the <see cref="Background"/> property.
@ -473,11 +474,6 @@ namespace Avalonia.Controls
control.SetValue(MaxLinesProperty, maxLines);
}
public void Add(string text)
{
_text = text;
}
/// <summary>
/// Renders the <see cref="TextBlock"/> to a drawing context.
/// </summary>
@ -512,6 +508,11 @@ namespace Avalonia.Controls
TextLayout.Draw(context, new Point(padding.Left, top));
}
void IAddChild<string>.AddChild(string text)
{
_text = text;
}
protected virtual string? GetText()
{
return _text;

4
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs

@ -70,8 +70,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
},
InnerServiceProviderFactoryMethod =
runtimeHelpers.FindMethod(m => m.Name == "CreateInnerServiceProviderV1"),
IAddChild = typeSystem.GetType("Avalonia.Markup.Xaml.IAddChild"),
IAddChildOfT = typeSystem.GetType("Avalonia.Markup.Xaml.IAddChild`1")
IAddChild = typeSystem.GetType("Avalonia.Metadata.IAddChild"),
IAddChildOfT = typeSystem.GetType("Avalonia.Metadata.IAddChild`1")
};
rv.CustomAttributeResolver = new AttributeResolver(typeSystem, rv);

1
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@ -15,7 +15,6 @@
<Compile Include="Converters\FontFamilyTypeConverter.cs" />
<Compile Include="Converters\TimeSpanTypeConverter.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="IAddChild.cs" />
<Compile Include="MarkupExtension.cs" />
<Compile Include="MarkupExtensions\CompiledBindingExtension.cs" />
<Compile Include="MarkupExtensions\CompiledBindings\ArrayElementPlugin.cs" />

Loading…
Cancel
Save