Browse Source

Merge branch 'master' into fixes/inlinesTrimming

pull/12695/head^2
Benedikt Stebner 3 years ago
committed by GitHub
parent
commit
0dcdeab528
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
  2. 84
      native/Avalonia.Native/src/OSX/PlatformRenderTimer.mm
  3. 1
      native/Avalonia.Native/src/OSX/common.h
  4. 11
      native/Avalonia.Native/src/OSX/main.mm
  5. 7
      src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
  6. 26
      src/Avalonia.Controls/Documents/Inline.cs
  7. 28
      src/Avalonia.Controls/ItemsControl.cs
  8. 11
      src/Avalonia.Controls/Primitives/AccessText.cs
  9. 5
      src/Avalonia.Controls/Shapes/Polygon.cs
  10. 5
      src/Avalonia.Controls/Shapes/Polyline.cs
  11. 2
      src/Avalonia.Controls/TextBlock.cs
  12. BIN
      src/Avalonia.Fonts.Inter/Assets/Inter-Bold.ttf
  13. BIN
      src/Avalonia.Fonts.Inter/Assets/Inter-ExtraLight.ttf
  14. BIN
      src/Avalonia.Fonts.Inter/Assets/Inter-Light.ttf
  15. BIN
      src/Avalonia.Fonts.Inter/Assets/Inter-Medium.ttf
  16. BIN
      src/Avalonia.Fonts.Inter/Assets/Inter-Regular.ttf
  17. BIN
      src/Avalonia.Fonts.Inter/Assets/Inter-SemiBold.ttf
  18. BIN
      src/Avalonia.Fonts.Inter/Assets/Inter-Thin.ttf
  19. 2
      src/Avalonia.Native/AvaloniaNativePlatform.cs
  20. 58
      src/Avalonia.Native/AvaloniaNativeRenderTimer.cs
  21. 10
      src/Avalonia.Native/avn.idl
  22. 152
      tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
  23. 21
      tests/Avalonia.Controls.UnitTests/TextBlockTests.cs

4
native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj

@ -59,6 +59,7 @@
BC11A5BE2608D58F0017BAD0 /* automation.h in Headers */ = {isa = PBXBuildFile; fileRef = BC11A5BC2608D58F0017BAD0 /* automation.h */; };
BC11A5BF2608D58F0017BAD0 /* automation.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC11A5BD2608D58F0017BAD0 /* automation.mm */; };
ED3791C42862E1F40080BD62 /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED3791C32862E1F40080BD62 /* UniformTypeIdentifiers.framework */; };
ED754D262A97306B0078B4DF /* PlatformRenderTimer.mm in Sources */ = {isa = PBXBuildFile; fileRef = ED754D252A97306B0078B4DF /* PlatformRenderTimer.mm */; };
EDF8CDCD2964CB01001EE34F /* PlatformSettings.mm in Sources */ = {isa = PBXBuildFile; fileRef = EDF8CDCC2964CB01001EE34F /* PlatformSettings.mm */; };
/* End PBXBuildFile section */
@ -122,6 +123,7 @@
BC11A5BC2608D58F0017BAD0 /* automation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = automation.h; sourceTree = "<group>"; };
BC11A5BD2608D58F0017BAD0 /* automation.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = automation.mm; sourceTree = "<group>"; };
ED3791C32862E1F40080BD62 /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; };
ED754D252A97306B0078B4DF /* PlatformRenderTimer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformRenderTimer.mm; sourceTree = "<group>"; };
EDF8CDCC2964CB01001EE34F /* PlatformSettings.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformSettings.mm; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -162,6 +164,7 @@
AB7A61E62147C814003C5833 = {
isa = PBXGroup;
children = (
ED754D252A97306B0078B4DF /* PlatformRenderTimer.mm */,
855EDC9E28C6546F00807998 /* PlatformBehaviorInhibition.mm */,
8D2F3511292F6AAE007FCF54 /* AvnTextInputMethodDelegate.h */,
8D300D68292E1E5D00320C49 /* AvnTextInputMethod.mm */,
@ -333,6 +336,7 @@
18391068E48EF96E3DB5FDAB /* ResizeScope.mm in Sources */,
18391D4EB311BC7EF8B8C0A6 /* AvnView.mm in Sources */,
18391AA7E0BBA74D184C5734 /* AutoFitContentView.mm in Sources */,
ED754D262A97306B0078B4DF /* PlatformRenderTimer.mm in Sources */,
1839151F32D1BB1AB51A7BB6 /* AvnPanelWindow.mm in Sources */,
18391AC16726CBC45856233B /* AvnWindow.mm in Sources */,
18391D8CD1756DC858DC1A09 /* PopupImpl.mm in Sources */,

84
native/Avalonia.Native/src/OSX/PlatformRenderTimer.mm

@ -0,0 +1,84 @@
#include "common.h"
class PlatformRenderTimer : public ComSingleObject<IAvnPlatformRenderTimer, &IID_IAvnPlatformRenderTimer>
{
private:
ComPtr<IAvnActionCallback> _callback;
CVDisplayLinkRef _displayLink;
public:
FORWARD_IUNKNOWN()
virtual HRESULT RegisterTick (
IAvnActionCallback* callback) override
{
START_COM_CALL;
@autoreleasepool
{
if (_displayLink != nil)
{
return E_UNEXPECTED;
}
_callback = callback;
auto result = CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink);
if (result != 0)
{
return E_FAIL;
}
result = CVDisplayLinkSetOutputCallback(_displayLink, OnTick, this);
if (result != 0)
{
return E_FAIL;
}
}
return S_OK;
}
virtual void Start () override
{
START_COM_CALL;
@autoreleasepool
{
if (CVDisplayLinkIsRunning(_displayLink) == false) {
CVDisplayLinkStart(_displayLink);
}
}
}
virtual void Stop () override
{
START_COM_CALL;
@autoreleasepool
{
if (CVDisplayLinkIsRunning(_displayLink) == true) {
CVDisplayLinkStop(_displayLink);
}
}
}
virtual bool RunsInBackground () override
{
START_COM_CALL;
@autoreleasepool
{
return true;
}
}
static CVReturn OnTick(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext)
{
PlatformRenderTimer *object = (PlatformRenderTimer *)displayLinkContext;
object->_callback->Run();
return kCVReturnSuccess;
}
};
extern IAvnPlatformRenderTimer* CreatePlatformRenderTimer()
{
return new PlatformRenderTimer();
}

1
native/Avalonia.Native/src/OSX/common.h

@ -32,6 +32,7 @@ extern IAvnApplicationCommands* CreateApplicationCommands();
extern IAvnPlatformBehaviorInhibition* CreatePlatformBehaviorInhibition();
extern IAvnNativeControlHost* CreateNativeControlHost(NSView* parent);
extern IAvnPlatformSettings* CreatePlatformSettings();
extern IAvnPlatformRenderTimer* CreatePlatformRenderTimer();
extern void SetAppMenu(IAvnMenu *menu);
extern void SetServicesMenu (IAvnMenu* menu);
extern IAvnMenu* GetAppMenu ();

11
native/Avalonia.Native/src/OSX/main.mm

@ -446,6 +446,17 @@ public:
return S_OK;
}
}
virtual HRESULT CreatePlatformRenderTimer(IAvnPlatformRenderTimer** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
*ppv = ::CreatePlatformRenderTimer();
return S_OK;
}
}
};
extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative()

7
src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs

@ -1278,14 +1278,11 @@ namespace Avalonia.Media.TextFormatting
var start = GetParagraphOffsetX(width, widthIncludingWhitespace);
var overhangLeading = Math.Max(0, bounds.Left - start);
var overhangTrailing = Math.Max(0, bounds.Width - widthIncludingWhitespace);
var hasOverflowed = overhangLeading + widthIncludingWhitespace + overhangTrailing > _paragraphWidth;
var hasOverflowed = width > _paragraphWidth;
if (!double.IsNaN(lineHeight) && !MathUtilities.IsZero(lineHeight))
{
if (lineHeight > height)
{
height = lineHeight;
}
height = lineHeight;
}
return new TextLineMetrics

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

@ -10,12 +10,14 @@ namespace Avalonia.Controls.Documents
/// </summary>
public abstract class Inline : TextElement
{
// TODO12: change the field type to an AttachedProperty for consistency (breaking change)
/// <summary>
/// AvaloniaProperty for <see cref="TextDecorations" /> property.
/// </summary>
public static readonly StyledProperty<TextDecorationCollection?> TextDecorationsProperty =
AvaloniaProperty.Register<Inline, TextDecorationCollection?>(
nameof(TextDecorations));
AvaloniaProperty.RegisterAttached<Inline, Inline, TextDecorationCollection?>(
nameof(TextDecorations),
inherits: true);
/// <summary>
/// AvaloniaProperty for <see cref="BaselineAlignment" /> property.
@ -43,7 +45,27 @@ namespace Avalonia.Controls.Documents
get { return GetValue(BaselineAlignmentProperty); }
set { SetValue(BaselineAlignmentProperty, value); }
}
/// <summary>
/// Gets the value of the attached <see cref="TextDecorationsProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The font style.</returns>
public static TextDecorationCollection? GetTextDecorations(Control control)
{
return control.GetValue(TextDecorationsProperty);
}
/// <summary>
/// Sets the value of the attached <see cref="TextDecorationsProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetTextDecorations(Control control, TextDecorationCollection? value)
{
control.SetValue(TextDecorationsProperty, value);
}
internal abstract void BuildTextRun(IList<TextRun> textRuns);
internal abstract void AppendText(StringBuilder stringBuilder);

28
src/Avalonia.Controls/ItemsControl.cs

@ -67,6 +67,9 @@ namespace Avalonia.Controls
public static readonly StyledProperty<IBinding?> DisplayMemberBindingProperty =
AvaloniaProperty.Register<ItemsControl, IBinding?>(nameof(DisplayMemberBinding));
private static readonly AttachedProperty<ControlTheme?> AppliedItemContainerTheme =
AvaloniaProperty.RegisterAttached<ItemsControl, Control, ControlTheme?>("AppliedItemContainerTheme");
/// <summary>
/// Gets or sets the <see cref="IBinding"/> to use for binding to the display member of each item.
/// </summary>
@ -663,13 +666,26 @@ namespace Avalonia.Controls
internal void PrepareItemContainer(Control container, object? item, int index)
{
var itemContainerTheme = ItemContainerTheme;
if (itemContainerTheme is not null &&
!container.IsSet(ThemeProperty) &&
StyledElement.GetStyleKey(container) == itemContainerTheme.TargetType)
// If the container has no theme set, or we've already applied our ItemContainerTheme
// (and it hasn't changed since) then we're in control of the container's Theme and may
// need to update it.
if (!container.IsSet(ThemeProperty) || container.GetValue(AppliedItemContainerTheme) == container.Theme)
{
container.Theme = itemContainerTheme;
var itemContainerTheme = ItemContainerTheme;
if (itemContainerTheme?.TargetType?.IsAssignableFrom(GetStyleKey(container)) == true)
{
// We have an ItemContainerTheme and it matches the container. Set the Theme
// property, and mark the container as having had ItemContainerTheme applied.
container.SetCurrentValue(ThemeProperty, itemContainerTheme);
container.SetValue(AppliedItemContainerTheme, itemContainerTheme);
}
else
{
// Otherwise clear the theme and the AppliedItemContainerTheme property.
container.ClearValue(ThemeProperty);
container.ClearValue(AppliedItemContainerTheme);
}
}
if (item is not Control)

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

@ -3,6 +3,7 @@ using Avalonia.Input;
using Avalonia.Reactive;
using Avalonia.Media;
using Avalonia.Media.TextFormatting;
using System;
namespace Avalonia.Controls.Primitives
{
@ -68,11 +69,15 @@ namespace Avalonia.Controls.Primitives
if (underscore != -1 && ShowAccessKey)
{
var rect = TextLayout!.HitTestTextPosition(underscore);
var offset = new Vector(0, -1.5);
var x1 = Math.Round(rect.Left, MidpointRounding.AwayFromZero);
var x2 = Math.Round(rect.Right, MidpointRounding.AwayFromZero);
var y = Math.Round(rect.Bottom, MidpointRounding.AwayFromZero) - 1.5;
context.DrawLine(
new Pen(Foreground, 1),
rect.BottomLeft + offset,
rect.BottomRight + offset);
new Point(x1, y),
new Point(x2, y));
}
}

5
src/Avalonia.Controls/Shapes/Polygon.cs

@ -1,5 +1,6 @@
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.Data;
namespace Avalonia.Controls.Shapes
{
@ -15,9 +16,9 @@ namespace Avalonia.Controls.Shapes
public Polygon()
{
Points = new Points();
SetValue(PointsProperty, new Points(), BindingPriority.Template);
}
public IList<Point> Points
{
get => GetValue(PointsProperty);

5
src/Avalonia.Controls/Shapes/Polyline.cs

@ -1,9 +1,10 @@
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.Data;
namespace Avalonia.Controls.Shapes
{
public class Polyline: Shape
public class Polyline : Shape
{
public static readonly StyledProperty<IList<Point>> PointsProperty =
AvaloniaProperty.Register<Polyline, IList<Point>>("Points");
@ -16,7 +17,7 @@ namespace Avalonia.Controls.Shapes
public Polyline()
{
Points = new Points();
SetValue(PointsProperty, new Points(), BindingPriority.Template);
}
public IList<Point> Points

2
src/Avalonia.Controls/TextBlock.cs

@ -135,7 +135,7 @@ namespace Avalonia.Controls
/// Defines the <see cref="TextDecorations"/> property.
/// </summary>
public static readonly StyledProperty<TextDecorationCollection?> TextDecorationsProperty =
AvaloniaProperty.Register<TextBlock, TextDecorationCollection?>(nameof(TextDecorations));
Inline.TextDecorationsProperty.AddOwner<TextBlock>();
/// <summary>
/// Defines the <see cref="Inlines"/> property.

BIN
src/Avalonia.Fonts.Inter/Assets/Inter-Bold.ttf

Binary file not shown.

BIN
src/Avalonia.Fonts.Inter/Assets/Inter-ExtraLight.ttf

Binary file not shown.

BIN
src/Avalonia.Fonts.Inter/Assets/Inter-Light.ttf

Binary file not shown.

BIN
src/Avalonia.Fonts.Inter/Assets/Inter-Medium.ttf

Binary file not shown.

BIN
src/Avalonia.Fonts.Inter/Assets/Inter-Regular.ttf

Binary file not shown.

BIN
src/Avalonia.Fonts.Inter/Assets/Inter-SemiBold.ttf

Binary file not shown.

BIN
src/Avalonia.Fonts.Inter/Assets/Inter-Thin.ttf

Binary file not shown.

2
src/Avalonia.Native/AvaloniaNativePlatform.cs

@ -108,7 +108,7 @@ namespace Avalonia.Native
.Bind<IPlatformSettings>().ToConstant(new NativePlatformSettings(_factory.CreatePlatformSettings()))
.Bind<IWindowingPlatform>().ToConstant(this)
.Bind<IClipboard>().ToConstant(new ClipboardImpl(_factory.CreateClipboard()))
.Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
.Bind<IRenderTimer>().ToConstant(new AvaloniaNativeRenderTimer(_factory.CreatePlatformRenderTimer()))
.Bind<IMountedVolumeInfoProvider>().ToConstant(new MacOSMountedVolumeInfoProvider())
.Bind<IPlatformDragSource>().ToConstant(new AvaloniaNativeDragSource(_factory))
.Bind<IPlatformLifetimeEventsImpl>().ToConstant(applicationPlatform)

58
src/Avalonia.Native/AvaloniaNativeRenderTimer.cs

@ -0,0 +1,58 @@
using System;
using System.Diagnostics;
using Avalonia.Native.Interop;
using Avalonia.Rendering;
#nullable enable
namespace Avalonia.Native;
internal sealed class AvaloniaNativeRenderTimer : NativeCallbackBase, IRenderTimer, IAvnActionCallback
{
private readonly IAvnPlatformRenderTimer _platformRenderTimer;
private readonly Stopwatch _stopwatch;
private Action<TimeSpan>? _tick;
private int _subscriberCount;
private bool registered;
public AvaloniaNativeRenderTimer(IAvnPlatformRenderTimer platformRenderTimer)
{
_platformRenderTimer = platformRenderTimer;
_stopwatch = Stopwatch.StartNew();
}
public event Action<TimeSpan> Tick
{
add
{
_tick += value;
if (!registered)
{
registered = true;
_platformRenderTimer.RegisterTick(this);
}
if (_subscriberCount++ == 0)
{
_platformRenderTimer.Start();
}
}
remove
{
if (--_subscriberCount == 0)
{
_platformRenderTimer.Stop();
}
_tick -= value;
}
}
public bool RunsInBackground => _platformRenderTimer.RunsInBackground().FromComBool();
public void Run()
{
_tick?.Invoke(_stopwatch.Elapsed);
}
}

10
src/Avalonia.Native/avn.idl

@ -507,6 +507,7 @@ interface IAvaloniaNativeFactory : IUnknown
HRESULT CreateApplicationCommands(IAvnApplicationCommands** ppv);
HRESULT CreatePlatformSettings(IAvnPlatformSettings** ppv);
HRESULT CreatePlatformBehaviorInhibition(IAvnPlatformBehaviorInhibition** ppv);
HRESULT CreatePlatformRenderTimer(IAvnPlatformRenderTimer** ppv);
}
[uuid(233e094f-9b9f-44a3-9a6e-6948bbdd9fb1)]
@ -999,3 +1000,12 @@ interface IAvnPlatformBehaviorInhibition : IUnknown
{
void SetInhibitAppSleep(bool inhibitAppSleep, char* reason);
}
[uuid(22edf20d-5803-2d3f-9247-b4842e5e9322)]
interface IAvnPlatformRenderTimer : IUnknown
{
HRESULT RegisterTick(IAvnActionCallback* callback);
void Start();
void Stop();
bool RunsInBackground();
}

152
tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs

@ -14,6 +14,7 @@ using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.LogicalTree;
using Avalonia.Markup.Xaml.Templates;
using Avalonia.Media;
using Avalonia.Styling;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
@ -128,6 +129,155 @@ namespace Avalonia.Controls.UnitTests
Assert.Same(container.Theme, theme);
}
[Fact]
public void Container_Should_Have_Theme_Set_To_ItemContainerTheme_With_Base_TargetType()
{
using var app = Start();
var theme = new ControlTheme { TargetType = typeof(Control) };
var target = CreateTarget(
itemsSource: new[] { "Foo" },
itemContainerTheme: theme);
var container = GetContainer(target);
Assert.Same(container.Theme, theme);
}
[Fact]
public void ItemContainerTheme_Can_Be_Changed()
{
using var app = Start();
var theme1 = new ControlTheme
{
TargetType = typeof(ContentPresenter),
Setters = { new Setter(ContentPresenter.BackgroundProperty, Brushes.Red) }
};
var theme2 = new ControlTheme
{
TargetType = typeof(ContentPresenter),
Setters = { new Setter(ContentPresenter.BackgroundProperty, Brushes.Green) }
};
var target = CreateTarget(
itemsSource: new[] { "Foo" },
itemContainerTheme: theme1);
var container = GetContainer(target);
Assert.Same(container.Theme, theme1);
Assert.Equal(container.Background, Brushes.Red);
target.ItemContainerTheme = theme2;
container = GetContainer(target);
Assert.Same(container.Theme, theme2);
Assert.Equal(container.Background, Brushes.Green);
}
[Fact]
public void ItemContainerTheme_Can_Be_Changed_Virtualizing()
{
using var app = Start();
var theme1 = new ControlTheme
{
TargetType = typeof(ContentPresenter),
Setters = { new Setter(ContentPresenter.BackgroundProperty, Brushes.Red) }
};
var theme2 = new ControlTheme
{
TargetType = typeof(ContentPresenter),
Setters = { new Setter(ContentPresenter.BackgroundProperty, Brushes.Green) }
};
var itemsPanel = new FuncTemplate<Panel?>(() => new VirtualizingStackPanel());
var target = CreateTarget(
itemsSource: new[] { "Foo" },
itemContainerTheme: theme1,
itemsPanel: itemsPanel);
var container = GetContainer(target);
Assert.Same(container.Theme, theme1);
Assert.Equal(container.Background, Brushes.Red);
target.ItemContainerTheme = theme2;
Layout(target);
container = GetContainer(target);
Assert.Same(container.Theme, theme2);
Assert.Equal(container.Background, Brushes.Green);
}
[Fact]
public void ItemContainerTheme_Can_Be_Cleared()
{
using var app = Start();
var theme = new ControlTheme
{
TargetType = typeof(ContentPresenter),
Setters = { new Setter(ContentPresenter.BackgroundProperty, Brushes.Red) }
};
var target = CreateTarget(
itemsSource: new[] { "Foo" },
itemContainerTheme: theme);
var container = GetContainer(target);
Assert.Same(container.Theme, theme);
Assert.Equal(container.Background, Brushes.Red);
target.ItemContainerTheme = null;
container = GetContainer(target);
Assert.Null(container.Theme);
Assert.Null(container.Background);
}
[Fact]
public void ItemContainerTheme_Should_Not_Override_LocalValue_Theme()
{
using var app = Start();
var theme1 = new ControlTheme
{
TargetType = typeof(ContentPresenter),
Setters = { new Setter(ContentPresenter.BackgroundProperty, Brushes.Red) }
};
var theme2 = new ControlTheme
{
TargetType = typeof(Control),
Setters = { new Setter(ContentPresenter.BackgroundProperty, Brushes.Green) }
};
var items = new object[]
{
new ContentPresenter(),
new ContentPresenter
{
Theme = theme2
},
};
var target = CreateTarget(
itemsSource: items,
itemContainerTheme: theme1);
Assert.Same(theme1, GetContainer(target, 0).Theme);
Assert.Same(theme2, GetContainer(target, 1).Theme);
target.ItemContainerTheme = null;
Assert.Null(GetContainer(target, 0).Theme);
Assert.Same(theme2, GetContainer(target, 1).Theme);
}
[Fact]
public void Container_Should_Have_LogicalParent_Set_To_ItemsControl()
{
@ -851,6 +1001,7 @@ namespace Avalonia.Controls.UnitTests
IList? itemsSource = null,
ControlTheme? itemContainerTheme = null,
IDataTemplate? itemTemplate = null,
ITemplate<Panel?>? itemsPanel = null,
IEnumerable<IDataTemplate>? dataTemplates = null,
bool performLayout = true)
{
@ -861,6 +1012,7 @@ namespace Avalonia.Controls.UnitTests
itemsSource: itemsSource,
itemContainerTheme: itemContainerTheme,
itemTemplate: itemTemplate,
itemsPanel: itemsPanel,
dataTemplates: dataTemplates,
performLayout: performLayout);
}

21
tests/Avalonia.Controls.UnitTests/TextBlockTests.cs

@ -202,5 +202,26 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(0, target.Inlines.Count);
}
}
[Fact]
public void Setting_TextDecorations_Should_Update_Inlines()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var target = new TextBlock();
target.Inlines.Add(new Run("Hello World"));
Assert.Equal(1, target.Inlines.Count);
Assert.Null(target.Inlines[0].TextDecorations);
var underline = TextDecorations.Underline;
target.TextDecorations = underline;
Assert.Equal(underline, target.Inlines[0].TextDecorations);
}
}
}
}

Loading…
Cancel
Save