diff --git a/Documentation/build.md b/Documentation/build.md
index 5f75290424..a7d68eb599 100644
--- a/Documentation/build.md
+++ b/Documentation/build.md
@@ -9,10 +9,24 @@ git clone https://github.com/AvaloniaUI/Avalonia.git
git submodule update --init
```
+### Install the required version of the .NET Core SDK
+
+Go to https://dotnet.microsoft.com/download/visual-studio-sdks and install the latest version of the .NET Core SDK compatible with Avalonia UI. Make sure to download the SDK (not just the "runtime") package. The version compatible is indicated within the [global.json](https://github.com/AvaloniaUI/Avalonia/blob/master/global.json) file. Note that Avalonia UI does not always use the latest version and is hardcoded to use the last version known to be compatible (SDK releases may break the builds from time-to-time).
+
### Open in Visual Studio
-Open the `Avalonia.sln` solution in Visual Studio 2019 or newer. The free Visual Studio Community
-edition works fine. Run the `Samples\ControlCatalog.Desktop` project to see the sample application.
+Open the `Avalonia.sln` solution in Visual Studio 2019 or newer. The free Visual Studio Community edition works fine. Build and run the `Samples\ControlCatalog.Desktop` or `ControlCatalog.NetCore` project to see the sample application.
+
+### Troubleshooting
+
+ * **Error CS0006: Avalonia.DesktopRuntime.dll could not be found**
+
+ It is common for the first build to fail with the errors below (also discussed in [#4257](https://github.com/AvaloniaUI/Avalonia/issues/4257)).
+ ```
+ >CSC : error CS0006: Metadata file 'C:\...\Avalonia\src\Avalonia.DesktopRuntime\bin\Debug\netcoreapp2.0\Avalonia.DesktopRuntime.dll' could not be found
+ >CSC : error CS0006: Metadata file 'C:\...\Avalonia\packages\Avalonia\bin\Debug\netcoreapp2.0\Avalonia.dll' could not be found
+ ```
+ To correct this, right click on the `Avalonia.DesktopRuntime` project then press `Build` to build the project manually. Afterwards the solution should build normally and the ControlCatalog can be run.
# Linux/macOS
@@ -20,9 +34,9 @@ It's *not* possible to build the *whole* project on Linux/macOS. You can only bu
MonoDevelop, Xamarin Studio and Visual Studio for Mac aren't capable of properly opening our solution. You can use Rider (at least 2017.2 EAP) or VSCode instead. They will fail to load most of platform specific projects, but you don't need them to run on .NET Core.
-### Install the latest version of .NET Core
+### Install the latest version of the .NET Core SDK
-Go to https://www.microsoft.com/net/core and follow instructions for your OS. You need SDK (not just "runtime") package.
+Go to https://www.microsoft.com/net/core and follow the instructions for your OS. Make sure to download the SDK (not just the "runtime") package.
### Additional requirements for macOS
diff --git a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml
index 998198cc1c..0c4f8249ce 100644
--- a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml
+++ b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml
@@ -163,6 +163,10 @@
+
-
-
+ x:Class="Avalonia.Diagnostics.Views.EventsPageView"
+ Margin="2">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml.cs
index c1c78d38f6..687a20c5f6 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml.cs
+++ b/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml.cs
@@ -1,7 +1,14 @@
-using System.Linq;
+using System;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.Linq;
using Avalonia.Controls;
+using Avalonia.Diagnostics.Models;
using Avalonia.Diagnostics.ViewModels;
+using Avalonia.Input;
+using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
+using Avalonia.Threading;
namespace Avalonia.Diagnostics.Views
{
@@ -12,13 +19,53 @@ namespace Avalonia.Diagnostics.Views
public EventsPageView()
{
InitializeComponent();
- _events = this.FindControl("events");
+ _events = this.FindControl("EventsList");
}
- private void RecordedEvents_CollectionChanged(object sender,
- System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
+ public void NavigateTo(object sender, TappedEventArgs e)
{
- _events.ScrollIntoView(_events.Items.OfType().LastOrDefault());
+ if (DataContext is EventsPageViewModel vm && sender is Control control)
+ {
+ switch (control.Tag)
+ {
+ case EventChainLink chainLink:
+ {
+ vm.RequestTreeNavigateTo(chainLink);
+ break;
+ }
+ case RoutedEvent evt:
+ {
+ vm.SelectEventByType(evt);
+
+ break;
+ }
+ }
+ }
+ }
+
+ protected override void OnDataContextChanged(EventArgs e)
+ {
+ base.OnDataContextChanged(e);
+
+ if (DataContext is EventsPageViewModel vm)
+ {
+ vm.RecordedEvents.CollectionChanged += OnRecordedEventsChanged;
+ }
+ }
+
+ private void OnRecordedEventsChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ if (sender is ObservableCollection events)
+ {
+ var evt = events.LastOrDefault();
+
+ if (evt is null)
+ {
+ return;
+ }
+
+ Dispatcher.UIThread.Post(() => _events.ScrollIntoView(evt));
+ }
}
private void InitializeComponent()
diff --git a/src/Avalonia.Themes.Fluent/Controls/DataValidationErrors.xaml b/src/Avalonia.Themes.Fluent/Controls/DataValidationErrors.xaml
index f83af266c2..b513fd5eae 100644
--- a/src/Avalonia.Themes.Fluent/Controls/DataValidationErrors.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/DataValidationErrors.xaml
@@ -1,44 +1,102 @@
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs
index 300d61f81d..6533c34ba0 100644
--- a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs
+++ b/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs
@@ -422,7 +422,7 @@ namespace Avalonia.Media.TextFormatting
}
else
{
- currentPosition = currentLength + lineBreaker.Current.PositionWrap;
+ currentPosition = currentLength + measuredLength;
}
breakFound = true;
diff --git a/src/Skia/Avalonia.Skia/TextShaperImpl.cs b/src/Skia/Avalonia.Skia/TextShaperImpl.cs
index 31724bfee9..5cf72e2ce8 100644
--- a/src/Skia/Avalonia.Skia/TextShaperImpl.cs
+++ b/src/Skia/Avalonia.Skia/TextShaperImpl.cs
@@ -87,7 +87,7 @@ namespace Avalonia.Skia
{
var nextCodepoint = Codepoint.ReadAt(text, i + 1, out _);
- if (nextCodepoint == '\r' && codepoint == '\n' || nextCodepoint == '\n' && codepoint == '\r')
+ if (nextCodepoint == '\n' && codepoint == '\r')
{
count++;
diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs
index 05dd32b84d..97af874238 100644
--- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs
+++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs
@@ -401,6 +401,24 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
Assert.Equal(expectedOffset, textLine.Start);
}
}
+
+ [Fact]
+ public void Should_FormatLine_With_Emergency_Breaks()
+ {
+ using (Start())
+ {
+ var defaultProperties = new GenericTextRunProperties(Typeface.Default);
+ var paragraphProperties = new GenericTextParagraphProperties(defaultProperties, textWrap: TextWrapping.Wrap);
+
+ var textSource = new SingleBufferTextSource("0123456789_0123456789_0123456789_0123456789", defaultProperties);
+ var formatter = new TextFormatterImpl();
+
+ var textLine =
+ formatter.FormatLine(textSource, 0, 33, paragraphProperties);
+
+ Assert.NotNull(textLine.TextLineBreak?.RemainingCharacters);
+ }
+ }
public static IDisposable Start()
{
diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextShaperTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextShaperTests.cs
new file mode 100644
index 0000000000..62d2c54ffe
--- /dev/null
+++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextShaperTests.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Globalization;
+using Avalonia.Media;
+using Avalonia.Media.TextFormatting;
+using Avalonia.UnitTests;
+using Xunit;
+
+namespace Avalonia.Skia.UnitTests.Media.TextFormatting
+{
+ public class TextShaperTests
+ {
+ [Fact]
+ public void Should_Form_Clusters_For_BreakPairs()
+ {
+ using (Start())
+ {
+ var text = "\n\r\n".AsMemory();
+
+ var glyphRun = TextShaper.Current.ShapeText(
+ text,
+ Typeface.Default,
+ 12,
+ CultureInfo.CurrentCulture);
+
+ Assert.Equal(glyphRun.Characters.Length, text.Length);
+ Assert.Equal(glyphRun.GlyphClusters.Length, text.Length);
+ Assert.Equal(0, glyphRun.GlyphClusters[0]);
+ Assert.Equal(1, glyphRun.GlyphClusters[1]);
+ Assert.Equal(1, glyphRun.GlyphClusters[2]);
+ }
+ }
+
+ private static IDisposable Start()
+ {
+ var disposable = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface
+ .With(renderInterface: new PlatformRenderInterface(null),
+ textShaperImpl: new TextShaperImpl(),
+ fontManagerImpl: new CustomFontManagerImpl()));
+
+ return disposable;
+ }
+ }
+}