Browse Source

Merge pull request #8541 from Gillibald/fixes/MoveIAddChild

Move IAddChild to Avalonia.Metadata and use it for Rich./TextBlock
pull/8580/head
Benedikt Stebner 4 years ago
committed by GitHub
parent
commit
d56a92514e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      src/Avalonia.Base/Metadata/IAddChild.cs
  2. 34
      src/Avalonia.Controls/Documents/Inline.cs
  3. 78
      src/Avalonia.Controls/Documents/InlineCollection.cs
  4. 35
      src/Avalonia.Controls/Documents/Span.cs
  5. 12
      src/Avalonia.Controls/Documents/TextElement.cs
  6. 41
      src/Avalonia.Controls/RichTextBlock.cs
  7. 15
      src/Avalonia.Controls/TextBlock.cs
  8. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs
  9. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
  10. 1
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  11. 3
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs

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 public interface IAddChild
{ {
void AddChild(object child); void AddChild(object child);
} }
public interface IAddChild<T> : IAddChild public interface IAddChild<T>
{ {
void AddChild(T child); void AddChild(T child);
} }

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

@ -50,8 +50,38 @@ namespace Avalonia.Controls.Documents
protected TextRunProperties CreateTextRunProperties() protected TextRunProperties CreateTextRunProperties()
{ {
return new GenericTextRunProperties(new Typeface(FontFamily, FontStyle, FontWeight), FontSize, var textDecorations = TextDecorations;
TextDecorations, Foreground, Background, BaselineAlignment); 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) protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)

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

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

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

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

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

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

41
src/Avalonia.Controls/RichTextBlock.cs

@ -170,6 +170,8 @@ namespace Avalonia.Controls
remove => RemoveHandler(CopyingToClipboardEvent, value); remove => RemoveHandler(CopyingToClipboardEvent, value);
} }
internal bool HasComplexContent => Inlines.Count > 0;
/// <summary> /// <summary>
/// Copies the current selection to the Clipboard. /// Copies the current selection to the Clipboard.
/// </summary> /// </summary>
@ -251,6 +253,30 @@ namespace Avalonia.Controls
SelectionEnd = SelectionStart; SelectionEnd = SelectionStart;
} }
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() protected override string? GetText()
{ {
return _text ?? Inlines.Text; return _text ?? Inlines.Text;
@ -259,17 +285,8 @@ namespace Avalonia.Controls
protected override void SetText(string? text) protected override void SetText(string? text)
{ {
var oldValue = _text ?? Inlines?.Text; var oldValue = _text ?? Inlines?.Text;
if (Inlines is not null && Inlines.HasComplexContent) AddText(text);
{
Inlines.Text = text;
_text = null;
}
else
{
_text = text;
}
RaisePropertyChanged(TextProperty, oldValue, text); RaisePropertyChanged(TextProperty, oldValue, text);
} }
@ -293,7 +310,7 @@ namespace Avalonia.Controls
var inlines = Inlines; var inlines = Inlines;
if (inlines is not null && inlines.HasComplexContent) if (HasComplexContent)
{ {
var textRuns = new List<TextRun>(); var textRuns = new List<TextRun>();

15
src/Avalonia.Controls/TextBlock.cs

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

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

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

2
src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github

@ -1 +1 @@
Subproject commit a4e6be2d1407abec4f35fcb208848830ce513ead Subproject commit d990d63774a04d2a4b3d52e626a90ee68e19e2b6

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

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

3
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs

@ -17,6 +17,7 @@ using System.Linq;
using System.Xml; using System.Xml;
using Xunit; using Xunit;
using Avalonia.Controls.Documents; using Avalonia.Controls.Documents;
using Avalonia.Metadata;
namespace Avalonia.Markup.Xaml.UnitTests.Xaml namespace Avalonia.Markup.Xaml.UnitTests.Xaml
{ {
@ -1011,7 +1012,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
} }
} }
public class ObjectWithAddChildOfT : IAddChild<string> public class ObjectWithAddChildOfT : IAddChild, IAddChild<string>
{ {
public string Text { get; set; } public string Text { get; set; }

Loading…
Cancel
Save